appium-android-driver 4.49.0 → 4.52.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,85 +8,80 @@ const PIN_UNLOCK_KEY_EVENT = 'pinWithKeyEvent';
8
8
  const PASSWORD_UNLOCK = 'password';
9
9
  const PATTERN_UNLOCK = 'pattern';
10
10
  const FINGERPRINT_UNLOCK = 'fingerprint';
11
- const UNLOCK_TYPES = [PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, PASSWORD_UNLOCK, PATTERN_UNLOCK, FINGERPRINT_UNLOCK];
11
+ const UNLOCK_TYPES = [
12
+ PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, PASSWORD_UNLOCK,
13
+ PATTERN_UNLOCK, FINGERPRINT_UNLOCK
14
+ ];
12
15
  const KEYCODE_NUMPAD_ENTER = 66;
13
- const KEYCODE_POWER = 26;
14
- const KEYCODE_WAKEUP = 224; // Can work over API Level 20
15
16
  const UNLOCK_WAIT_TIME = 100;
16
- const HIDE_KEYBOARD_WAIT_TIME = 100;
17
17
  const INPUT_KEYS_WAIT_TIME = 100;
18
18
  const NUMBER_ZERO_KEYCODE = 7;
19
19
 
20
- let helpers = {};
21
- helpers.isValidUnlockType = function isValidUnlockType (type) {
22
- return UNLOCK_TYPES.includes(type);
23
- };
20
+ const helpers = {};
24
21
 
25
- helpers.isValidKey = function isValidKey (type, key) {
26
- if (_.isUndefined(key)) {
27
- return false;
28
- }
29
- if ([PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, FINGERPRINT_UNLOCK].includes(type)) {
30
- return /^[0-9]+$/.test(key.trim());
22
+ helpers.validateUnlockCapabilities = function validateUnlockCapabilities (caps = {}) {
23
+ const {
24
+ unlockKey,
25
+ unlockType,
26
+ } = caps;
27
+ if (_.isNil(unlockKey) || unlockKey === '') {
28
+ throw new Error('A non-empty unlock key value must be provided');
31
29
  }
32
- if (type === PATTERN_UNLOCK) {
33
- if (!/^[1-9]{2,9}$/.test(key.trim())) {
34
- return false;
30
+
31
+ if ([PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, FINGERPRINT_UNLOCK].includes(unlockType)) {
32
+ if (!/^[0-9]+$/.test(_.trim(unlockKey))) {
33
+ throw new Error(`Unlock key value '${unlockKey}' must only consist of digits`);
35
34
  }
36
- return !(/([1-9]).*?\1/.test(key.trim()));
37
- }
38
- // Dont trim password key, you can use blank spaces in your android password
39
- // ¯\_(ツ)_/¯
40
- if (type === PASSWORD_UNLOCK) {
41
- return /.{4,}/g.test(key);
35
+ } else if (unlockType === PATTERN_UNLOCK) {
36
+ if (!/^[1-9]{2,9}$/.test(_.trim(unlockKey))) {
37
+ throw new Error(`Unlock key value '${unlockKey}' must only include from two to nine digits in range 1..9`);
38
+ }
39
+ if (/([1-9]).*?\1/.test(_.trim(unlockKey))) {
40
+ throw new Error(`Unlock key value '${unlockKey}' must define a valid pattern where repeats are not allowed`);
41
+ }
42
+ } else if (unlockType === PASSWORD_UNLOCK) {
43
+ // Dont trim password key, you can use blank spaces in your android password
44
+ // ¯\_(ツ)_/¯
45
+ if (!/.{4,}/g.test(unlockKey)) {
46
+ throw new Error(`The minimum allowed length of unlock key value '${unlockKey}' is 4 characters`);
47
+ }
48
+ } else {
49
+ throw new Error(`Invalid unlock type '${unlockType}'. ` +
50
+ `Only the following unlock types are supported: ${UNLOCK_TYPES}`);
42
51
  }
43
- throw new Error(`Invalid unlock type ${type}`);
52
+ return caps;
44
53
  };
45
54
 
46
- helpers.dismissKeyguard = async function dismissKeyguard (driver, adb) {
47
- logger.info('Waking up the device to unlock it');
48
- // Screen off once to force pre-inputted text field clean after wake-up
49
- // Just screen on if the screen defaults off
50
- await driver.pressKeyCode(KEYCODE_POWER);
51
- await driver.pressKeyCode(KEYCODE_WAKEUP);
52
- let isKeyboardShown = await driver.isKeyboardShown();
53
- if (isKeyboardShown) {
54
- await driver.hideKeyboard();
55
- // Waits a bit for the keyboard to hide
56
- await sleep(HIDE_KEYBOARD_WAIT_TIME);
55
+ helpers.fastUnlock = async function fastUnlock (adb, opts = {}) {
56
+ const {
57
+ credential,
58
+ credentialType,
59
+ } = opts;
60
+ logger.info(`Unlocking the device via ADB using ${credentialType} credential '${credential}'`);
61
+ const wasLockEnabled = await adb.isLockEnabled();
62
+ if (wasLockEnabled) {
63
+ await adb.clearLockCredential(credential);
64
+ // not sure why, but the device's screen still remains locked
65
+ // if a preliminary wake up cycle has not been performed
66
+ await adb.cycleWakeUp();
67
+ } else {
68
+ logger.info('No active lock has been detected. Proceeding to the keyguard dismissal');
57
69
  }
58
- // dismiss notifications
59
- logger.info('Dismiss notifications from unlock view');
60
- await adb.shell(['service', 'call', 'notification', '1']);
61
- await adb.back();
62
- if (await adb.getApiLevel() > 21) {
63
- logger.info('Trying to dismiss keyguard');
64
- await adb.shell(['wm', 'dismiss-keyguard']);
65
- return;
70
+ try {
71
+ await adb.dismissKeyguard();
72
+ } finally {
73
+ if (wasLockEnabled) {
74
+ await adb.setLockCredential(credentialType, credential);
75
+ }
66
76
  }
67
- logger.info('Swiping up to dismiss keyguard');
68
- await helpers.swipeUp(driver);
69
- };
70
-
71
- helpers.swipeUp = async function swipeUp (driver) {
72
- let windowSize = await driver.getWindowSize();
73
- let x0 = parseInt(windowSize.x / 2, 10);
74
- let y0 = windowSize.y - 10;
75
- let yP = 100;
76
- let actions = [
77
- {action: 'press', options: {element: null, x: x0, y: y0}},
78
- {action: 'moveTo', options: {element: null, x: x0, y: yP}},
79
- {action: 'release'}
80
- ];
81
- await driver.performTouch(actions);
82
77
  };
83
78
 
84
79
  helpers.encodePassword = function encodePassword (key) {
85
- return key.replace(/\s/ig, '%s');
80
+ return `${key}`.replace(/\s/ig, '%s');
86
81
  };
87
82
 
88
83
  helpers.stringKeyToArr = function stringKeyToArr (key) {
89
- return key.trim().replace(/\s+/g, '').split(/\s*/);
84
+ return `${key}`.trim().replace(/\s+/g, '').split(/\s*/);
90
85
  };
91
86
 
92
87
  helpers.fingerprintUnlock = async function fingerprintUnlock (adb, driver, capabilities) {
@@ -99,26 +94,26 @@ helpers.fingerprintUnlock = async function fingerprintUnlock (adb, driver, capab
99
94
 
100
95
  helpers.pinUnlock = async function pinUnlock (adb, driver, capabilities) {
101
96
  logger.info(`Trying to unlock device using pin ${capabilities.unlockKey}`);
102
- await helpers.dismissKeyguard(driver, adb);
103
- let keys = helpers.stringKeyToArr(capabilities.unlockKey);
97
+ await adb.dismissKeyguard();
98
+ const keys = helpers.stringKeyToArr(capabilities.unlockKey);
104
99
  if (await adb.getApiLevel() >= 21) {
105
- let els = await driver.findElOrEls('id', 'com.android.systemui:id/digit_text', true);
100
+ const els = await driver.findElOrEls('id', 'com.android.systemui:id/digit_text', true);
106
101
  if (_.isEmpty(els)) {
107
102
  // fallback to pin with key event
108
103
  return await helpers.pinUnlockWithKeyEvent(adb, driver, capabilities);
109
104
  }
110
- let pins = {};
111
- for (let el of els) {
112
- let text = await driver.getAttribute('text', util.unwrapElement(el));
105
+ const pins = {};
106
+ for (const el of els) {
107
+ const text = await driver.getAttribute('text', util.unwrapElement(el));
113
108
  pins[text] = el;
114
109
  }
115
- for (let pin of keys) {
116
- let el = pins[pin];
110
+ for (const pin of keys) {
111
+ const el = pins[pin];
117
112
  await driver.click(util.unwrapElement(el));
118
113
  }
119
114
  } else {
120
- for (let pin of keys) {
121
- let el = await driver.findElOrEls('id', `com.android.keyguard:id/key${pin}`, false);
115
+ for (const pin of keys) {
116
+ const el = await driver.findElOrEls('id', `com.android.keyguard:id/key${pin}`, false);
122
117
  if (el === null) {
123
118
  // fallback to pin with key event
124
119
  return await helpers.pinUnlockWithKeyEvent(adb, driver, capabilities);
@@ -126,10 +121,9 @@ helpers.pinUnlock = async function pinUnlock (adb, driver, capabilities) {
126
121
  await driver.click(util.unwrapElement(el));
127
122
  }
128
123
  }
129
- await waitForUnlock(adb, driver);
124
+ await waitForUnlock(adb);
130
125
  };
131
126
 
132
-
133
127
  /**
134
128
  * Wait for the display to be unlocked.
135
129
  * Some devices automatically accept typed 'pin' and 'password' code
@@ -139,21 +133,20 @@ helpers.pinUnlock = async function pinUnlock (adb, driver, capabilities) {
139
133
  * the enter key code.
140
134
  *
141
135
  * @param {ADB} adb The instance of ADB
142
- * @param {AndroidDriver} driver The instance of AndroidDriver
143
136
  */
144
- async function waitForUnlock (adb, driver) {
137
+ async function waitForUnlock (adb) {
145
138
  await sleep(UNLOCK_WAIT_TIME);
146
139
  if (!await adb.isScreenLocked()) {
147
140
  return;
148
141
  }
149
142
 
150
- await driver.pressKeyCode(KEYCODE_NUMPAD_ENTER);
143
+ await adb.keyevent(KEYCODE_NUMPAD_ENTER);
151
144
  await sleep(UNLOCK_WAIT_TIME);
152
145
  }
153
146
 
154
147
  helpers.pinUnlockWithKeyEvent = async function pinUnlockWithKeyEvent (adb, driver, capabilities) {
155
148
  logger.info(`Trying to unlock device using pin with keycode ${capabilities.unlockKey}`);
156
- await helpers.dismissKeyguard(driver, adb);
149
+ await adb.dismissKeyguard();
157
150
  const keys = helpers.stringKeyToArr(capabilities.unlockKey);
158
151
 
159
152
  // Some device does not have system key ids like 'com.android.keyguard:id/key'
@@ -167,11 +160,11 @@ helpers.pinUnlockWithKeyEvent = async function pinUnlockWithKeyEvent (adb, drive
167
160
  };
168
161
 
169
162
  helpers.passwordUnlock = async function passwordUnlock (adb, driver, capabilities) {
170
- logger.info(`Trying to unlock device using password ${capabilities.unlockKey}`);
171
- await helpers.dismissKeyguard(driver, adb);
172
- let key = capabilities.unlockKey;
163
+ const { unlockKey } = capabilities;
164
+ logger.info(`Trying to unlock device using password ${unlockKey}`);
165
+ await adb.dismissKeyguard();
173
166
  // Replace blank spaces with %s
174
- key = helpers.encodePassword(key);
167
+ const key = helpers.encodePassword(unlockKey);
175
168
  // Why adb ? It was less flaky
176
169
  await adb.shell(['input', 'text', key]);
177
170
  // Why sleeps ? Avoid some flakyness waiting for the input to receive the keys
@@ -192,21 +185,24 @@ helpers.getPatternKeyPosition = function getPatternKeyPosition (key, initPos, pi
192
185
  const pins = 9;
193
186
  const xPos = (key, x, piece) => Math.round(x + ((key % cols) || cols) * piece - piece / 2);
194
187
  const yPos = (key, y, piece) => Math.round(y + (Math.ceil(((key % pins) || pins) / cols) * piece - piece / 2));
195
- return {x: xPos(key, initPos.x, piece), y: yPos(key, initPos.y, piece)};
188
+ return {
189
+ x: xPos(key, initPos.x, piece),
190
+ y: yPos(key, initPos.y, piece)
191
+ };
196
192
  };
197
193
 
198
194
  helpers.getPatternActions = function getPatternActions (keys, initPos, piece) {
199
- let actions = [];
195
+ const actions = [];
200
196
  let lastPos;
201
197
  for (let key of keys) {
202
- let keyPos = helpers.getPatternKeyPosition(key, initPos, piece);
198
+ const keyPos = helpers.getPatternKeyPosition(key, initPos, piece);
203
199
  if (key === keys[0]) {
204
200
  actions.push({action: 'press', options: {element: null, x: keyPos.x, y: keyPos.y}});
205
201
  lastPos = keyPos;
206
202
  continue;
207
203
  }
208
- let moveTo = {x: 0, y: 0};
209
- let diffX = keyPos.x - lastPos.x;
204
+ const moveTo = {x: 0, y: 0};
205
+ const diffX = keyPos.x - lastPos.x;
210
206
  if (diffX > 0) {
211
207
  moveTo.x = piece;
212
208
  if (Math.abs(diffX) > piece) {
@@ -218,7 +214,7 @@ helpers.getPatternActions = function getPatternActions (keys, initPos, piece) {
218
214
  moveTo.x -= piece;
219
215
  }
220
216
  }
221
- let diffY = keyPos.y - lastPos.y;
217
+ const diffY = keyPos.y - lastPos.y;
222
218
  if (diffY > 0) {
223
219
  moveTo.y = piece;
224
220
  if (Math.abs(diffY) > piece) {
@@ -230,7 +226,10 @@ helpers.getPatternActions = function getPatternActions (keys, initPos, piece) {
230
226
  moveTo.y -= piece;
231
227
  }
232
228
  }
233
- actions.push({action: 'moveTo', options: {element: null, x: moveTo.x + lastPos.x, y: moveTo.y + lastPos.y}});
229
+ actions.push({
230
+ action: 'moveTo',
231
+ options: {element: null, x: moveTo.x + lastPos.x, y: moveTo.y + lastPos.y}
232
+ });
234
233
  lastPos = keyPos;
235
234
  }
236
235
  actions.push({action: 'release'});
@@ -238,9 +237,10 @@ helpers.getPatternActions = function getPatternActions (keys, initPos, piece) {
238
237
  };
239
238
 
240
239
  helpers.patternUnlock = async function patternUnlock (adb, driver, capabilities) {
241
- logger.info(`Trying to unlock device using pattern ${capabilities.unlockKey}`);
242
- await helpers.dismissKeyguard(driver, adb);
243
- let keys = helpers.stringKeyToArr(capabilities.unlockKey);
240
+ const { unlockKey } = capabilities;
241
+ logger.info(`Trying to unlock device using pattern ${unlockKey}`);
242
+ await adb.dismissKeyguard();
243
+ const keys = helpers.stringKeyToArr(unlockKey);
244
244
  /* We set the device pattern buttons as number of a regular phone
245
245
  * | • • • | | 1 2 3 |
246
246
  * | • • • | --> | 4 5 6 |
@@ -250,15 +250,15 @@ helpers.patternUnlock = async function patternUnlock (adb, driver, capabilities)
250
250
  included inside a FrameLayout, so we are going to try clicking on the buttons
251
251
  using the parent view bounds and math.
252
252
  */
253
- let apiLevel = await adb.getApiLevel();
254
- let el = await driver.findElOrEls('id',
253
+ const apiLevel = await adb.getApiLevel();
254
+ const el = await driver.findElOrEls('id',
255
255
  `com.android.${apiLevel >= 21 ? 'systemui' : 'keyguard'}:id/lockPatternView`,
256
256
  false
257
257
  );
258
- let initPos = await driver.getLocation(util.unwrapElement(el));
259
- let size = await driver.getSize(util.unwrapElement(el));
258
+ const initPos = await driver.getLocation(util.unwrapElement(el));
259
+ const size = await driver.getSize(util.unwrapElement(el));
260
260
  // Get actions to perform
261
- let actions = helpers.getPatternActions(keys, initPos, size.width / 3);
261
+ const actions = helpers.getPatternActions(keys, initPos, size.width / 3);
262
262
  // Perform gesture
263
263
  await driver.performTouch(actions);
264
264
  // Waits a bit for the device to be unlocked
@@ -271,5 +271,8 @@ helpers.PASSWORD_UNLOCK = PASSWORD_UNLOCK;
271
271
  helpers.PATTERN_UNLOCK = PATTERN_UNLOCK;
272
272
  helpers.FINGERPRINT_UNLOCK = FINGERPRINT_UNLOCK;
273
273
 
274
- export { PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, PASSWORD_UNLOCK, PATTERN_UNLOCK, FINGERPRINT_UNLOCK, helpers };
274
+ export {
275
+ PIN_UNLOCK, PIN_UNLOCK_KEY_EVENT, PASSWORD_UNLOCK, PATTERN_UNLOCK,
276
+ FINGERPRINT_UNLOCK, helpers
277
+ };
275
278
  export default helpers;
@@ -517,17 +517,20 @@ helpers.createChromedriverCaps = function createChromedriverCaps (opts, deviceId
517
517
  // add device id from adb
518
518
  caps.chromeOptions.androidDeviceSerial = deviceId;
519
519
 
520
- if (opts.loggingPrefs) {
521
- caps.loggingPrefs = opts.loggingPrefs;
520
+ if (_.isPlainObject(opts.loggingPrefs) || _.isPlainObject(opts.chromeLoggingPrefs)) {
521
+ if (opts.loggingPrefs) {
522
+ logger.warn(`The 'loggingPrefs' cap is deprecated; use the 'chromeLoggingPrefs' cap instead`);
523
+ }
524
+ caps.loggingPrefs = opts.chromeLoggingPrefs || opts.loggingPrefs;
522
525
  }
523
526
  if (opts.enablePerformanceLogging) {
524
527
  logger.warn(`The 'enablePerformanceLogging' cap is deprecated; simply use ` +
525
- `the 'loggingPrefs' cap instead, with a 'performance' key set to 'ALL'`);
528
+ `the 'chromeLoggingPrefs' cap instead, with a 'performance' key set to 'ALL'`);
526
529
  const newPref = {performance: 'ALL'};
527
530
  // don't overwrite other logging prefs that have been sent in if they exist
528
- caps.loggingPrefs = caps.loggingPrefs ?
529
- Object.assign({}, caps.loggingPrefs, newPref) :
530
- newPref;
531
+ caps.loggingPrefs = caps.loggingPrefs
532
+ ? Object.assign({}, caps.loggingPrefs, newPref)
533
+ : newPref;
531
534
  }
532
535
 
533
536
  if (opts.chromeOptions?.Arguments) {
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "mobile",
10
10
  "mobile testing"
11
11
  ],
12
- "version": "4.49.0",
12
+ "version": "4.52.1",
13
13
  "author": "appium",
14
14
  "license": "Apache-2.0",
15
15
  "repository": {
@@ -36,7 +36,7 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "@babel/runtime": "^7.0.0",
39
- "appium-adb": "^8.11.0",
39
+ "appium-adb": "^8.16.0",
40
40
  "appium-base-driver": "^7.0.0",
41
41
  "appium-chromedriver": "^4.13.0",
42
42
  "appium-support": "^2.47.1",
@@ -77,6 +77,7 @@
77
77
  "precommit-test"
78
78
  ],
79
79
  "devDependencies": {
80
+ "@xmldom/xmldom": "^0.x",
80
81
  "android-apidemos": "^3.0.0",
81
82
  "appium-gulp-plugins": "^5.4.0",
82
83
  "appium-test-support": "^1.0.0",
@@ -87,8 +88,7 @@
87
88
  "mocha": "^9.0.0",
88
89
  "mock-fs": "^5.0.0",
89
90
  "pre-commit": "^1.1.3",
90
- "sinon": "^11.0.0",
91
- "xmldom": "^0.x",
91
+ "sinon": "^12.0.0",
92
92
  "xpath": "^0.x"
93
93
  }
94
94
  }