How to use this.adb.refreshGeoLocationCache method in Appium Android Driver

Best JavaScript code snippet using appium-android-driver

Run Appium Android Driver automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

network.js

Source: network.js Github

copy
1import _ from 'lodash';
2import { errors } from '@appium/base-driver';
3import B from 'bluebird';
4
5let commands = {}, helpers = {}, extensions = {};
6
7const AIRPLANE_MODE_MASK = 0b001;
8const WIFI_MASK = 0b010;
9const DATA_MASK = 0b100;
10// The value close to zero, but not zero, is needed
11// to trick JSON generation and send a float value instead of an integer,
12// This allows strictly-typed clients, like Java, to properly
13// parse it. Otherwise float 0.0 is always represented as integer 0 in JS.
14// The value must not be greater than DBL_EPSILON (https://opensource.apple.com/source/Libc/Libc-498/include/float.h)
15const GEO_EPSILON = Number.MIN_VALUE;
16
17commands.getNetworkConnection = async function getNetworkConnection () {
18  this.log.info('Getting network connection');
19  let airplaneModeOn = await this.adb.isAirplaneModeOn();
20  let connection = airplaneModeOn ? AIRPLANE_MODE_MASK : 0;
21
22  // no need to check anything else if we are in airplane mode
23  if (!airplaneModeOn) {
24    let wifiOn = await this.isWifiOn();
25    connection |= (wifiOn ? WIFI_MASK : 0);
26    let dataOn = await this.adb.isDataOn();
27    connection |= (dataOn ? DATA_MASK : 0);
28  }
29
30  return connection;
31};
32
33/**
34 * decoupling to override the behaviour in other drivers like UiAutomator2.
35 */
36commands.isWifiOn = async function isWifiOn () {
37  return await this.adb.isWifiOn();
38};
39
40commands.setNetworkConnection = async function setNetworkConnection (type) {
41  this.log.info('Setting network connection');
42  // decode the input
43  const shouldEnableAirplaneMode = (type & AIRPLANE_MODE_MASK) !== 0;
44  const shouldEnableWifi = (type & WIFI_MASK) !== 0;
45  const shouldEnableDataConnection = (type & DATA_MASK) !== 0;
46
47  const currentState = await this.getNetworkConnection();
48  const isAirplaneModeEnabled = (currentState & AIRPLANE_MODE_MASK) !== 0;
49  const isWiFiEnabled = (currentState & WIFI_MASK) !== 0;
50  const isDataEnabled = (currentState & DATA_MASK) !== 0;
51
52  if (shouldEnableAirplaneMode !== isAirplaneModeEnabled) {
53    await this.wrapBootstrapDisconnect(async () => {
54      await this.adb.setAirplaneMode(shouldEnableAirplaneMode);
55    });
56    await this.wrapBootstrapDisconnect(async () => {
57      await this.adb.broadcastAirplaneMode(shouldEnableAirplaneMode);
58    });
59  } else {
60    this.log.info(`Not changing airplane mode, since it is already ` +
61             `${shouldEnableAirplaneMode ? 'enabled' : 'disabled'}`);
62  }
63
64  if (shouldEnableWifi === isWiFiEnabled && shouldEnableDataConnection === isDataEnabled) {
65    this.log.info('Not changing data connection/Wi-Fi states, since they are already set to expected values');
66    if (await this.adb.isAirplaneModeOn()) {
67      return AIRPLANE_MODE_MASK | currentState;
68    }
69    return ~AIRPLANE_MODE_MASK & currentState;
70  }
71
72  await this.wrapBootstrapDisconnect(async () => {
73    if (shouldEnableWifi !== isWiFiEnabled) {
74      await this.setWifiState(shouldEnableWifi);
75    } else {
76      this.log.info(`Not changing Wi-Fi state, since it is already ` +
77        `${shouldEnableWifi ? 'enabled' : 'disabled'}`);
78    }
79
80    if (shouldEnableAirplaneMode) {
81      this.log.info('Not changing data connection state, because airplane mode is enabled');
82    } else if (shouldEnableDataConnection === isDataEnabled) {
83      this.log.info(`Not changing data connection state, since it is already ` +
84        `${shouldEnableDataConnection ? 'enabled' : 'disabled'}`);
85    } else {
86      await this.adb.setDataState(shouldEnableDataConnection, this.isEmulator());
87    }
88  });
89
90  return await this.getNetworkConnection();
91};
92
93/**
94 * decoupling to override behaviour in other drivers like UiAutomator2.
95 */
96commands.setWifiState = async function setWifiState (wifi) {
97  await this.adb.setWifiState(wifi, this.isEmulator());
98};
99
100commands.toggleData = async function toggleData () {
101  let data = !(await this.adb.isDataOn());
102  this.log.info(`Turning network data ${data ? 'on' : 'off'}`);
103  await this.wrapBootstrapDisconnect(async () => {
104    await this.adb.setWifiAndData({data}, this.isEmulator());
105  });
106};
107
108commands.toggleWiFi = async function toggleWiFi () {
109  let wifi = !(await this.adb.isWifiOn());
110  this.log.info(`Turning WiFi ${wifi ? 'on' : 'off'}`);
111  await this.wrapBootstrapDisconnect(async () => {
112    await this.adb.setWifiAndData({wifi}, this.isEmulator());
113  });
114};
115
116commands.toggleFlightMode = async function toggleFlightMode () {
117  /*
118   * TODO: Implement isRealDevice(). This method fails on
119   * real devices, it should throw a NotYetImplementedError
120   */
121  let flightMode = !(await this.adb.isAirplaneModeOn());
122  this.log.info(`Turning flight mode ${flightMode ? 'on' : 'off'}`);
123  await this.wrapBootstrapDisconnect(async () => {
124    await this.adb.setAirplaneMode(flightMode);
125  });
126  await this.wrapBootstrapDisconnect(async () => {
127    await this.adb.broadcastAirplaneMode(flightMode);
128  });
129};
130
131commands.setGeoLocation = async function setGeoLocation (location) {
132  await this.adb.setGeoLocation(location, this.isEmulator());
133  try {
134    return await this.getGeoLocation();
135  } catch (e) {
136    this.log.warn(`Could not get the current geolocation info: ${e.message}`);
137    this.log.warn(`Returning the default zero'ed values`);
138    return {
139      latitude: GEO_EPSILON,
140      longitude: GEO_EPSILON,
141      altitude: GEO_EPSILON,
142    };
143  }
144};
145
146/**
147 * @typedef {Object} GpsCacheRefreshOptions
148 * @property {number} timeoutMs [20000] The maximum number of milliseconds
149 * to block until GPS cache is refreshed. Providing zero or a negative
150 * value to it skips waiting completely.
151 */
152
153/**
154 * Sends an async request to refresh the GPS cache.
155 * This feature only works if the device under test has
156 * Google Play Services installed. In case the vanilla
157 * LocationManager is used the device API level must be at
158 * version 30 (Android R) or higher.
159 *
160 * @param {GpsCacheRefreshOptions} opts
161 */
162commands.mobileRefreshGpsCache = async function mobileRefreshGpsCache (opts = {}) {
163  const { timeoutMs } = opts;
164  await this.adb.refreshGeoLocationCache(timeoutMs);
165};
166
167commands.getGeoLocation = async function getGeoLocation () {
168  const {latitude, longitude, altitude} = await this.adb.getGeoLocation();
169  return {
170    latitude: parseFloat(latitude) || GEO_EPSILON,
171    longitude: parseFloat(longitude) || GEO_EPSILON,
172    altitude: parseFloat(altitude) || GEO_EPSILON,
173  };
174};
175// https://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_DPAD_CENTER
176// in the android docs, this is how the keycodes are defined
177const KeyCode = {
178  UP: 19,
179  DOWN: 20,
180  RIGHT: 22,
181  CENTER: 23
182};
183commands.toggleLocationServices = async function toggleLocationServices () {
184  this.log.info('Toggling location services');
185  let api = await this.adb.getApiLevel();
186  if (this.isEmulator()) {
187    let providers = await this.adb.getLocationProviders();
188    let isGpsEnabled = providers.indexOf('gps') !== -1;
189    await this.adb.toggleGPSLocationProvider(!isGpsEnabled);
190    return;
191  }
192
193  if (api > 15) {
194    let seq = [KeyCode.UP, KeyCode.UP];
195    if (api === 16) {
196      // This version of Android has a "parent" button in its action bar
197      seq.push(KeyCode.DOWN);
198    } else if (api < 28) {
199      // Newer versions of Android have the toggle in the Action bar
200      seq = [KeyCode.RIGHT, KeyCode.RIGHT, KeyCode.UP];
201      /*
202       * Once the Location services switch is OFF, it won't receive focus
203       * when going back to the Location Services settings screen unless we
204       * send a dummy keyevent (UP) *before* opening the settings screen
205       */
206      await this.adb.keyevent(KeyCode.UP);
207    } else if (api >= 28) {
208      // Even newer versions of android have the toggle in a bar below the action bar
209      // this means a single right click will cause it to be selected.
210      seq = [KeyCode.RIGHT];
211      await this.adb.keyevent(KeyCode.UP);
212    }
213    await this.toggleSetting('LOCATION_SOURCE_SETTINGS', seq);
214  } else {
215    // There's no global location services toggle on older Android versions
216    throw new errors.NotYetImplementedError();
217  }
218};
219
220helpers.toggleSetting = async function toggleSetting (setting, preKeySeq) {
221  /*
222   * preKeySeq is the keyevent sequence to send over ADB in order
223   * to position the cursor on the right option.
224   * By default it's [up, up, down] because we usually target the 1st item in
225   * the screen, and sometimes when opening settings activities the cursor is
226   * already positionned on the 1st item, but we can't know for sure
227   */
228  if (_.isNull(preKeySeq)) {
229    preKeySeq = [KeyCode.UP, KeyCode.UP, KeyCode.DOWN];
230  }
231
232  await this.openSettingsActivity(setting);
233
234  for (let key of preKeySeq) {
235    await this.doKey(key);
236  }
237
238  let {appPackage, appActivity} = await this.adb.getFocusedPackageAndActivity();
239
240  /*
241   * Click and handle potential ADB disconnect that occurs on official
242   * emulator when the network connection is disabled
243   */
244  await this.wrapBootstrapDisconnect(async () => {
245    await this.doKey(KeyCode.CENTER);
246  });
247
248  /*
249   * In one particular case (enable Location Services), a pop-up is
250   * displayed on some platforms so the user accepts or refuses that Google
251   * collects location data. So we wait for that pop-up to open, if it
252   * doesn't then proceed
253   */
254  try {
255    await this.adb.waitForNotActivity(appPackage, appActivity, 5000);
256    await this.doKey(KeyCode.RIGHT);
257    await this.doKey(KeyCode.CENTER);
258    await this.adb.waitForNotActivity(appPackage, appActivity, 5000);
259  } catch (ign) {}
260
261  await this.adb.back();
262};
263
264helpers.doKey = async function doKey (key) {
265  // TODO: Confirm we need this delay. Seems to work without it.
266  await B.delay(2000);
267  await this.adb.keyevent(key);
268};
269
270helpers.wrapBootstrapDisconnect = async function wrapBootstrapDisconnect (wrapped) {
271  if (!this.bootstrap) {
272    return await wrapped();
273  }
274
275  this.bootstrap.ignoreUnexpectedShutdown = true;
276  try {
277    await wrapped();
278    await this.adb.restart();
279    await this.bootstrap.start(this.opts.appPackage, this.opts.disableAndroidWatchers, this.opts.acceptSslCerts);
280  } finally {
281    this.bootstrap.ignoreUnexpectedShutdown = false;
282  }
283};
284
285Object.assign(extensions, commands, helpers);
286export { commands, helpers };
287export default extensions;
288
Full Screen

Accelerate Your Automation Test Cycles With LambdaTest

Leverage LambdaTest’s cloud-based platform to execute your automation tests in parallel and trim down your test execution time significantly. Your first 100 automation testing minutes are on us.

Try LambdaTest

Run JavaScript Tests on LambdaTest Cloud Grid

Execute automation tests with Appium Android Driver on a cloud-based Grid of 3000+ real browsers and operating systems for both web and mobile applications.

Test now for Free
LambdaTestX

We use cookies to give you the best experience. Cookies help to provide a more personalized experience and relevant advertising for you, and web analytics for us. Learn More in our Cookies policy, Privacy & Terms of service

Allow Cookie
Sarah

I hope you find the best code examples for your project.

If you want to accelerate automated browser testing, try LambdaTest. Your first 100 automation testing minutes are FREE.

Sarah Elson (Product & Growth Lead)