Update location service

This commit is contained in:
Marvin W 2022-01-18 18:45:51 +01:00
parent d593de25ef
commit 0bdcb1319b
No known key found for this signature in database
GPG Key ID: 072E9235DB996F2A
20 changed files with 688 additions and 156 deletions

View File

@ -5,7 +5,7 @@
buildscript {
ext.cronetVersion = '91.0.4472.120.1'
ext.nlpVersion = '2.0-alpha6'
ext.nlpVersion = '2.0-alpha7'
ext.safeParcelVersion = '1.7.0'
ext.wearableVersion = '0.1.1'

View File

@ -0,0 +1,3 @@
package com.google.android.gms.location;
parcelable DeviceOrientation;

View File

@ -0,0 +1,7 @@
package com.google.android.gms.location;
import com.google.android.gms.location.DeviceOrientation;
interface IDeviceOrientationListener {
void onDeviceOrientationChanged(in DeviceOrientation deviceOrientation);
}

View File

@ -0,0 +1,3 @@
package com.google.android.gms.location.internal;
parcelable DeviceOrientationRequestUpdateData;

View File

@ -5,8 +5,10 @@ import android.location.Location;
import android.os.Bundle;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.common.api.internal.IStatusCallback;
import com.google.android.gms.location.places.AutocompleteFilter;
import com.google.android.gms.location.places.internal.IPlacesCallbacks;
import com.google.android.gms.location.internal.DeviceOrientationRequestUpdateData;
import com.google.android.gms.location.internal.ISettingsCallbacks;
import com.google.android.gms.location.internal.LocationRequestInternal;
import com.google.android.gms.location.internal.LocationRequestUpdateData;
@ -36,17 +38,19 @@ interface IGoogleLocationManagerService {
void removeGeofencesByIntent(in PendingIntent pendingIntent, IGeofencerCallbacks callbacks, String packageName) = 1;
void removeGeofencesById(in String[] geofenceRequestIds, IGeofencerCallbacks callbacks, String packageName) = 2;
void removeAllGeofences(IGeofencerCallbacks callbacks, String packageName) = 3;
// void removeGeofences(in RemoveGeofencingRequest request, IGeofencerCallbacks callback) = 73;
void requestActivityUpdates(long detectionIntervalMillis, boolean alwaysTrue, in PendingIntent callbackIntent) = 4;
void removeActivityUpdates(in PendingIntent callbackIntent) = 5;
ActivityRecognitionResult getLastActivity(String packageName) = 63;
Status iglms65(in PendingIntent pendingIntent) = 64;
Status iglms66(in PendingIntent pendingIntent) = 65;
Status requestGestureUpdates(in GestureRequest request, in PendingIntent pendingIntent) = 59;
Status iglms61(in PendingIntent pendingIntent) = 60;
Location getLastLocation() = 6;
Location getLastLocationWithPackage(String packageName) = 20;
Location getLastLocationWith(String s) = 79;
void requestLocationUpdatesWithListener(in LocationRequest request, ILocationListener listener) = 7;
void requestLocationUpdatesWithPackage(in LocationRequest request, ILocationListener listener, String packageName) = 19;
void requestLocationUpdatesWithIntent(in LocationRequest request, in PendingIntent callbackIntent) = 8;
@ -55,34 +59,55 @@ interface IGoogleLocationManagerService {
void removeLocationUpdatesWithListener(ILocationListener listener) = 9;
void removeLocationUpdatesWithIntent(in PendingIntent callbackIntent) = 10;
void updateLocationRequest(in LocationRequestUpdateData locationRequestUpdateData) = 58;
//void flushLocations(IFusedLocationProviderCallback callback = 66;
// void flushLocations(IFusedLocationProviderCallback callback) = 66;
void setMockMode(boolean mockMode) = 11;
void setMockLocation(in Location mockLocation) = 12;
void injectLocation(in Location mockLocation, int injectionType) = 25;
Location getLastLocationWithPackage(String packageName) = 20;
void iglms26(in Location var1, int var2) = 25;
LocationAvailability getLocationAvailabilityWithPackage(String packageName) = 33;
IBinder iglms51() = 50;
// void requestSleepSegmentUpdates(in PendingIntent pendingIntent, in SleepSegmentRequest request, IStatusCallback callback) = 78;
void removeSleepSegmentUpdates(in PendingIntent pendingIntent, IStatusCallback callback) = 68;
void requestLocationSettingsDialog(in LocationSettingsRequest settingsRequest, ISettingsCallbacks callback, String packageName) = 62;
// void requestActivityTransitionUpdates(in ActivityTransitionRequest request, in PendingIntent pendingIntent, IStatusCallback callback) = 71;
void removeActivityTransitionUpdates(in PendingIntent pendingIntent, IStatusCallback callback) = 72;
void updateDeviceOrientationRequest(in DeviceOrientationRequestUpdateData request) = 74;
boolean setActivityRecognitionMode(int mode) = 76;
void iglms14(in LatLngBounds var1, int var2, in PlaceFilter var3, in PlacesParams var4, IPlacesCallbacks var5) = 13;
void iglms15(String var1, in PlacesParams var2, IPlacesCallbacks var3) = 14;
void iglms16(in LatLng var1, in PlaceFilter var2, in PlacesParams var3, IPlacesCallbacks var4) = 15;
void iglms17(in PlaceFilter var1, in PlacesParams var2, IPlacesCallbacks var3) = 16;
void iglms18(in PlaceRequest var1, in PlacesParams var2, in PendingIntent var3) = 17;
void iglms19(in PlacesParams var1, in PendingIntent var2) = 18;
void iglms25(in PlaceReport var1, in PlacesParams var2) = 24;
void iglms42(String var1, in PlacesParams var2, IPlacesCallbacks var3) = 41;
void iglms46(in UserAddedPlace var1, in PlacesParams var2, IPlacesCallbacks var3) = 45;
void iglms47(in LatLngBounds var1, int var2, String var3, in PlaceFilter var4, in PlacesParams var5, IPlacesCallbacks var6) = 46;
void iglms48(in NearbyAlertRequest var1, in PlacesParams var2, in PendingIntent var3) = 47;
void iglms49(in PlacesParams var1, in PendingIntent var2) = 48;
void iglms50(in UserDataType var1, in LatLngBounds var2, in List var3, in PlacesParams var4, IPlacesCallbacks var5) = 49;
IBinder iglms51() = 50;
IBinder iglms54() = 53;
void iglms55(String var1, in LatLngBounds var2, in AutocompleteFilter var3, in PlacesParams var4, IPlacesCallbacks var5) = 54;
void iglms58(in List var1, in PlacesParams var2, IPlacesCallbacks var3) = 57;
//void updateDeviceOrientationRequest(in DeviceOrientationRequestUpdateData request) = 74;
void iglms65(in PendingIntent pendingIntent, IStatusCallback callback) = 64;
void iglms66(in PendingIntent pendingIntent, IStatusCallback callback) = 65;
void iglms68(in PendingIntent pendingIntent, IStatusCallback callback) = 67;
// void iglms70(in ActivityRecognitionRequest request, in PendingIntent pendingIntent, IStatusCallback callback) = 69;
void iglms71(IStatusCallback callback) = 70;
void iglms76(in PendingIntent pendingIntent) = 75;
int iglms78() = 77;
}

View File

@ -0,0 +1,118 @@
/*
* SPDX-FileCopyrightText: 2022 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.location;
import org.microg.safeparcel.AutoSafeParcelable;
import java.util.Arrays;
public class DeviceOrientation extends AutoSafeParcelable {
@Field(1)
private float[] attitude = new float[4];
@Field(2)
private int attitudeConfidence = -1;
@Field(3)
private int magConfidence = -1;
@Field(4)
private float headingDegrees = Float.NaN;
@Field(5)
private float headingErrorDegrees = Float.NaN;
@Field(6)
private long elapsedRealtimeNanos = 0;
@Field(7)
private byte flags = 0;
@Field(8)
private float conservativeHeadingErrorVonMisesKappa = Float.NaN;
public float[] getAttitude() {
if ((flags & 0x10) != 0) return attitude;
return new float[4];
}
public void setAttitude(float[] attitude) {
if (attitude.length != 4) throw new IllegalArgumentException();
this.attitude = attitude;
flags = (byte) (flags | 0x10);
}
public int getAttitudeConfidence() {
if ((flags & 0x1) != 0) return attitudeConfidence;
return -1;
}
public void setAttitudeConfidence(int attitudeConfidence) {
this.attitudeConfidence = attitudeConfidence;
flags = (byte) (flags | 0x1);
}
public int getMagConfidence() {
if ((flags & 0x2) != 0) return magConfidence;
return -1;
}
public void setMagConfidence(int magConfidence) {
this.magConfidence = magConfidence;
flags = (byte) (flags | 0x2);
}
public float getHeadingDegrees() {
if ((flags & 0x4) != 0) return headingDegrees;
return Float.NaN;
}
public void setHeadingDegrees(float headingDegrees) {
this.headingDegrees = headingDegrees;
flags = (byte) (flags | 0x4);
}
public float getHeadingErrorDegrees() {
if ((flags & 0x8) != 0) return headingErrorDegrees;
return Float.NaN;
}
public void setHeadingErrorDegrees(float headingErrorDegrees) {
this.headingErrorDegrees = headingErrorDegrees;
flags = (byte) (flags | 0x8);
}
public float getConservativeHeadingErrorVonMisesKappa() {
if ((flags & 0x20) != 0) return conservativeHeadingErrorVonMisesKappa;
return Float.NaN;
}
public void setConservativeHeadingErrorVonMisesKappa(float conservativeHeadingErrorVonMisesKappa) {
this.conservativeHeadingErrorVonMisesKappa = conservativeHeadingErrorVonMisesKappa;
flags = (byte) (flags | 0x20);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("DeviceOrientation{");
if ((flags & 0x10) != 0)
sb.append("attitude=").append(Arrays.toString(attitude));
if ((flags & 0x1) != 0)
sb.append(", attitudeConfidence=").append(attitudeConfidence);
if ((flags & 0x2) != 0)
sb.append(", magConfidence=").append(magConfidence);
if ((flags & 0x4) != 0)
sb.append(", headingDegrees=").append(headingDegrees);
if ((flags & 0x8) != 0)
sb.append(", headingErrorDegrees=").append(headingErrorDegrees);
return "DeviceOrientation{" +
"attitude=" + Arrays.toString(attitude) +
", attitudeConfidence=" + attitudeConfidence +
", magConfidence=" + magConfidence +
", headingDegrees=" + headingDegrees +
", headingErrorDegrees=" + headingErrorDegrees +
", elapsedRealtimeNanos=" + elapsedRealtimeNanos +
", flags=" + flags +
", conservativeHeadingErrorVonMisesKappa=" + conservativeHeadingErrorVonMisesKappa +
'}';
}
public static final Creator<DeviceOrientation> CREATOR = new AutoCreator<DeviceOrientation>(DeviceOrientation.class);
}

View File

@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2022 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.location;
import android.os.SystemClock;
import org.microg.safeparcel.AutoSafeParcelable;
public class DeviceOrientationRequest extends AutoSafeParcelable {
@Field(1)
public boolean shouldUseMag;
@Field(2)
public long minimumSamplingPeriodMs;
@Field(3)
public float smallesAngleChangeRadians;
@Field(4)
public long expirationTime;
@Field(5)
public int numUpdates;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Request[shouldUseMag=").append(shouldUseMag);
sb.append(" minimumSamplingPeriod=").append(minimumSamplingPeriodMs).append("ms");
sb.append(" smallesAngleChange=").append(smallesAngleChangeRadians).append("rad");
if (expirationTime != Long.MAX_VALUE)
sb.append(" expireIn=").append(SystemClock.elapsedRealtime() - expirationTime).append("ms");
if (numUpdates != Integer.MAX_VALUE)
sb.append(" num=").append(numUpdates);
sb.append("]");
return sb.toString();
}
public static final Creator<DeviceOrientationRequest> CREATOR = new AutoCreator<DeviceOrientationRequest>(DeviceOrientationRequest.class);
}

View File

@ -17,8 +17,8 @@
package com.google.android.gms.location;
import android.os.SystemClock;
import org.microg.safeparcel.AutoSafeParcelable;
import org.microg.safeparcel.SafeParceled;
import java.util.Arrays;
@ -101,24 +101,26 @@ public class LocationRequest extends AutoSafeParcelable {
*/
public static final int PRIORITY_NO_POWER = 105;
@SafeParceled(1000)
@Field(1000)
private int versionCode = 1;
@SafeParceled(1)
@Field(1)
private int priority;
@SafeParceled(2)
@Field(2)
private long interval;
@SafeParceled(3)
@Field(3)
private long fastestInterval;
@SafeParceled(4)
@Field(4)
private boolean explicitFastestInterval;
@SafeParceled(5)
@Field(5)
private long expirationTime;
@SafeParceled(6)
@Field(6)
private int numUpdates;
@SafeParceled(7)
private float smallestDesplacement;
@SafeParceled(8)
@Field(7)
private float smallestDisplacement;
@Field(8)
private long maxWaitTime;
@Field(9)
private boolean waitForAccurateLocation;
public LocationRequest() {
this.priority = PRIORITY_BALANCED_POWER_ACCURACY;
@ -127,7 +129,7 @@ public class LocationRequest extends AutoSafeParcelable {
this.explicitFastestInterval = false;
this.expirationTime = Long.MAX_VALUE;
this.numUpdates = Integer.MAX_VALUE;
this.smallestDesplacement = 0;
this.smallestDisplacement = 0;
this.maxWaitTime = 0;
}
@ -176,6 +178,17 @@ public class LocationRequest extends AutoSafeParcelable {
return interval;
}
/**
* Gets the maximum wait time in milliseconds for location updates. If the wait time is smaller than the interval
* requested with {@link #setInterval(long)}, then the interval will be used instead.
*
* @return maximum wait time in milliseconds, inexact
* @see #setMaxWaitTime(long)
*/
public long getMaxWaitTime() {
return maxWaitTime;
}
/**
* Get the number of updates requested.
* <p/>
@ -204,8 +217,8 @@ public class LocationRequest extends AutoSafeParcelable {
*
* @return minimum displacement between location updates in meters
*/
public float getSmallestDesplacement() {
return smallestDesplacement;
public float getSmallestDisplacement() {
return smallestDisplacement;
}
@Override
@ -231,7 +244,7 @@ public class LocationRequest extends AutoSafeParcelable {
return false;
if (priority != that.priority)
return false;
if (Float.compare(that.smallestDesplacement, smallestDesplacement) != 0)
if (Float.compare(that.smallestDisplacement, smallestDisplacement) != 0)
return false;
return true;
@ -240,11 +253,28 @@ public class LocationRequest extends AutoSafeParcelable {
@Override
public int hashCode() {
return Arrays.hashCode(
new Object[] { priority, interval, fastestInterval, explicitFastestInterval,
explicitFastestInterval, numUpdates, smallestDesplacement, maxWaitTime
new Object[]{priority, interval, fastestInterval, explicitFastestInterval,
explicitFastestInterval, numUpdates, smallestDisplacement, maxWaitTime
});
}
/**
* Returns whether or not the fastest interval was explicitly specified for the location request.
*
* @return True if the fastest interval was explicitly set for the location request; false otherwise
*/
public boolean isFastestIntervalExplicitlySet() {
return explicitFastestInterval;
}
/**
* Returns whether the location services will wait a few seconds initially for accurate locations, if accurate
* locations cannot be computed on the device for {@link #PRIORITY_HIGH_ACCURACY} requests.
*/
public boolean isWaitForAccurateLocation() {
return waitForAccurateLocation;
}
/**
* Set the duration of this request, in milliseconds.
* <p/>
@ -312,6 +342,7 @@ public class LocationRequest extends AutoSafeParcelable {
if (millis < 0)
throw new IllegalArgumentException("interval must not be negative");
fastestInterval = millis;
explicitFastestInterval = true;
return this;
}
@ -348,6 +379,27 @@ public class LocationRequest extends AutoSafeParcelable {
return this;
}
/**
* Sets the maximum wait time in milliseconds for location updates.
* <p>
* If you pass a value at least 2x larger than the interval specified with {@link #setInterval(long)}, then
* location delivery may be delayed and multiple locations can be delivered at once. Locations are determined at
* the {@link #setInterval(long)} rate, but can be delivered in batch after the interval you set in this method.
* This can consume less battery and give more accurate locations, depending on the device's hardware capabilities.
* You should set this value to be as large as possible for your needs if you don't need immediate location
* delivery.
*
* @param millis desired maximum wait time in millisecond, inexact
* @return the same object, so that setters can be chained
* @throws IllegalArgumentException if the interval is less than zero
*/
public LocationRequest setMaxWaitTime(long millis) throws IllegalArgumentException {
if (millis < 0)
throw new IllegalArgumentException("interval must not be negative");
maxWaitTime = millis;
return this;
}
/**
* Set the number of location updates.
* <p/>
@ -417,22 +469,58 @@ public class LocationRequest extends AutoSafeParcelable {
public LocationRequest setSmallestDisplacement(float smallestDisplacementMeters) {
if (smallestDisplacementMeters < 0)
throw new IllegalArgumentException("smallestDisplacementMeters must not be negative");
this.smallestDesplacement = smallestDisplacementMeters;
this.smallestDisplacement = smallestDisplacementMeters;
return this;
}
/**
* Sets whether the client wants the locations services to wait a few seconds for accurate locations initially,
* when accurate locations could not be computed on the device immediately after {@link #PRIORITY_HIGH_ACCURACY}
* request is made. By default the location services will wait for accurate locations.
* <p>
* Note that this only applies to clients with {@link #PRIORITY_HIGH_ACCURACY} requests.
* <p>
* Also note this only applies to the initial locations computed right after the location request is added. The
* following inaccurate locations may still be delivered to the clients without delay.
*/
public LocationRequest setWaitForAccurateLocation(boolean waitForAccurateLocation) {
this.waitForAccurateLocation = waitForAccurateLocation;
return this;
}
private static String priorityToString(int priority) {
switch (priority) {
case PRIORITY_HIGH_ACCURACY:
return "PRIORITY_HIGH_ACCURACY";
case PRIORITY_BALANCED_POWER_ACCURACY:
return "PRIORITY_BALANCED_POWER_ACCURACY";
case PRIORITY_LOW_POWER:
return "PRIORITY_LOW_POWER";
case PRIORITY_NO_POWER:
return "PRIORITY_NO_POWER";
default:
return "???";
}
}
@Override
public String toString() {
return "LocationRequest{" +
"priority=" + priority +
", interval=" + interval +
", fastestInterval=" + fastestInterval +
", explicitFastestInterval=" + explicitFastestInterval +
", expirationTime=" + expirationTime +
", numUpdates=" + numUpdates +
", smallestDesplacement=" + smallestDesplacement +
", maxWaitTime=" + maxWaitTime +
'}';
StringBuilder sb = new StringBuilder();
sb.append("Request[");
sb.append(priorityToString(priority));
if (priority != PRIORITY_NO_POWER)
sb.append(" requested=").append(interval).append("ms");
sb.append(" fastest=").append(fastestInterval).append("ms");
if (maxWaitTime > interval)
sb.append(" maxWait=").append(maxWaitTime).append("ms");
if (smallestDisplacement > 0)
sb.append(" smallestDisplacement=").append(smallestDisplacement).append("m");
if (expirationTime != Long.MAX_VALUE)
sb.append(" expireIn=").append(SystemClock.elapsedRealtime() - expirationTime).append("ms");
if (numUpdates != Integer.MAX_VALUE)
sb.append(" num=").append(numUpdates);
sb.append("]");
return sb.toString();
}
public static final Creator<LocationRequest> CREATOR = new AutoCreator<LocationRequest>(LocationRequest.class);

View File

@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2022 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.location.internal;
import com.google.android.gms.location.DeviceOrientationRequest;
import org.microg.safeparcel.AutoSafeParcelable;
import java.util.List;
public class DeviceOrientationRequestInternal extends AutoSafeParcelable {
@Field(1)
public DeviceOrientationRequest request;
@Field(value = 2, subClass = ClientIdentity.class)
public List<ClientIdentity> clients;
@Field(3)
public String tag;
@Override
public String toString() {
return "DeviceOrientationRequestInternal{" +
"request=" + request +
", clients=" + clients +
", tag='" + tag + '\'' +
'}';
}
public static final Creator<DeviceOrientationRequestInternal> CREATOR = new AutoCreator<DeviceOrientationRequestInternal>(DeviceOrientationRequestInternal.class);
}

View File

@ -0,0 +1,39 @@
/*
* SPDX-FileCopyrightText: 2022 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.location.internal;
import com.google.android.gms.location.IDeviceOrientationListener;
import org.microg.safeparcel.AutoSafeParcelable;
public class DeviceOrientationRequestUpdateData extends AutoSafeParcelable {
public static final int REQUEST_UPDATES = 1;
public static final int REMOVE_UPDATES = 2;
@Field(1)
public int opCode;
@Field(2)
public DeviceOrientationRequestInternal request;
@Field(3)
public IDeviceOrientationListener listener;
@Field(4)
public IFusedLocationProviderCallback fusedLocationProviderCallback;
@Override
public String toString() {
return "DeviceOrientationRequestUpdateData{" +
"opCode=" + opCode +
", request=" + request +
", listener=" + (listener != null ? listener.asBinder() : null) +
", fusedLocationProviderCallback=" + (fusedLocationProviderCallback != null ? fusedLocationProviderCallback.asBinder() : null) +
'}';
}
public static final Creator<DeviceOrientationRequestUpdateData> CREATOR = new AutoCreator<DeviceOrientationRequestUpdateData>(DeviceOrientationRequestUpdateData.class);
}

View File

@ -25,39 +25,48 @@ import java.util.List;
public class LocationRequestInternal extends AutoSafeParcelable {
@SafeParceled(1000)
@Field(1000)
private int versionCode = 1;
@SafeParceled(1)
@Field(1)
public LocationRequest request;
@SafeParceled(2)
@Field(2) @Deprecated
public boolean requestNlpDebugInfo;
@SafeParceled(3)
@Field(3) @Deprecated
public boolean restorePendingIntentListeners;
@SafeParceled(4)
@Field(4) @Deprecated
public boolean triggerUpdate;
@SafeParceled(value = 5, subClass = ClientIdentity.class)
@Field(value = 5, subClass = ClientIdentity.class)
public List<ClientIdentity> clients;
@SafeParceled(6)
@Field(6)
public String tag;
@SafeParceled(7)
@Field(7)
public boolean hideFromAppOps;
@SafeParceled(8)
@Field(8)
public boolean forceCoarseLocation;
@SafeParceled(9)
@Field(9)
public boolean exemptFromThrottle;
@SafeParceled(10)
@Field(10)
public String moduleId;
@Field(11)
public boolean locationSettingsIgnored;
@Field(12)
public boolean inaccurateLocationsDelayed;
@Field(13)
public String contextAttributeTag;
@Override
public String toString() {
return "LocationRequestInternal{" +
@ -71,6 +80,9 @@ public class LocationRequestInternal extends AutoSafeParcelable {
", forceCoarseLocation=" + forceCoarseLocation +
", exemptFromThrottle=" + exemptFromThrottle +
", moduleId=" + moduleId +
", locationSettingsIgnored=" + locationSettingsIgnored +
", inaccurateLocationsDelayed=" + inaccurateLocationsDelayed +
", contextAttributeTag=" + contextAttributeTag +
'}';
}

View File

@ -8,19 +8,16 @@ apply plugin: 'kotlin-android'
dependencies {
api project(':play-services-location-api')
implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion"
implementation project(':play-services-base-core')
implementation "org.microg.nlp:geocode-v1:$nlpVersion"
implementation "org.microg.nlp:location-v2:$nlpVersion"
implementation "org.microg.nlp:location-v3:$nlpVersion"
implementation "org.microg.nlp:service:$nlpVersion"
runtimeOnly "org.microg.nlp:service:$nlpVersion"
api "org.microg.nlp:client:$nlpVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion"
api "org.microg.nlp:client:$nlpVersion"
api "org.microg.nlp:ui:$nlpVersion"
implementation "androidx.lifecycle:lifecycle-service:$lifecycleVersion"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"
}
android {

View File

@ -27,6 +27,7 @@ import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.ILocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.internal.FusedLocationProviderResult;
@ -35,6 +36,7 @@ import com.google.android.gms.location.internal.LocationRequestUpdateData;
import org.microg.gms.common.PackageUtils;
import org.microg.gms.common.Utils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@ -45,8 +47,10 @@ import static android.location.LocationManager.GPS_PROVIDER;
import static com.google.android.gms.location.LocationRequest.PRIORITY_HIGH_ACCURACY;
import static com.google.android.gms.location.LocationRequest.PRIORITY_NO_POWER;
import androidx.lifecycle.Lifecycle;
public class GoogleLocationManager implements LocationChangeListener {
private static final String TAG = "GmsLocManager";
private static final String TAG = "LocationManager";
private static final String MOCK_PROVIDER = "mock";
private static final long VERIFY_CURRENT_REQUESTS_INTERVAL_MS = 5000; // 5 seconds
private static final long SWITCH_ON_FRESHNESS_CLIFF_MS = 30000; // 30 seconds
@ -60,7 +64,8 @@ public class GoogleLocationManager implements LocationChangeListener {
private final MockLocationProvider mockProvider;
private final List<LocationRequestHelper> currentRequests = new ArrayList<LocationRequestHelper>();
public GoogleLocationManager(Context context) {
public GoogleLocationManager(Context context, Lifecycle lifecycle) {
long callingIdentity = Binder.clearCallingIdentity();
this.context = context;
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
if (Utils.hasSelfPermissionOrNotify(context, Manifest.permission.ACCESS_FINE_LOCATION)) {
@ -69,12 +74,13 @@ public class GoogleLocationManager implements LocationChangeListener {
this.gpsProvider = null;
}
if (Utils.hasSelfPermissionOrNotify(context, Manifest.permission.ACCESS_COARSE_LOCATION)) {
this.networkProvider = new UnifiedLocationProvider(context, this);
this.networkProvider = new UnifiedLocationProvider(context, this, lifecycle);
} else {
this.networkProvider = null;
}
mockProvider = new MockLocationProvider(this);
handler = new Handler(Looper.getMainLooper());
Binder.restoreCallingIdentity(callingIdentity);
}
public void invokeOnceReady(Runnable runnable) {
@ -140,19 +146,29 @@ public class GoogleLocationManager implements LocationChangeListener {
}
}
if (old != null) {
Log.d(TAG, "Removing replaced location request: " + old);
currentRequests.remove(old);
}
currentRequests.add(request);
if (gpsProvider != null && request.hasFinePermission() && request.locationRequest.getPriority() == PRIORITY_HIGH_ACCURACY) {
Log.d(TAG, "Registering request with high accuracy location provider");
gpsProvider.addRequest(request);
} else if (gpsProvider != null && old != null) {
Log.d(TAG, "Unregistering request with high accuracy location provider");
gpsProvider.removeRequest(old);
} else {
Log.w(TAG, "Not providing high accuracy location: missing permission");
}
if (networkProvider != null && request.hasCoarsePermission() && request.locationRequest.getPriority() != PRIORITY_NO_POWER) {
Log.d(TAG, "Registering request with low accuracy location provider");
networkProvider.addRequest(request);
} else if (networkProvider != null && old != null) {
Log.d(TAG, "Unregistering request with low accuracy location provider");
networkProvider.removeRequest(old);
} else {
Log.w(TAG, "Not providing low accuracy location: missing permission");
}
handler.postDelayed(this::onLocationChanged, request.locationRequest.getFastestInterval());
}
public void requestLocationUpdates(LocationRequest request, ILocationListener listener, String packageName) {
@ -188,28 +204,43 @@ public class GoogleLocationManager implements LocationChangeListener {
}
public void updateLocationRequest(LocationRequestUpdateData data) {
String packageName = PackageUtils.getCallingPackage(context);
if (data.pendingIntent != null)
packageName = PackageUtils.packageFromPendingIntent(data.pendingIntent);
if (data.opCode == LocationRequestUpdateData.REQUEST_UPDATES) {
requestLocationUpdates(new LocationRequestHelper(context, packageName, Binder.getCallingUid(), data));
} else if (data.opCode == LocationRequestUpdateData.REMOVE_UPDATES) {
for (int i = 0; i < currentRequests.size(); i++) {
if (currentRequests.get(i).respondsTo(data.listener)
|| currentRequests.get(i).respondsTo(data.pendingIntent)
|| currentRequests.get(i).respondsTo(data.callback)) {
removeLocationUpdates(currentRequests.get(i));
i--;
try {
Log.d(TAG, "updateLocationRequest: " + data);
String packageName = PackageUtils.getCallingPackage(context);
if (data.pendingIntent != null)
packageName = PackageUtils.packageFromPendingIntent(data.pendingIntent);
Log.d(TAG, "Using source package: " + packageName);
if (data.opCode == LocationRequestUpdateData.REQUEST_UPDATES) {
requestLocationUpdates(new LocationRequestHelper(context, packageName, Binder.getCallingUid(), data));
} else if (data.opCode == LocationRequestUpdateData.REMOVE_UPDATES) {
for (int i = 0; i < currentRequests.size(); i++) {
if (currentRequests.get(i).respondsTo(data.listener)
|| currentRequests.get(i).respondsTo(data.pendingIntent)
|| currentRequests.get(i).respondsTo(data.callback)) {
removeLocationUpdates(currentRequests.get(i));
i--;
}
}
}
Log.d(TAG, "Updated current requests, verifying");
verifyCurrentRequests();
if (data.fusedLocationProviderCallback != null) {
try {
Log.d(TAG, "Send success result to " + packageName);
data.fusedLocationProviderCallback.onFusedLocationProviderResult(FusedLocationProviderResult.SUCCESS);
} catch (RemoteException ignored) {
}
}
} catch (Exception e) {
Log.w(TAG, "Exception in updateLocationRequest", e);
if (data.fusedLocationProviderCallback != null) {
try {
Log.d(TAG, "Send internal error result");
data.fusedLocationProviderCallback.onFusedLocationProviderResult(FusedLocationProviderResult.create(Status.INTERNAL_ERROR));
} catch (RemoteException ignored) {
}
}
}
if (data.fusedLocationProviderCallback != null) {
try {
data.fusedLocationProviderCallback.onFusedLocationProviderResult(FusedLocationProviderResult.SUCCESS);
} catch (RemoteException ignored) {
}
}
verifyCurrentRequests();
}
public void setMockMode(boolean mockMode) {
@ -250,4 +281,13 @@ public class GoogleLocationManager implements LocationChangeListener {
}
}
}
public void dump(PrintWriter writer) {
if (gpsProvider != null) gpsProvider.dump(writer);
if (networkProvider != null) networkProvider.dump(writer);
writer.println(currentRequests.size() + " requests:");
for (LocationRequestHelper request : currentRequests) {
writer.println(" " + request.id + " package=" + request.packageName + " interval=" + request.locationRequest.getInterval() + " smallestDisplacement=" + request.locationRequest.getSmallestDisplacement());
}
}
}

View File

@ -27,11 +27,14 @@ import com.google.android.gms.common.internal.IGmsCallbacks;
import org.microg.gms.BaseService;
import org.microg.gms.common.GmsService;
import java.io.FileDescriptor;
import java.io.PrintWriter;
public class GoogleLocationManagerService extends BaseService {
private GoogleLocationManagerServiceImpl impl = new GoogleLocationManagerServiceImpl(this);
private GoogleLocationManagerServiceImpl impl = new GoogleLocationManagerServiceImpl(this, getLifecycle());
public GoogleLocationManagerService() {
super("GmsLocManagerSvc", GmsService.LOCATION_MANAGER, GmsService.GEODATA, GmsService.PLACE_DETECTION);
super("LocationManager", GmsService.LOCATION_MANAGER, GmsService.GEODATA, GmsService.PLACE_DETECTION);
}
@Override
@ -49,4 +52,9 @@ public class GoogleLocationManagerService extends BaseService {
}
});
}
@Override
protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
impl.getLocationManager().dump(writer);
}
}

View File

@ -20,12 +20,19 @@ import android.app.PendingIntent;
import android.content.Context;
import android.location.Location;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.common.api.internal.IStatusCallback;
import com.google.android.gms.location.ActivityRecognitionResult;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.GestureRequest;
@ -35,6 +42,7 @@ import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationSettingsRequest;
import com.google.android.gms.location.LocationSettingsResult;
import com.google.android.gms.location.LocationSettingsStates;
import com.google.android.gms.location.internal.DeviceOrientationRequestUpdateData;
import com.google.android.gms.location.internal.IGeofencerCallbacks;
import com.google.android.gms.location.internal.IGoogleLocationManagerService;
import com.google.android.gms.location.internal.ISettingsCallbacks;
@ -58,23 +66,31 @@ import org.microg.gms.common.PackageUtils;
import java.util.Arrays;
import java.util.List;
public class GoogleLocationManagerServiceImpl extends IGoogleLocationManagerService.Stub {
public class GoogleLocationManagerServiceImpl extends IGoogleLocationManagerService.Stub implements LifecycleOwner {
private static final String TAG = "GmsLocManagerSvcImpl";
private final Context context;
private final Lifecycle lifecycle;
private GoogleLocationManager locationManager;
public GoogleLocationManagerServiceImpl(Context context) {
public GoogleLocationManagerServiceImpl(Context context, Lifecycle lifecycle) {
this.context = context;
this.lifecycle = lifecycle;
}
@NonNull
@Override
public Lifecycle getLifecycle() {
return lifecycle;
}
public void invokeOnceReady(Runnable runnable) {
getLocationManager().invokeOnceReady(runnable);
}
private GoogleLocationManager getLocationManager() {
public synchronized GoogleLocationManager getLocationManager() {
if (locationManager == null)
locationManager = new GoogleLocationManager(context);
locationManager = new GoogleLocationManager(context, lifecycle);
return locationManager;
}
@ -123,18 +139,6 @@ public class GoogleLocationManagerServiceImpl extends IGoogleLocationManagerServ
return null;
}
@Override
public Status iglms65(PendingIntent pendingIntent) throws RemoteException {
Log.d(TAG, "iglms65");
return null;
}
@Override
public Status iglms66(PendingIntent pendingIntent) throws RemoteException {
Log.d(TAG, "iglms66");
return null;
}
@Override
public Status requestGestureUpdates(GestureRequest request, PendingIntent pendingIntent) throws RemoteException {
Log.d(TAG, "requestGestureUpdates");
@ -199,6 +203,11 @@ public class GoogleLocationManagerServiceImpl extends IGoogleLocationManagerServ
getLocationManager().setMockLocation(mockLocation);
}
@Override
public void injectLocation(Location mockLocation, int injectionType) throws RemoteException {
Log.d(TAG, "injectLocation[" + injectionType + "]: " + mockLocation);
}
@Override
public void iglms14(LatLngBounds var1, int var2, PlaceFilter var3, PlacesParams var4,
IPlacesCallbacks var5) throws RemoteException {
@ -250,13 +259,14 @@ public class GoogleLocationManagerServiceImpl extends IGoogleLocationManagerServ
}
@Override
public void iglms25(PlaceReport var1, PlacesParams var2) throws RemoteException {
Log.d(TAG, "iglms25: " + var1);
public Location getLastLocationWith(String s) throws RemoteException {
Log.d(TAG, "getLastLocationWith: " + s);
return getLastLocation();
}
@Override
public void iglms26(Location var1, int var2) throws RemoteException {
Log.d(TAG, "iglms26: " + var1);
public void iglms25(PlaceReport var1, PlacesParams var2) throws RemoteException {
Log.d(TAG, "iglms25: " + var1);
}
@Override
@ -266,6 +276,11 @@ public class GoogleLocationManagerServiceImpl extends IGoogleLocationManagerServ
return new LocationAvailability();
}
@Override
public void removeSleepSegmentUpdates(PendingIntent pendingIntent, IStatusCallback callback) throws RemoteException {
Log.d(TAG, "removeSleepSegmentUpdates");
}
@Override
public void iglms42(String var1, PlacesParams var2, IPlacesCallbacks var3)
throws RemoteException {
@ -311,7 +326,29 @@ public class GoogleLocationManagerServiceImpl extends IGoogleLocationManagerServ
public void requestLocationSettingsDialog(LocationSettingsRequest settingsRequest, ISettingsCallbacks callback, String packageName) throws RemoteException {
Log.d(TAG, "requestLocationSettingsDialog: " + settingsRequest);
PackageUtils.getAndCheckCallingPackage(context, packageName);
callback.onLocationSettingsResult(new LocationSettingsResult(new LocationSettingsStates(true, true, false, true, true, false), Status.SUCCESS));
(new Handler(Looper.getMainLooper())).post(() -> {
try {
callback.onLocationSettingsResult(new LocationSettingsResult(new LocationSettingsStates(true, true, true, true, true, true), Status.SUCCESS));
} catch (RemoteException e) {
Log.w(TAG, e);
}
});
}
@Override
public void removeActivityTransitionUpdates(PendingIntent pendingIntent, IStatusCallback callback) throws RemoteException {
Log.d(TAG, "removeActivityTransitionUpdates");
}
@Override
public void updateDeviceOrientationRequest(DeviceOrientationRequestUpdateData request) throws RemoteException {
Log.d(TAG, "updateDeviceOrientationRequest: " + request);
}
@Override
public boolean setActivityRecognitionMode(int mode) throws RemoteException {
Log.d(TAG, "setActivityRecognitionMode: " + mode);
return false;
}
@Override
@ -352,6 +389,37 @@ public class GoogleLocationManagerServiceImpl extends IGoogleLocationManagerServ
Log.d(TAG, "iglms58: " + var1);
}
@Override
public void iglms65(PendingIntent pendingIntent, IStatusCallback callback) throws RemoteException {
Log.d(TAG, "iglms65");
}
@Override
public void iglms66(PendingIntent pendingIntent, IStatusCallback callback) throws RemoteException {
Log.d(TAG, "iglms66");
}
@Override
public void iglms68(PendingIntent pendingIntent, IStatusCallback callback) throws RemoteException {
Log.d(TAG, "iglms68");
}
@Override
public void iglms71(IStatusCallback callback) throws RemoteException {
Log.d(TAG, "iglms71");
}
@Override
public void iglms76(PendingIntent pendingIntent) throws RemoteException {
Log.d(TAG, "iglms76");
}
@Override
public int iglms78() throws RemoteException {
Log.d(TAG, "iglms78");
return 0;
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
if (super.onTransact(code, data, reply, flags)) return true;

View File

@ -17,7 +17,6 @@
package org.microg.gms.location;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.Context;
@ -35,12 +34,9 @@ import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.internal.LocationRequestUpdateData;
import org.microg.gms.common.PackageUtils;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION;
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
@ -56,6 +52,7 @@ public class LocationRequestHelper {
public ILocationListener listener;
public PendingIntent pendingIntent;
public ILocationCallback callback;
public String id = UUID.randomUUID().toString();
private Location lastReport;
private int numReports = 0;
@ -117,10 +114,13 @@ public class LocationRequestHelper {
if (location == null) return true;
if (!isActive()) return false;
if (lastReport != null) {
if (location.equals(lastReport)) {
return true;
}
if (location.getTime() - lastReport.getTime() < locationRequest.getFastestInterval()) {
return true;
}
if (location.distanceTo(lastReport) < locationRequest.getSmallestDesplacement()) {
if (location.distanceTo(lastReport) < locationRequest.getSmallestDisplacement()) {
return true;
}
}

View File

@ -23,6 +23,7 @@ import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
@ -44,7 +45,12 @@ public class RealLocationProvider {
private LocationListener listener = new LocationListener() {
@Override
public void onLocationChanged(Location location) {
lastLocation = location;
lastLocation = new Location(location);
try {
lastLocation.getExtras().keySet(); // call to unparcel()
} catch (Exception e) {
// Sometimes we need to define the correct ClassLoader before unparcel(). Ignore those.
}
changeListener.onLocationChanged();
}
@ -121,7 +127,7 @@ public class RealLocationProvider {
StringBuilder sb = new StringBuilder();
for (LocationRequestHelper request : requests) {
minTime = Math.min(request.locationRequest.getInterval(), minTime);
minDistance = Math.min(request.locationRequest.getSmallestDesplacement(), minDistance);
minDistance = Math.min(request.locationRequest.getSmallestDisplacement(), minDistance);
if (sb.length() != 0) sb.append(", ");
sb.append(request.packageName).append(":").append(request.locationRequest.getInterval()).append("ms");
}
@ -146,4 +152,16 @@ public class RealLocationProvider {
connectedMinDistance = minDistance;
}
}
public void dump(PrintWriter writer) {
if (writer != null) {
writer.println(name + " provider:");
writer.println(" last location: " + lastLocation);
writer.println(" active: " + connected.get());
if (connected.get()) {
writer.println(" interval: " + connectedMinTime);
writer.println(" distance: " + connectedMinDistance);
}
}
}
}

View File

@ -17,6 +17,7 @@
package org.microg.gms.location;
import android.accounts.Account;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
@ -58,4 +59,15 @@ public class ReportingServiceImpl extends IReportingService.Stub {
Log.d(TAG, "reportDeviceAtPlace");
return 0;
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
if (super.onTransact(code, data, reply, flags)) {
return true;
}
Log.d(TAG, "onTransact [unknown]: " + code + ", " + data + ", " + flags);
return false;
}
}

View File

@ -2,32 +2,54 @@ package org.microg.gms.location
import android.content.Context
import android.location.Location
import android.os.Bundle
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.microg.nlp.client.UnifiedLocationClient
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.microg.nlp.client.LocationClient
import org.microg.nlp.service.api.Constants
import org.microg.nlp.service.api.ILocationListener
import org.microg.nlp.service.api.LocationRequest
import java.io.PrintWriter
import java.lang.Exception
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.collections.ArrayList
class UnifiedLocationProvider(context: Context?, changeListener: LocationChangeListener) {
private val client: UnifiedLocationClient
private var connectedMinTime: Long = 0
class UnifiedLocationProvider(private val context: Context, private val changeListener: LocationChangeListener, private val lifecycle: Lifecycle): LifecycleOwner {
private val client: LocationClient = LocationClient(context, lifecycle)
private var lastLocation: Location? = null
private val connected = AtomicBoolean(false)
private val changeListener: LocationChangeListener
private val requests: MutableList<LocationRequestHelper> = ArrayList()
private val listener: UnifiedLocationClient.LocationListener = object : UnifiedLocationClient.LocationListener {
override fun onLocation(location: Location) {
lastLocation = location
changeListener.onLocationChanged()
private val activeRequestIds = hashSetOf<String>()
private val activeRequestMutex = Mutex(false)
private val listener: ILocationListener = object : ILocationListener.Stub() {
override fun onLocation(statusCode: Int, location: Location?) {
if (statusCode == Constants.STATUS_OK && location != null) {
lastLocation = Location(location)
try {
for (key in lastLocation?.extras?.keySet()?.toList().orEmpty()) {
if (key?.startsWith("org.microg.nlp.") == true) {
lastLocation?.extras?.remove(key)
}
}
} catch (e:Exception){
// Sometimes we need to define the correct ClassLoader before unparcel(). Ignore those.
}
changeListener.onLocationChanged()
}
}
}
private var ready = false
private val invokeOnceReady = hashSetOf<Runnable>()
init {
updateLastLocation()
}
private fun updateLastLocation() {
GlobalScope.launch(Dispatchers.Main) {
lifecycleScope.launchWhenStarted {
Log.d(TAG, "unified network: requesting last location")
val lastLocation = client.getLastLocation()
Log.d(TAG, "unified network: got last location: $lastLocation")
@ -78,42 +100,40 @@ class UnifiedLocationProvider(context: Context?, changeListener: LocationChangeL
@Synchronized
private fun updateConnection() {
if (connected.get() && requests.isEmpty()) {
Log.d(TAG, "unified network: no longer requesting location update")
client.removeLocationUpdates(listener)
connected.set(false)
} else if (requests.isNotEmpty()) {
var minTime = Long.MAX_VALUE
var maxUpdates = Int.MAX_VALUE
val sb = StringBuilder()
var opPackageName: String? = null
for (request in requests) {
if (request.locationRequest.interval < minTime) {
opPackageName = request.packageName
minTime = request.locationRequest.interval
maxUpdates = request.locationRequest.numUpdates
lifecycleScope.launchWhenStarted {
activeRequestMutex.withLock {
if (activeRequestIds.isNotEmpty() && requests.isEmpty()) {
Log.d(TAG, "unified network: no longer requesting location update")
for (id in activeRequestIds) {
client.cancelLocationRequestById(id)
}
activeRequestIds.clear()
} else if (requests.isNotEmpty()) {
val requests = ArrayList(requests).filter { it.isActive }
for (id in activeRequestIds.filter { id -> requests.none { it.id == id } }) {
client.cancelLocationRequestById(id)
}
for (request in requests.filter { it.id !in activeRequestIds }) {
client.updateLocationRequest(LocationRequest(listener, request.locationRequest.interval, request.locationRequest.numUpdates, request.id), Bundle().apply {
putString("packageName", request.packageName)
putString("source", "GoogleLocationManager")
})
activeRequestIds.add(request.id)
}
}
if (sb.isNotEmpty()) sb.append(", ")
sb.append("${request.packageName}:${request.locationRequest.interval}ms")
}
client.opPackageName = opPackageName
if (minTime <= 0) {
client.forceNextUpdate = true
}
Log.d(TAG, "unified network: requesting location updates with interval ${minTime}ms ($sb)")
client.requestLocationUpdates(listener, minTime, maxUpdates)
connected.set(true)
connectedMinTime = minTime
}
}
override fun getLifecycle(): Lifecycle = lifecycle
fun dump(writer: PrintWriter) {
writer.println("network provider (via direct client):")
writer.println(" last location: $lastLocation")
writer.println(" ready: $ready")
}
companion object {
const val TAG = "GmsLocProviderU"
}
init {
client = UnifiedLocationClient[context!!]
this.changeListener = changeListener
updateLastLocation()
}
}

View File

@ -135,7 +135,7 @@ public class NativeLocationClientImpl {
i.putExtras(bundle);
pendingCount.put(pendingIntent, request.getNumUpdates());
nativePendingMap.put(pendingIntent, PendingIntent.getActivity(context, 0, i, 0));
locationManager.requestLocationUpdates(request.getInterval(), request.getSmallestDesplacement(),
locationManager.requestLocationUpdates(request.getInterval(), request.getSmallestDisplacement(),
makeNativeCriteria(request), nativePendingMap.get(pendingIntent));
}
@ -147,7 +147,7 @@ public class NativeLocationClientImpl {
}
nativeListenerMap.put(listener, new NativeListener(listener, request.getNumUpdates()));
locationManager.requestLocationUpdates(request.getInterval(),
request.getSmallestDesplacement(), makeNativeCriteria(request),
request.getSmallestDisplacement(), makeNativeCriteria(request),
nativeListenerMap.get(listener), looper);
}