appium-android-driver 7.7.0 → 7.8.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.
- package/CHANGELOG.md +14 -0
- package/build/lib/commands/file-actions.d.ts.map +1 -1
- package/build/lib/commands/file-actions.js +8 -9
- package/build/lib/commands/file-actions.js.map +1 -1
- package/build/lib/commands/general.d.ts.map +1 -1
- package/build/lib/commands/general.js +4 -5
- package/build/lib/commands/general.js.map +1 -1
- package/build/lib/commands/media-projection.d.ts.map +1 -1
- package/build/lib/commands/media-projection.js +3 -104
- package/build/lib/commands/media-projection.js.map +1 -1
- package/build/lib/commands/mixins.d.ts +5 -4
- package/build/lib/commands/mixins.d.ts.map +1 -1
- package/build/lib/commands/mixins.js.map +1 -1
- package/build/lib/commands/network.d.ts.map +1 -1
- package/build/lib/commands/network.js +17 -15
- package/build/lib/commands/network.js.map +1 -1
- package/build/lib/commands/types.d.ts +16 -0
- package/build/lib/commands/types.d.ts.map +1 -1
- package/build/lib/driver.d.ts +3 -0
- package/build/lib/driver.d.ts.map +1 -1
- package/build/lib/driver.js +7 -0
- package/build/lib/driver.js.map +1 -1
- package/build/lib/helpers/android.d.ts +2 -2
- package/build/lib/helpers/android.d.ts.map +1 -1
- package/build/lib/helpers/android.js +32 -47
- package/build/lib/helpers/android.js.map +1 -1
- package/build/lib/index.d.ts +1 -1
- package/build/lib/index.d.ts.map +1 -1
- package/build/lib/index.js +1 -1
- package/build/lib/index.js.map +1 -1
- package/lib/commands/file-actions.js +8 -9
- package/lib/commands/general.js +4 -5
- package/lib/commands/media-projection.js +4 -119
- package/lib/commands/mixins.ts +4 -4
- package/lib/commands/network.js +18 -16
- package/lib/commands/types.ts +18 -0
- package/lib/driver.ts +10 -0
- package/lib/helpers/android.ts +37 -44
- package/lib/index.ts +4 -1
- package/package.json +3 -3
- package/build/lib/stubs.d.ts +0 -7
- package/build/lib/stubs.d.ts.map +0 -1
- package/build/lib/stubs.js +0 -7
- package/build/lib/stubs.js.map +0 -1
- package/lib/stubs.ts +0 -7
|
@@ -1,24 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {fs, net, tempDir, util} from '@appium/support';
|
|
4
|
-
import {waitForCondition} from 'asyncbox';
|
|
5
|
-
import B from 'bluebird';
|
|
1
|
+
import {fs, net, util} from '@appium/support';
|
|
6
2
|
import _ from 'lodash';
|
|
7
3
|
import moment from 'moment';
|
|
8
4
|
import path from 'node:path';
|
|
9
|
-
import {SETTINGS_HELPER_PKG_ID} from '../helpers';
|
|
10
5
|
import {mixin} from './mixins';
|
|
11
6
|
|
|
12
7
|
// https://github.com/appium/io.appium.settings#internal-audio--video-recording
|
|
13
8
|
const DEFAULT_EXT = '.mp4';
|
|
14
|
-
const RECORDING_STARTUP_TIMEOUT_MS = 3 * 1000;
|
|
15
|
-
const RECORDING_STOP_TIMEOUT_MS = 3 * 1000;
|
|
16
9
|
const MIN_API_LEVEL = 29;
|
|
17
|
-
const RECORDING_SERVICE_NAME = `${SETTINGS_HELPER_PKG_ID}/.recorder.RecorderService`;
|
|
18
|
-
const RECORDING_ACTIVITY_NAME = `${SETTINGS_HELPER_PKG_ID}/io.appium.settings.Settings`;
|
|
19
|
-
const RECORDING_ACTION_START = `${SETTINGS_HELPER_PKG_ID}.recording.ACTION_START`;
|
|
20
|
-
const RECORDING_ACTION_STOP = `${SETTINGS_HELPER_PKG_ID}.recording.ACTION_STOP`;
|
|
21
|
-
const RECORDINGS_ROOT = `/storage/emulated/0/Android/data/${SETTINGS_HELPER_PKG_ID}/files`;
|
|
22
10
|
const DEFAULT_FILENAME_FORMAT = 'YYYY-MM-DDTHH-mm-ss';
|
|
23
11
|
|
|
24
12
|
/**
|
|
@@ -82,109 +70,6 @@ async function verifyMediaProjectionRecordingIsSupported(adb) {
|
|
|
82
70
|
}
|
|
83
71
|
}
|
|
84
72
|
|
|
85
|
-
class MediaProjectionRecorder {
|
|
86
|
-
/**
|
|
87
|
-
* @param {ADB} adb
|
|
88
|
-
*/
|
|
89
|
-
constructor(adb) {
|
|
90
|
-
this.adb = adb;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async isRunning() {
|
|
94
|
-
const stdout = await this.adb.shell([
|
|
95
|
-
'dumpsys',
|
|
96
|
-
'activity',
|
|
97
|
-
'services',
|
|
98
|
-
RECORDING_SERVICE_NAME,
|
|
99
|
-
]);
|
|
100
|
-
return stdout.includes(RECORDING_SERVICE_NAME);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
*
|
|
105
|
-
* @param {import('./types').StartMediaProjectionRecordingOpts} opts
|
|
106
|
-
* @returns {Promise<boolean>}
|
|
107
|
-
*/
|
|
108
|
-
async start(opts = {}) {
|
|
109
|
-
if (await this.isRunning()) {
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
await this.cleanup();
|
|
114
|
-
const {filename, maxDurationSec, priority, resolution} = opts;
|
|
115
|
-
const args = ['am', 'start', '-n', RECORDING_ACTIVITY_NAME, '-a', RECORDING_ACTION_START];
|
|
116
|
-
if (filename) {
|
|
117
|
-
args.push('--es', 'filename', filename);
|
|
118
|
-
}
|
|
119
|
-
if (maxDurationSec) {
|
|
120
|
-
args.push('--es', 'max_duration_sec', `${maxDurationSec}`);
|
|
121
|
-
}
|
|
122
|
-
if (priority) {
|
|
123
|
-
args.push('--es', 'priority', priority);
|
|
124
|
-
}
|
|
125
|
-
if (resolution) {
|
|
126
|
-
args.push('--es', 'resolution', resolution);
|
|
127
|
-
}
|
|
128
|
-
await this.adb.shell(args);
|
|
129
|
-
await new B((resolve, reject) => {
|
|
130
|
-
setTimeout(async () => {
|
|
131
|
-
if (!(await this.isRunning())) {
|
|
132
|
-
return reject(
|
|
133
|
-
new Error(
|
|
134
|
-
`The media projection recording is not running after ${RECORDING_STARTUP_TIMEOUT_MS}ms. ` +
|
|
135
|
-
`Please check the logcat output for more details.`
|
|
136
|
-
)
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
resolve();
|
|
140
|
-
}, RECORDING_STARTUP_TIMEOUT_MS);
|
|
141
|
-
});
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async cleanup() {
|
|
146
|
-
await this.adb.shell([`rm -f ${RECORDINGS_ROOT}/*`]);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async pullRecent() {
|
|
150
|
-
const recordings = await this.adb.ls(RECORDINGS_ROOT, ['-tr']);
|
|
151
|
-
if (_.isEmpty(recordings)) {
|
|
152
|
-
return null;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const dstPath = path.join(await tempDir.openDir(), recordings[0]);
|
|
156
|
-
// increase timeout to 5 minutes because it might take a while to pull a large video file
|
|
157
|
-
await this.adb.pull(`${RECORDINGS_ROOT}/${recordings[0]}`, dstPath, {timeout: 300000});
|
|
158
|
-
return dstPath;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async stop() {
|
|
162
|
-
if (!(await this.isRunning())) {
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
await this.adb.shell([
|
|
167
|
-
'am',
|
|
168
|
-
'start',
|
|
169
|
-
'-n',
|
|
170
|
-
RECORDING_ACTIVITY_NAME,
|
|
171
|
-
'-a',
|
|
172
|
-
RECORDING_ACTION_STOP,
|
|
173
|
-
]);
|
|
174
|
-
try {
|
|
175
|
-
await waitForCondition(async () => !(await this.isRunning()), {
|
|
176
|
-
waitMs: RECORDING_STOP_TIMEOUT_MS,
|
|
177
|
-
intervalMs: 500,
|
|
178
|
-
});
|
|
179
|
-
} catch (e) {
|
|
180
|
-
throw new Error(
|
|
181
|
-
`The attempt to stop the current media projection recording timed out after ` +
|
|
182
|
-
`${RECORDING_STOP_TIMEOUT_MS}ms`
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
return true;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
73
|
/**
|
|
189
74
|
* @type {import('./mixins').MediaProjectionMixin & ThisType<import('../driver').AndroidDriver>}
|
|
190
75
|
* @satisfies {import('@appium/types').ExternalDriver}
|
|
@@ -194,7 +79,7 @@ const MediaProjectionMixin = {
|
|
|
194
79
|
await verifyMediaProjectionRecordingIsSupported(this.adb);
|
|
195
80
|
|
|
196
81
|
const {resolution, priority, maxDurationSec, filename} = options;
|
|
197
|
-
const recorder =
|
|
82
|
+
const recorder = this.settingsApp.makeMediaProjectionRecorder();
|
|
198
83
|
const fname = adjustMediaExtension(filename || moment().format(DEFAULT_FILENAME_FORMAT));
|
|
199
84
|
const didStart = await recorder.start({
|
|
200
85
|
resolution,
|
|
@@ -215,14 +100,14 @@ const MediaProjectionMixin = {
|
|
|
215
100
|
async mobileIsMediaProjectionRecordingRunning() {
|
|
216
101
|
await verifyMediaProjectionRecordingIsSupported(this.adb);
|
|
217
102
|
|
|
218
|
-
const recorder =
|
|
103
|
+
const recorder = this.settingsApp.makeMediaProjectionRecorder();
|
|
219
104
|
return await recorder.isRunning();
|
|
220
105
|
},
|
|
221
106
|
|
|
222
107
|
async mobileStopMediaProjectionRecording(options = {}) {
|
|
223
108
|
await verifyMediaProjectionRecordingIsSupported(this.adb);
|
|
224
109
|
|
|
225
|
-
const recorder =
|
|
110
|
+
const recorder = this.settingsApp.makeMediaProjectionRecorder();
|
|
226
111
|
if (await recorder.stop()) {
|
|
227
112
|
this.log.info(
|
|
228
113
|
'Successfully stopped a media projection recording. Pulling the recorded media'
|
package/lib/commands/mixins.ts
CHANGED
|
@@ -14,7 +14,6 @@ import type {
|
|
|
14
14
|
ADB,
|
|
15
15
|
InstallOptions,
|
|
16
16
|
LogcatListener,
|
|
17
|
-
SmsListResult,
|
|
18
17
|
UninstallOptions,
|
|
19
18
|
} from 'appium-adb';
|
|
20
19
|
import type Chromedriver from 'appium-chromedriver';
|
|
@@ -564,15 +563,15 @@ export interface GeneralMixin {
|
|
|
564
563
|
/**
|
|
565
564
|
* Retrieves the list of recent system notifications.
|
|
566
565
|
*
|
|
567
|
-
* @returns See the documentation on `
|
|
566
|
+
* @returns See the documentation on `io.appium.settings -> getNotifications` for more details
|
|
568
567
|
*/
|
|
569
568
|
mobileGetNotifications(): Promise<StringRecord>;
|
|
570
569
|
|
|
571
570
|
/**
|
|
572
571
|
* Retrieves the list of recent SMS messages with their properties.
|
|
573
|
-
* @returns See the documentation on `
|
|
572
|
+
* @returns See the documentation on `io.appium.settings -> getSmsList` for more details
|
|
574
573
|
*/
|
|
575
|
-
mobileListSms(opts: types.ListSmsOpts): Promise<SmsListResult>;
|
|
574
|
+
mobileListSms(opts: types.ListSmsOpts): Promise<types.SmsListResult>;
|
|
576
575
|
|
|
577
576
|
/**
|
|
578
577
|
* Unlocks the device if it is locked. Noop if the device's screen is not locked.
|
|
@@ -711,6 +710,7 @@ export interface NetworkMixin {
|
|
|
711
710
|
* decoupling to override behaviour in other drivers like UiAutomator2.
|
|
712
711
|
*/
|
|
713
712
|
setWifiState(state: boolean): Promise<void>;
|
|
713
|
+
setDataState(state: boolean): Promise<void>;
|
|
714
714
|
toggleData(): Promise<void>;
|
|
715
715
|
toggleWiFi(): Promise<void>;
|
|
716
716
|
toggleFlightMode(): Promise<void>;
|
package/lib/commands/network.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import {mixin} from './mixins';
|
|
4
2
|
import _ from 'lodash';
|
|
5
3
|
import {errors} from 'appium/driver';
|
|
@@ -67,10 +65,10 @@ const NetworkMixin = {
|
|
|
67
65
|
/** @type {(Promise<any>|(() => Promise<any>))[]} */
|
|
68
66
|
const setters = [];
|
|
69
67
|
if (!_.isUndefined(wifi) && currentState.wifi !== Boolean(wifi)) {
|
|
70
|
-
setters.push(this.
|
|
68
|
+
setters.push(this.setWifiState(wifi));
|
|
71
69
|
}
|
|
72
70
|
if (!_.isUndefined(data) && currentState.data !== Boolean(data)) {
|
|
73
|
-
setters.push(this.
|
|
71
|
+
setters.push(this.setDataState(data));
|
|
74
72
|
}
|
|
75
73
|
if (!_.isUndefined(airplaneMode) && currentState.airplaneMode !== Boolean(airplaneMode)) {
|
|
76
74
|
setters.push(async () => {
|
|
@@ -170,26 +168,30 @@ const NetworkMixin = {
|
|
|
170
168
|
`${shouldEnableDataConnection ? 'enabled' : 'disabled'}`
|
|
171
169
|
);
|
|
172
170
|
} else {
|
|
173
|
-
await this.
|
|
171
|
+
await this.setDataState(shouldEnableDataConnection);
|
|
174
172
|
}
|
|
175
173
|
|
|
176
174
|
return await this.getNetworkConnection();
|
|
177
175
|
},
|
|
178
176
|
|
|
179
|
-
async setWifiState(
|
|
180
|
-
await this.
|
|
177
|
+
async setWifiState(isOn) {
|
|
178
|
+
await this.settingsApp.setWifiState(isOn, this.isEmulator());
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
async setDataState(isOn) {
|
|
182
|
+
await this.settingsApp.setDataState(isOn, this.isEmulator());
|
|
181
183
|
},
|
|
182
184
|
|
|
183
185
|
async toggleData() {
|
|
184
|
-
|
|
185
|
-
this.log.info(`Turning network data ${
|
|
186
|
-
await this.
|
|
186
|
+
const isOn = await this.adb.isDataOn();
|
|
187
|
+
this.log.info(`Turning network data ${!isOn ? 'on' : 'off'}`);
|
|
188
|
+
await this.setDataState(!isOn);
|
|
187
189
|
},
|
|
188
190
|
|
|
189
191
|
async toggleWiFi() {
|
|
190
|
-
|
|
191
|
-
this.log.info(`Turning WiFi ${
|
|
192
|
-
await this.
|
|
192
|
+
const isOn = await this.adb.isWifiOn();
|
|
193
|
+
this.log.info(`Turning WiFi ${!isOn ? 'on' : 'off'}`);
|
|
194
|
+
await this.setWifiState(!isOn);
|
|
193
195
|
},
|
|
194
196
|
|
|
195
197
|
async toggleFlightMode() {
|
|
@@ -206,7 +208,7 @@ const NetworkMixin = {
|
|
|
206
208
|
},
|
|
207
209
|
|
|
208
210
|
async setGeoLocation(location) {
|
|
209
|
-
await this.
|
|
211
|
+
await this.settingsApp.setGeoLocation(location, this.isEmulator());
|
|
210
212
|
try {
|
|
211
213
|
return await this.getGeoLocation();
|
|
212
214
|
} catch (e) {
|
|
@@ -224,11 +226,11 @@ const NetworkMixin = {
|
|
|
224
226
|
|
|
225
227
|
async mobileRefreshGpsCache(opts = {}) {
|
|
226
228
|
const {timeoutMs} = opts;
|
|
227
|
-
await this.
|
|
229
|
+
await this.settingsApp.refreshGeoLocationCache(timeoutMs);
|
|
228
230
|
},
|
|
229
231
|
|
|
230
232
|
async getGeoLocation() {
|
|
231
|
-
const {latitude, longitude, altitude} = await this.
|
|
233
|
+
const {latitude, longitude, altitude} = await this.settingsApp.getGeoLocation();
|
|
232
234
|
return {
|
|
233
235
|
latitude: parseFloat(String(latitude)) || GEO_EPSILON,
|
|
234
236
|
longitude: parseFloat(String(longitude)) || GEO_EPSILON,
|
package/lib/commands/types.ts
CHANGED
|
@@ -1130,3 +1130,21 @@ export interface GetUiModeOpts {
|
|
|
1130
1130
|
*/
|
|
1131
1131
|
mode: string;
|
|
1132
1132
|
}
|
|
1133
|
+
|
|
1134
|
+
export interface SmsListResultItem {
|
|
1135
|
+
id: string;
|
|
1136
|
+
address: string;
|
|
1137
|
+
person: string|null;
|
|
1138
|
+
date: string;
|
|
1139
|
+
read: string;
|
|
1140
|
+
status: string;
|
|
1141
|
+
type: string;
|
|
1142
|
+
subject: string|null;
|
|
1143
|
+
body: string;
|
|
1144
|
+
serviceCenter: string|null;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
export interface SmsListResult {
|
|
1148
|
+
items: SmsListResultItem[];
|
|
1149
|
+
total: number;
|
|
1150
|
+
}
|
package/lib/driver.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {BaseDriver} from 'appium/driver';
|
|
|
16
16
|
import ANDROID_DRIVER_CONSTRAINTS, {AndroidDriverConstraints} from './constraints';
|
|
17
17
|
import {helpers} from './helpers';
|
|
18
18
|
import {newMethodMap} from './method-map';
|
|
19
|
+
import { SettingsApp } from 'io.appium.settings';
|
|
19
20
|
|
|
20
21
|
export type AndroidDriverCaps = DriverCaps<AndroidDriverConstraints>;
|
|
21
22
|
export type W3CAndroidDriverCaps = W3CDriverCaps<AndroidDriverConstraints>;
|
|
@@ -31,6 +32,8 @@ class AndroidDriver
|
|
|
31
32
|
|
|
32
33
|
adb: ADB;
|
|
33
34
|
|
|
35
|
+
_settingsApp: SettingsApp;
|
|
36
|
+
|
|
34
37
|
unlocker: typeof helpers.unlocker;
|
|
35
38
|
|
|
36
39
|
apkStrings: StringRecord<StringRecord<string>>;
|
|
@@ -75,6 +78,13 @@ class AndroidDriver
|
|
|
75
78
|
this.opts = opts as AndroidDriverOpts;
|
|
76
79
|
}
|
|
77
80
|
|
|
81
|
+
get settingsApp() {
|
|
82
|
+
if (!this._settingsApp) {
|
|
83
|
+
this._settingsApp = new SettingsApp({adb: this.adb});
|
|
84
|
+
}
|
|
85
|
+
return this._settingsApp;
|
|
86
|
+
}
|
|
87
|
+
|
|
78
88
|
isEmulator() {
|
|
79
89
|
return helpers.isEmulator(this.adb, this.opts);
|
|
80
90
|
}
|
package/lib/helpers/android.ts
CHANGED
|
@@ -4,7 +4,13 @@ import type {AppiumServer, StringRecord} from '@appium/types';
|
|
|
4
4
|
import {ADB} from 'appium-adb';
|
|
5
5
|
import {retryInterval, waitForCondition} from 'asyncbox';
|
|
6
6
|
import B from 'bluebird';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
path as SETTINGS_APK_PATH,
|
|
9
|
+
SettingsApp,
|
|
10
|
+
SETTINGS_HELPER_ID,
|
|
11
|
+
UNICODE_IME,
|
|
12
|
+
EMPTY_IME,
|
|
13
|
+
} from 'io.appium.settings';
|
|
8
14
|
import _ from 'lodash';
|
|
9
15
|
import {EOL} from 'node:os';
|
|
10
16
|
import path from 'node:path';
|
|
@@ -57,8 +63,6 @@ const CHROME_BROWSER_PACKAGE_ACTIVITY = {
|
|
|
57
63
|
activity: 'com.google.android.apps.chrome.Main',
|
|
58
64
|
},
|
|
59
65
|
} as const;
|
|
60
|
-
const SETTINGS_HELPER_PKG_ID = 'io.appium.settings';
|
|
61
|
-
const SETTING_NOTIFICATIONS_LISTENER_SERVICE = `${SETTINGS_HELPER_PKG_ID}/.NLService`;
|
|
62
66
|
const EMULATOR_PATTERN = /\bemulator\b/i;
|
|
63
67
|
// These constants are in sync with
|
|
64
68
|
// https://developer.apple.com/documentation/xctest/xcuiapplicationstate/xcuiapplicationstaterunningbackground?language=objc
|
|
@@ -68,7 +72,6 @@ const APP_STATE = {
|
|
|
68
72
|
RUNNING_IN_BACKGROUND: 3,
|
|
69
73
|
RUNNING_IN_FOREGROUND: 4,
|
|
70
74
|
} as const;
|
|
71
|
-
const EMPTY_IME = `${SETTINGS_HELPER_PKG_ID}/.EmptyIME`;
|
|
72
75
|
|
|
73
76
|
function ensureNetworkSpeed(adb: ADB, networkSpeed: string) {
|
|
74
77
|
if (networkSpeed.toUpperCase() in adb.NETWORK_SPEED) {
|
|
@@ -344,13 +347,8 @@ const AndroidHelpers: AndroidHelpers = {
|
|
|
344
347
|
},
|
|
345
348
|
|
|
346
349
|
async ensureDeviceLocale(adb, language, country, script) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
logger.warn(`Got language: '${language}' and country: '${country}'`);
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
await adb.setDeviceLanguageCountry(language, country, script);
|
|
350
|
+
const settingsApp = new SettingsApp({adb});
|
|
351
|
+
await settingsApp.setDeviceLocale(language!, country!, script);
|
|
354
352
|
|
|
355
353
|
if (!(await adb.ensureCurrentLocale(language, country, script))) {
|
|
356
354
|
const message = script
|
|
@@ -686,10 +684,9 @@ const AndroidHelpers: AndroidHelpers = {
|
|
|
686
684
|
const defaultIME = await adb.defaultIME();
|
|
687
685
|
|
|
688
686
|
logger.debug(`Unsetting previous IME ${defaultIME}`);
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
await adb.
|
|
692
|
-
await adb.setIME(appiumIME);
|
|
687
|
+
logger.debug(`Setting IME to '${UNICODE_IME}'`);
|
|
688
|
+
await adb.enableIME(UNICODE_IME);
|
|
689
|
+
await adb.setIME(UNICODE_IME);
|
|
693
690
|
return defaultIME;
|
|
694
691
|
},
|
|
695
692
|
|
|
@@ -755,7 +752,7 @@ const AndroidHelpers: AndroidHelpers = {
|
|
|
755
752
|
await adb.shell([
|
|
756
753
|
'appops',
|
|
757
754
|
'set',
|
|
758
|
-
resultPkgs[0] ??
|
|
755
|
+
resultPkgs[0] ?? SETTINGS_HELPER_ID,
|
|
759
756
|
'android:mock_location',
|
|
760
757
|
'deny',
|
|
761
758
|
]);
|
|
@@ -793,65 +790,61 @@ const AndroidHelpers: AndroidHelpers = {
|
|
|
793
790
|
logger.debug('Pushing settings apk to device...');
|
|
794
791
|
|
|
795
792
|
try {
|
|
796
|
-
await AndroidHelpers.installHelperApp(adb,
|
|
793
|
+
await AndroidHelpers.installHelperApp(adb, SETTINGS_APK_PATH, SETTINGS_HELPER_ID);
|
|
797
794
|
} catch (err) {
|
|
798
795
|
if (throwError) {
|
|
799
796
|
throw err;
|
|
800
797
|
}
|
|
801
798
|
|
|
802
799
|
logger.warn(
|
|
803
|
-
`Ignored error while installing '${
|
|
800
|
+
`Ignored error while installing '${SETTINGS_APK_PATH}': ` +
|
|
804
801
|
`'${(err as Error).message}'. Features that rely on this helper ` +
|
|
805
802
|
'require the apk such as toggle WiFi and getting location ' +
|
|
806
803
|
'will raise an error if you try to use them.'
|
|
807
804
|
);
|
|
808
805
|
}
|
|
809
806
|
|
|
807
|
+
const settingsApp = new SettingsApp({adb});
|
|
810
808
|
// Reinstall would stop the settings helper process anyway, so
|
|
811
809
|
// there is no need to continue if the application is still running
|
|
812
|
-
if (await
|
|
810
|
+
if (await settingsApp.isRunningInForeground()) {
|
|
813
811
|
logger.debug(
|
|
814
|
-
`${
|
|
812
|
+
`${SETTINGS_HELPER_ID} is already running. ` +
|
|
815
813
|
`There is no need to reset its permissions.`
|
|
816
814
|
);
|
|
817
815
|
return;
|
|
818
816
|
}
|
|
819
817
|
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
try {
|
|
824
|
-
await adb.shell(['appops', 'set', SETTINGS_HELPER_PKG_ID, 'PROJECT_MEDIA', 'allow']);
|
|
825
|
-
} catch (err) {
|
|
826
|
-
logger.debug((err as Error).message);
|
|
827
|
-
}
|
|
828
|
-
try {
|
|
829
|
-
await adb.shell([
|
|
830
|
-
'cmd',
|
|
831
|
-
'notification',
|
|
832
|
-
'allow_listener',
|
|
833
|
-
SETTING_NOTIFICATIONS_LISTENER_SERVICE,
|
|
834
|
-
]);
|
|
835
|
-
} catch (err) {
|
|
836
|
-
logger.debug((err as Error).message);
|
|
818
|
+
const fixSettingsAppPermissionsForLegacyApis = async () => {
|
|
819
|
+
if (await adb.getApiLevel() > 23) {
|
|
820
|
+
return;
|
|
837
821
|
}
|
|
838
|
-
|
|
839
|
-
if (apiLevel <= 23) {
|
|
822
|
+
|
|
840
823
|
// Android 6- devices should have granted permissions
|
|
841
824
|
// https://github.com/appium/appium/pull/11640#issuecomment-438260477
|
|
842
825
|
const perms = ['SET_ANIMATION_SCALE', 'CHANGE_CONFIGURATION', 'ACCESS_FINE_LOCATION'];
|
|
843
|
-
logger.info(`Granting permissions ${perms} to '${
|
|
826
|
+
logger.info(`Granting permissions ${perms} to '${SETTINGS_HELPER_ID}'`);
|
|
844
827
|
await adb.grantPermissions(
|
|
845
|
-
|
|
828
|
+
SETTINGS_HELPER_ID,
|
|
846
829
|
perms.map((x) => `android.permission.${x}`)
|
|
847
830
|
);
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
try {
|
|
834
|
+
await B.all([
|
|
835
|
+
settingsApp.adjustNotificationsPermissions(),
|
|
836
|
+
settingsApp.adjustMediaProjectionServicePermissions(),
|
|
837
|
+
fixSettingsAppPermissionsForLegacyApis(),
|
|
838
|
+
]);
|
|
839
|
+
} catch (e) {
|
|
840
|
+
logger.debug(e.stack);
|
|
848
841
|
}
|
|
849
842
|
|
|
850
843
|
// launch io.appium.settings app due to settings failing to be set
|
|
851
844
|
// if the app is not launched prior to start the session on android 7+
|
|
852
845
|
// see https://github.com/appium/appium/issues/8957
|
|
853
846
|
try {
|
|
854
|
-
await
|
|
847
|
+
await settingsApp.requireRunning({
|
|
855
848
|
timeout: AndroidHelpers.isEmulator(adb, opts) ? 30000 : 5000,
|
|
856
849
|
});
|
|
857
850
|
} catch (err) {
|
|
@@ -1003,7 +996,7 @@ const AndroidHelpers: AndroidHelpers = {
|
|
|
1003
996
|
|
|
1004
997
|
if (!AndroidHelpers.isEmulator(adb, opts)) {
|
|
1005
998
|
if (mockLocationApp || _.isUndefined(mockLocationApp)) {
|
|
1006
|
-
await AndroidHelpers.setMockLocationApp(adb, mockLocationApp ||
|
|
999
|
+
await AndroidHelpers.setMockLocationApp(adb, mockLocationApp || SETTINGS_HELPER_ID);
|
|
1007
1000
|
} else {
|
|
1008
1001
|
await AndroidHelpers.resetMockLocation(adb);
|
|
1009
1002
|
}
|
|
@@ -1156,5 +1149,5 @@ const AndroidHelpers: AndroidHelpers = {
|
|
|
1156
1149
|
};
|
|
1157
1150
|
|
|
1158
1151
|
export const helpers = AndroidHelpers;
|
|
1159
|
-
export {APP_STATE,
|
|
1152
|
+
export {APP_STATE, SETTINGS_HELPER_ID, ensureNetworkSpeed, prepareAvdArgs};
|
|
1160
1153
|
export default AndroidHelpers;
|
package/lib/index.ts
CHANGED
|
@@ -6,7 +6,10 @@ export type * from './commands';
|
|
|
6
6
|
export {ANDROID_DRIVER_CONSTRAINTS as commonCapConstraints} from './constraints';
|
|
7
7
|
export * from './driver';
|
|
8
8
|
export * as doctor from './doctor/checks';
|
|
9
|
-
export {
|
|
9
|
+
export {
|
|
10
|
+
SETTINGS_HELPER_ID as SETTINGS_HELPER_PKG_ID,
|
|
11
|
+
default as androidHelpers
|
|
12
|
+
} from './helpers/android';
|
|
10
13
|
export type * from './helpers/types';
|
|
11
14
|
export {
|
|
12
15
|
CHROMIUM_WIN,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appium-android-driver",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.8.1",
|
|
4
4
|
"description": "Android UiAutomator and Chrome support for Appium",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"appium",
|
|
@@ -57,12 +57,12 @@
|
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@appium/support": "^4.2.0",
|
|
59
59
|
"@colors/colors": "^1.6.0",
|
|
60
|
-
"appium-adb": "^
|
|
60
|
+
"appium-adb": "^12.0.0",
|
|
61
61
|
"appium-chromedriver": "^5.5.1",
|
|
62
62
|
"asyncbox": "^3.0.0",
|
|
63
63
|
"axios": "^1.x",
|
|
64
64
|
"bluebird": "^3.4.7",
|
|
65
|
-
"io.appium.settings": "^5.
|
|
65
|
+
"io.appium.settings": "^5.7.1",
|
|
66
66
|
"lodash": "^4.17.4",
|
|
67
67
|
"lru-cache": "^10.0.1",
|
|
68
68
|
"moment": "^2.24.0",
|
package/build/lib/stubs.d.ts
DELETED
package/build/lib/stubs.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stubs.d.ts","sourceRoot":"","sources":["../../lib/stubs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,QAAQ,oBAAoB,CAAC"}
|
package/build/lib/stubs.js
DELETED
package/build/lib/stubs.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stubs.js","sourceRoot":"","sources":["../../lib/stubs.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
|