io.appium.settings
Version:
App for dealing with Android settings
168 lines • 7.09 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SettingsApp = void 0;
const logger_1 = require("./logger");
const asyncbox_1 = require("asyncbox");
const constants_1 = require("./constants");
const animation_1 = require("./commands/animation");
const bluetooth_1 = require("./commands/bluetooth");
const clipboard_1 = require("./commands/clipboard");
const geolocation_1 = require("./commands/geolocation");
const locale_1 = require("./commands/locale");
const media_1 = require("./commands/media");
const network_1 = require("./commands/network");
const notifications_1 = require("./commands/notifications");
const sms_1 = require("./commands/sms");
const typing_1 = require("./commands/typing");
const media_projection_1 = require("./commands/media-projection");
class SettingsApp {
adb;
log;
constructor(opts) {
this.adb = opts.adb;
this.log = logger_1.log;
}
/**
* Ensures that Appium Settings helper application is running
* and starts it if necessary
*
* @param opts Startup options
* @throws {Error} If Appium Settings has failed to start
* @returns Self instance for chaining
*/
async requireRunning(opts = {}) {
const { timeout = 5000, shouldRestoreCurrentApp = false, forceRestart = false, } = opts;
if (forceRestart) {
await this.adb.forceStop(constants_1.SETTINGS_HELPER_ID);
}
else if (await this.isRunningInForeground()) {
return this;
}
this.log.debug(logger_1.LOG_PREFIX, 'Starting Appium Settings app');
let appPackage;
if (shouldRestoreCurrentApp) {
try {
const result = await this.adb.getFocusedPackageAndActivity();
appPackage = result.appPackage ?? undefined;
}
catch (e) {
this.log.warn(logger_1.LOG_PREFIX, `The current application can not be restored: ${e.message}`);
}
}
await this.adb.startApp({
pkg: constants_1.SETTINGS_HELPER_ID,
activity: constants_1.SETTINGS_HELPER_MAIN_ACTIVITY,
action: 'android.intent.action.MAIN',
category: 'android.intent.category.LAUNCHER',
stopApp: false,
waitForLaunch: false,
});
try {
await (0, asyncbox_1.waitForCondition)(async () => await this.isRunningInForeground(), {
waitMs: timeout,
intervalMs: 300,
});
if (shouldRestoreCurrentApp && appPackage) {
try {
await this.adb.activateApp(appPackage);
}
catch (e) {
logger_1.log.warn(`The current application can not be restored: ${e.message}`);
}
}
return this;
}
catch {
throw new Error(`Appium Settings app is not running after ${timeout}ms`);
}
}
/**
* If the io.appium.settings package has running foreground service.
*
* @throws {Error} If the method gets an error in the adb shell execution
* @returns Return true if the device Settings app has a service running in foreground
*/
async isRunningInForeground() {
// 'dumpsys activity services <package>' had slightly better performance
// than 'dumpsys activity services' and parsing the foreground apps.
const output = await this.adb.shell(['dumpsys', 'activity', 'services', constants_1.SETTINGS_HELPER_ID]);
return output.includes('isForeground=true');
}
/**
* Performs broadcast and verifies the result of it
*
* @param args Arguments passed to the `am broadcast` command
* @param action The exception message in case of broadcast failure
* @param requireRunningApp Whether to run a check for a running Appium Settings app
* @returns The broadcast output
* @throws {Error} If the broadcast fails
*/
async checkBroadcast(args, action, requireRunningApp = true) {
if (requireRunningApp) {
await this.requireRunning({ shouldRestoreCurrentApp: true });
}
const output = await this.adb.shell([
'am', 'broadcast',
...args,
]);
if (!output.includes('result=-1')) {
this.log.debug(logger_1.LOG_PREFIX, output);
const error = new Error(`Cannot execute the '${action}' action. Check the logcat output for more details.`);
error.output = output;
throw error;
}
return output;
}
/**
* Parses the output in JSON format retrieved from
* the corresponding Appium Settings broadcast calls
*
* @param output The actual command output
* @param entityName The name of the entity which is going to be parsed
* @returns The parsed JSON object
* @throws {Error} If the output cannot be parsed as a valid JSON
*/
_parseJsonData(output, entityName) {
if (!/\bresult=-1\b/.test(output) || !/\bdata="/.test(output)) {
this.log.debug(logger_1.LOG_PREFIX, output);
throw new Error(`Cannot retrieve ${entityName} from the device. ` +
'Check the server log for more details');
}
const match = /\bdata="(.+)",?/.exec(output);
if (!match) {
this.log.debug(logger_1.LOG_PREFIX, output);
throw new Error(`Cannot parse ${entityName} from the command output. ` +
'Check the server log for more details');
}
const jsonStr = match[1].trim();
try {
return JSON.parse(jsonStr);
}
catch {
logger_1.log.debug(jsonStr);
throw new Error(`Cannot parse ${entityName} from the resulting data string. ` +
'Check the server log for more details');
}
}
setAnimationState = animation_1.setAnimationState;
setBluetoothState = bluetooth_1.setBluetoothState;
unpairAllBluetoothDevices = bluetooth_1.unpairAllBluetoothDevices;
getClipboard = clipboard_1.getClipboard;
setGeoLocation = geolocation_1.setGeoLocation;
getGeoLocation = geolocation_1.getGeoLocation;
refreshGeoLocationCache = geolocation_1.refreshGeoLocationCache;
listSupportedLocales = locale_1.listSupportedLocales;
setDeviceLocale = locale_1.setDeviceLocale;
scanMedia = media_1.scanMedia;
setDataState = network_1.setDataState;
setWifiState = network_1.setWifiState;
getNotifications = notifications_1.getNotifications;
adjustNotificationsPermissions = notifications_1.adjustNotificationsPermissions;
getSmsList = sms_1.getSmsList;
performEditorAction = typing_1.performEditorAction;
typeUnicode = typing_1.typeUnicode;
makeMediaProjectionRecorder = media_projection_1.makeMediaProjectionRecorder;
adjustMediaProjectionServicePermissions = media_projection_1.adjustMediaProjectionServicePermissions;
}
exports.SettingsApp = SettingsApp;
//# sourceMappingURL=client.js.map