io.appium.settings 3.2.0 → 3.5.0

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/README.md CHANGED
@@ -134,6 +134,12 @@ $ adb shell am startservice --user 0 -n io.appium.settings/.LocationService --es
134
134
  Running the command again stops sending the previously specified location and starts sending updates for the
135
135
  new mock location.
136
136
 
137
+ Additionally the service allows to provide the following optional parameters to the mocked
138
+ location:
139
+
140
+ - `speed`: the speed, in meters/second over ground. A float value greater than zero is acceptable.
141
+ - `bearing`: the bearing, in degrees. Bearing is the horizontal direction of travel of this device, and is not related to the device orientation. The input will be wrapped into the range (0.0, 360.0]
142
+
137
143
  Stop sending new mocklocations and clean up everything (remove the mock location providers) by executing:
138
144
  ```shell
139
145
  $ adb shell am stopservice io.appium.settings/.LocationService
@@ -280,6 +286,23 @@ The example of the resulting data:
280
286
  ```
281
287
 
282
288
 
289
+ ## Media Scanning
290
+
291
+ Since version 3.5 Appium Settings supports broadcast messages handling
292
+ that performs media scanning in response to `io.appium.settings.scan_media`
293
+ intent. This was done due to `android.intent.action.MEDIA_SCANNER_SCAN_FILE` deprecation
294
+ since Android API version 30. To scan the given file or folder for media data simply run:
295
+
296
+ ```bash
297
+ $ adb shell am broadcast -a io.appium.settings.scan_media --es path /sdcard/media
298
+ ```
299
+
300
+ This command will _recursively_ scan all files inside of `/sdcard/media` folder
301
+ and add them to the media library if their MIME types are supported. If the
302
+ file/folder in _path_ does not exist/is not readable or is not provided then an
303
+ error will be returned and the corresponding log message would be written into logs.
304
+
305
+
283
306
  ## Notes:
284
307
 
285
308
  * You have to specify the receiver class if the app has never been executed before:
Binary file
package/app/build.gradle CHANGED
@@ -1,14 +1,13 @@
1
1
  apply plugin: 'com.android.application'
2
2
 
3
3
  android {
4
- compileSdkVersion 28
5
- buildToolsVersion '28.0.3'
4
+ compileSdkVersion 29
6
5
 
7
6
  defaultConfig {
8
7
  minSdkVersion 18
9
- targetSdkVersion 28
10
- versionCode 27
11
- versionName "3.2.0"
8
+ targetSdkVersion 29
9
+ versionCode 31
10
+ versionName "3.5.0"
12
11
  applicationId "io.appium.settings"
13
12
  }
14
13
 
@@ -4,6 +4,7 @@
4
4
  package="io.appium.settings">
5
5
 
6
6
  <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
7
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
7
8
  <uses-permission android:name="android.permission.WAKE_LOCK"/>
8
9
  <uses-permission android:name="android.permission.INTERNET" />
9
10
  <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
@@ -132,5 +133,8 @@
132
133
  <receiver android:name=".receivers.SmsReader"
133
134
  android:exported="true"
134
135
  tools:ignore="ExportedReceiver" />
136
+ <receiver android:name=".receivers.MediaScannerReceiver"
137
+ android:exported="true"
138
+ tools:ignore="ExportedReceiver" />
135
139
  </application>
136
140
  </manifest>
@@ -20,7 +20,6 @@ import android.app.Service;
20
20
  import android.content.Context;
21
21
  import android.content.Intent;
22
22
  import android.content.pm.PackageManager;
23
- import android.location.Criteria;
24
23
  import android.location.Location;
25
24
  import android.location.LocationManager;
26
25
  import android.location.LocationProvider;
@@ -40,21 +39,16 @@ import java.util.TimerTask;
40
39
  import io.appium.settings.helpers.NotificationHelpers;
41
40
  import io.appium.settings.helpers.PlayServicesHelpers;
42
41
  import io.appium.settings.location.FusedLocationProvider;
43
- import io.appium.settings.location.LocationFactory;
42
+ import io.appium.settings.location.LocationBuilder;
44
43
  import io.appium.settings.location.LocationManagerProvider;
45
44
  import io.appium.settings.location.MockLocationProvider;
46
45
 
47
46
  public class LocationService extends Service {
48
47
  private static final String TAG = "MOCKED LOCATION SERVICE";
49
48
 
50
- private static final String LONGITUDE_PARAMETER_KEY = "longitude";
51
- private static final String LATITUDE_PARAMETER_KEY = "latitude";
52
- private static final String ALTITUDE_PARAMETER_KEY = "altitude";
53
-
54
49
  private static final long UPDATE_INTERVAL_MS = 2000L;
55
50
 
56
51
  private final List<MockLocationProvider> mockLocationProviders = new LinkedList<>();
57
- private final LocationFactory locationFactory = new LocationFactory();
58
52
  private final Timer locationUpdatesTimer = new Timer();
59
53
  private TimerTask locationUpdateTask;
60
54
 
@@ -85,7 +79,6 @@ public class LocationService extends Service {
85
79
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
86
80
  finishForegroundSetup();
87
81
  }
88
- Log.i(TAG, "INTENT " + intent.getExtras());
89
82
 
90
83
  handleIntent(intent);
91
84
 
@@ -104,9 +97,9 @@ public class LocationService extends Service {
104
97
  if (intent == null) {
105
98
  return;
106
99
  }
107
- // update the locationFactory also if the service is already running to mock
108
- updateMockLocationFactory(intent);
109
- scheduleLocationUpdate();
100
+ Log.i(TAG, "INTENT " + intent.getExtras());
101
+
102
+ scheduleLocationUpdate(intent);
110
103
  }
111
104
 
112
105
  private void enableLocationProviders() {
@@ -143,7 +136,7 @@ public class LocationService extends Service {
143
136
  Log.d(TAG, String.format("Created mock providers: %s", mockLocationProviders.toString()));
144
137
  }
145
138
 
146
- private void scheduleLocationUpdate() {
139
+ private void scheduleLocationUpdate(final Intent intent) {
147
140
  Log.i(TAG, "Scheduling mock location updates");
148
141
 
149
142
  // If we run 'startservice' again we should schedule an update right away to avoid a delay
@@ -155,7 +148,7 @@ public class LocationService extends Service {
155
148
  @Override
156
149
  public void run() {
157
150
  for (MockLocationProvider mockLocationProvider : mockLocationProviders) {
158
- Location location = locationFactory.createLocation(mockLocationProvider.getProviderName(), Criteria.ACCURACY_FINE);
151
+ Location location = LocationBuilder.buildFromIntent(intent, mockLocationProvider.getProviderName());
159
152
  Log.d(TAG, String.format("Setting location of '%s' to '%s'", mockLocationProvider.getProviderName(), location));
160
153
  try {
161
154
  mockLocationProvider.setLocation(location);
@@ -170,36 +163,6 @@ public class LocationService extends Service {
170
163
  locationUpdatesTimer.schedule(locationUpdateTask, 0, UPDATE_INTERVAL_MS);
171
164
  }
172
165
 
173
- private void updateMockLocationFactory(Intent intent) {
174
- double longitude;
175
- try {
176
- longitude = Double.valueOf(intent.getStringExtra("longitude"));
177
- } catch (NumberFormatException e) {
178
- throw new IllegalArgumentException(
179
- String.format("longitude should be a valid number. '%s' is given instead",
180
- intent.getStringExtra(LONGITUDE_PARAMETER_KEY)));
181
- }
182
- double latitude;
183
- try {
184
- latitude = Double.valueOf(intent.getStringExtra("latitude"));
185
- } catch (NumberFormatException e) {
186
- throw new IllegalArgumentException(
187
- String.format("latitude should be a valid number. '%s' is given instead",
188
- intent.getStringExtra(LATITUDE_PARAMETER_KEY)));
189
- }
190
- double altitude = 0.0;
191
- try {
192
- if (intent.hasExtra(ALTITUDE_PARAMETER_KEY)) {
193
- altitude = Double.valueOf(intent.getStringExtra(ALTITUDE_PARAMETER_KEY));
194
- }
195
- } catch (NumberFormatException e) {
196
- Log.e(TAG, String.format("altitude should be a valid number. '%s' is given instead",
197
- intent.getStringExtra(ALTITUDE_PARAMETER_KEY)));
198
- }
199
-
200
- locationFactory.setLocation(latitude, longitude, altitude);
201
- }
202
-
203
166
  private List<MockLocationProvider> createMockProviders(LocationManager locationManager) {
204
167
  List<String> providers = locationManager.getAllProviders();
205
168
  List<MockLocationProvider> mockProviders = new LinkedList<>();
@@ -24,7 +24,7 @@ import android.os.Bundle;
24
24
  import android.os.Handler;
25
25
  import android.util.Log;
26
26
 
27
- import java.util.ArrayList;
27
+ import java.util.Arrays;
28
28
  import java.util.List;
29
29
 
30
30
  import io.appium.settings.receivers.AnimationSettingReceiver;
@@ -34,6 +34,7 @@ import io.appium.settings.receivers.DataConnectionSettingReceiver;
34
34
  import io.appium.settings.receivers.HasAction;
35
35
  import io.appium.settings.receivers.LocaleSettingReceiver;
36
36
  import io.appium.settings.receivers.LocationInfoReceiver;
37
+ import io.appium.settings.receivers.MediaScannerReceiver;
37
38
  import io.appium.settings.receivers.NotificationsReceiver;
38
39
  import io.appium.settings.receivers.SmsReader;
39
40
  import io.appium.settings.receivers.UnpairBluetoothDevicesReceiver;
@@ -50,18 +51,19 @@ public class Settings extends Activity {
50
51
 
51
52
  LocationTracker.getInstance().start(this);
52
53
 
53
- final List<Class<? extends BroadcastReceiver>> receiverClasses = new ArrayList<>();
54
- receiverClasses.add(WiFiConnectionSettingReceiver.class);
55
- receiverClasses.add(AnimationSettingReceiver.class);
56
- receiverClasses.add(DataConnectionSettingReceiver.class);
57
- receiverClasses.add(LocaleSettingReceiver.class);
58
- receiverClasses.add(LocationInfoReceiver.class);
59
- receiverClasses.add(ClipboardReceiver.class);
60
- receiverClasses.add(BluetoothConnectionSettingReceiver.class);
61
- receiverClasses.add(UnpairBluetoothDevicesReceiver.class);
62
- receiverClasses.add(NotificationsReceiver.class);
63
- receiverClasses.add(SmsReader.class);
64
- registerSettingsReceivers(receiverClasses);
54
+ registerSettingsReceivers(Arrays.asList(
55
+ WiFiConnectionSettingReceiver.class,
56
+ AnimationSettingReceiver.class,
57
+ DataConnectionSettingReceiver.class,
58
+ LocaleSettingReceiver.class,
59
+ LocationInfoReceiver.class,
60
+ ClipboardReceiver.class,
61
+ BluetoothConnectionSettingReceiver.class,
62
+ UnpairBluetoothDevicesReceiver.class,
63
+ NotificationsReceiver.class,
64
+ SmsReader.class,
65
+ MediaScannerReceiver.class
66
+ ));
65
67
 
66
68
  // https://developer.android.com/about/versions/oreo/background-location-limits
67
69
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -16,9 +16,11 @@
16
16
 
17
17
  package io.appium.settings.handlers;
18
18
 
19
+ import android.annotation.SuppressLint;
19
20
  import android.bluetooth.BluetoothAdapter;
20
21
  import android.content.Context;
21
22
 
23
+ @SuppressLint("MissingPermission")
22
24
  public class BluetoothConnectionSettingHandler extends AbstractSettingHandler {
23
25
 
24
26
  private BluetoothAdapter bluetoothAdapter;
@@ -0,0 +1,83 @@
1
+ /*
2
+ Copyright 2012-present Appium Committers
3
+ <p>
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+ <p>
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+ <p>
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ package io.appium.settings.location;
18
+
19
+ import android.content.Intent;
20
+ import android.location.Criteria;
21
+ import android.location.Location;
22
+ import android.os.Build;
23
+ import android.os.SystemClock;
24
+ import android.support.annotation.Nullable;
25
+ import android.util.Log;
26
+
27
+
28
+ public class LocationBuilder {
29
+
30
+ private static final String TAG = "MOCKED LOCATION BUILDER";
31
+ private static final String LONGITUDE_PARAMETER_KEY = "longitude";
32
+ private static final String LATITUDE_PARAMETER_KEY = "latitude";
33
+ private static final String ALTITUDE_PARAMETER_KEY = "altitude";
34
+ private static final String SPEED_PARAMETER_KEY = "speed";
35
+ private static final String BEARING_PARAMETER_KEY = "bearing";
36
+
37
+ @Nullable
38
+ private static Double extractParam(Intent intent, String paramKey) {
39
+ Double value = null;
40
+
41
+ try {
42
+ if (intent.hasExtra(paramKey)) {
43
+ value = Double.parseDouble(intent.getStringExtra(paramKey));
44
+ Log.i(TAG, String.format("Received parameter: %s, value: %s", paramKey, value));
45
+ }
46
+ } catch (NumberFormatException e) {
47
+ Log.e(TAG, String.format("%s should be a valid number. '%s' is given instead",
48
+ paramKey, intent.getStringExtra(paramKey)));
49
+ }
50
+ return value;
51
+ }
52
+
53
+ public static Location buildFromIntent(Intent intent, String providerName) {
54
+ Double longitude = extractParam(intent, LONGITUDE_PARAMETER_KEY);
55
+ Double latitude = extractParam(intent, LATITUDE_PARAMETER_KEY);
56
+ Double altitude = extractParam(intent, ALTITUDE_PARAMETER_KEY);
57
+ Double speed = extractParam(intent, SPEED_PARAMETER_KEY);
58
+ Double bearing = extractParam(intent, BEARING_PARAMETER_KEY);
59
+ Location location = new Location(providerName);
60
+ location.setAccuracy(Criteria.ACCURACY_FINE);
61
+ if (longitude != null) {
62
+ location.setLongitude(longitude);
63
+ }
64
+ if (latitude != null) {
65
+ location.setLatitude(latitude);
66
+ }
67
+ if (altitude != null) {
68
+ location.setAltitude(altitude);
69
+ }
70
+ if (speed != null) {
71
+ location.setSpeed(speed.floatValue());
72
+ }
73
+ if (bearing != null) {
74
+ location.setBearing(bearing.floatValue());
75
+ }
76
+
77
+ location.setTime(System.currentTimeMillis());
78
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
79
+ location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
80
+ }
81
+ return location;
82
+ }
83
+ }
@@ -45,7 +45,7 @@ public class LocationInfoReceiver extends BroadcastReceiver
45
45
  if (location != null) {
46
46
  setResultCode(Activity.RESULT_OK);
47
47
  // Decimal separator is a dot
48
- setResultData(String.format(Locale.US, "%.5f %.5f %.5f",
48
+ setResultData(String.format(Locale.US, "%.7f %.7f %.7f",
49
49
  location.getLatitude(), location.getLongitude(), location.getAltitude()));
50
50
  } else {
51
51
  setResultCode(Activity.RESULT_CANCELED);
@@ -0,0 +1,91 @@
1
+ /*
2
+ Copyright 2012-present Appium Committers
3
+ <p>
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+ <p>
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+ <p>
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ package io.appium.settings.receivers;
18
+
19
+ import android.app.Activity;
20
+ import android.content.BroadcastReceiver;
21
+ import android.content.Context;
22
+ import android.content.Intent;
23
+ import android.media.MediaScannerConnection;
24
+ import android.util.Log;
25
+
26
+ import java.io.File;
27
+ import java.util.ArrayList;
28
+ import java.util.Collections;
29
+ import java.util.List;
30
+
31
+ public class MediaScannerReceiver extends BroadcastReceiver
32
+ implements HasAction {
33
+ private static final String TAG = MediaScannerReceiver.class.getSimpleName();
34
+ private static final String ACTION = "io.appium.settings.scan_media";
35
+ private static final String PATH = "path";
36
+
37
+ private List<String> fetchFiles(File root) {
38
+ if (root.isFile()) {
39
+ return root.canRead()
40
+ ? Collections.singletonList(root.toString())
41
+ : Collections.emptyList();
42
+ }
43
+ File[] items = root.listFiles();
44
+ if (items == null) {
45
+ return Collections.emptyList();
46
+ }
47
+ List<String> filePaths = new ArrayList<>();
48
+ for (File item : items) {
49
+ filePaths.addAll(fetchFiles(item));
50
+ }
51
+ return filePaths;
52
+ }
53
+
54
+ /**
55
+ * Responds to broadcast requests like
56
+ * am broadcast -a io.appium.settings.scan_media -e path /sdcard/yolo
57
+ * by scanning all files/folders under the given path
58
+ */
59
+ @Override
60
+ public void onReceive(Context context, Intent intent) {
61
+ Log.d(TAG, "Scanning the requested media");
62
+ if (!intent.hasExtra(PATH)) {
63
+ Log.e(TAG, "No path has been provided");
64
+ setResultCode(Activity.RESULT_CANCELED);
65
+ setResultData("");
66
+ return;
67
+ }
68
+ File item = new File(intent.getStringExtra(PATH));
69
+ if (!item.exists()) {
70
+ Log.e(TAG, String.format("The item at '%s' does not exist", item.toString()));
71
+ setResultCode(Activity.RESULT_CANCELED);
72
+ setResultData("");
73
+ return;
74
+ }
75
+ List<String> filePaths = fetchFiles(item);
76
+ if (filePaths.isEmpty()) {
77
+ Log.i(TAG, String.format("Found no files to scan at '%s'", item.toString()));
78
+ } else {
79
+ MediaScannerConnection.scanFile(context, filePaths.toArray(new String[0]), null, null);
80
+ Log.i(TAG, String.format("Successfully scanned %s file(s) at '%s'",
81
+ filePaths.size(), item.toString()));
82
+ }
83
+ setResultCode(Activity.RESULT_OK);
84
+ setResultData("");
85
+ }
86
+
87
+ @Override
88
+ public String getAction() {
89
+ return ACTION;
90
+ }
91
+ }
@@ -58,7 +58,10 @@ public class SmsReader extends BroadcastReceiver implements HasAction {
58
58
  do {
59
59
  JSONObject item = new JSONObject();
60
60
  for (String[] entry : SMS_INFO_MAPPING) {
61
- item.put(entry[1], formatJsonNull(cursor.getString(cursor.getColumnIndex(entry[0]))));
61
+ int columnIndex = cursor.getColumnIndex(entry[0]);
62
+ if (columnIndex >= 0) {
63
+ item.put(entry[1], formatJsonNull(cursor.getString(columnIndex)));
64
+ }
62
65
  }
63
66
  items.put(item);
64
67
  } while (cursor.moveToNext() && items.length() < maxCount);
@@ -16,6 +16,7 @@
16
16
 
17
17
  package io.appium.settings.receivers;
18
18
 
19
+ import android.annotation.SuppressLint;
19
20
  import android.app.Activity;
20
21
  import android.bluetooth.BluetoothAdapter;
21
22
  import android.bluetooth.BluetoothDevice;
@@ -27,6 +28,7 @@ import android.util.Log;
27
28
  import java.lang.reflect.InvocationTargetException;
28
29
  import java.util.Set;
29
30
 
31
+ @SuppressLint("MissingPermission")
30
32
  public class UnpairBluetoothDevicesReceiver extends BroadcastReceiver implements HasAction {
31
33
  private static final String TAG = UnpairBluetoothDevicesReceiver.class.getSimpleName();
32
34
 
@@ -69,9 +71,10 @@ public class UnpairBluetoothDevicesReceiver extends BroadcastReceiver implements
69
71
  }
70
72
  }
71
73
 
72
- private void unpairBluetoothDevice(BluetoothDevice device) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
73
- //noinspection JavaReflectionMemberAccess,ConstantConditions,ConfusingArgumentToVarargsMethod
74
- device.getClass().getMethod("removeBond", null).invoke(device, null);
74
+ private void unpairBluetoothDevice(BluetoothDevice device)
75
+ throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
76
+ //noinspection JavaReflectionMemberAccess
77
+ device.getClass().getMethod("removeBond").invoke(device);
75
78
  }
76
79
 
77
80
  @Override
package/build.gradle CHANGED
@@ -5,7 +5,7 @@ buildscript {
5
5
  jcenter()
6
6
  }
7
7
  dependencies {
8
- classpath 'com.android.tools.build:gradle:3.5.3'
8
+ classpath 'com.android.tools.build:gradle:7.0.3'
9
9
  }
10
10
  }
11
11
 
@@ -1,6 +1,6 @@
1
- #Thu Dec 19 12:41:17 CET 2019
1
+ #Tue May 19 12:07:24 CEST 2020
2
2
  distributionBase=GRADLE_USER_HOME
3
- distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
4
3
  distributionPath=wrapper/dists
5
- zipStorePath=wrapper/dists
6
4
  zipStoreBase=GRADLE_USER_HOME
5
+ zipStorePath=wrapper/dists
6
+ distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-all.zip
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "io.appium.settings",
3
- "version": "3.2.0",
3
+ "version": "3.5.0",
4
4
  "description": "App for dealing with Android settings",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -1,52 +0,0 @@
1
- /*
2
- Copyright 2012-present Appium Committers
3
- <p>
4
- Licensed under the Apache License, Version 2.0 (the "License");
5
- you may not use this file except in compliance with the License.
6
- You may obtain a copy of the License at
7
- <p>
8
- http://www.apache.org/licenses/LICENSE-2.0
9
- <p>
10
- Unless required by applicable law or agreed to in writing, software
11
- distributed under the License is distributed on an "AS IS" BASIS,
12
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- See the License for the specific language governing permissions and
14
- limitations under the License.
15
- */
16
-
17
- package io.appium.settings.location;
18
-
19
- import android.location.Location;
20
- import android.os.Build;
21
- import android.os.SystemClock;
22
-
23
- public class LocationFactory {
24
-
25
- private double latitude;
26
- private double longitude;
27
- private double altitude;
28
-
29
-
30
- public synchronized Location createLocation(String providerName, float accuracy) {
31
- Location l = new Location(providerName);
32
- l.setAccuracy(accuracy);
33
-
34
- l.setLatitude(latitude);
35
- l.setLongitude(longitude);
36
- l.setAltitude(altitude);
37
- l.setSpeed(0);
38
- l.setBearing(0);
39
-
40
- l.setTime(System.currentTimeMillis());
41
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
42
- l.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
43
- }
44
- return l;
45
- }
46
-
47
- public synchronized void setLocation(double latitude, double longitude, double altitude) {
48
- this.latitude = latitude;
49
- this.longitude = longitude;
50
- this.altitude = altitude;
51
- }
52
- }