diff --git a/build.gradle b/build.gradle index 14a8ecde..e873b2bb 100644 --- a/build.gradle +++ b/build.gradle @@ -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' diff --git a/play-services-location-api/src/main/aidl/com/google/android/gms/location/DeviceOrientation.aidl b/play-services-location-api/src/main/aidl/com/google/android/gms/location/DeviceOrientation.aidl new file mode 100644 index 00000000..3055c41b --- /dev/null +++ b/play-services-location-api/src/main/aidl/com/google/android/gms/location/DeviceOrientation.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.location; + +parcelable DeviceOrientation; diff --git a/play-services-location-api/src/main/aidl/com/google/android/gms/location/IDeviceOrientationListener.aidl b/play-services-location-api/src/main/aidl/com/google/android/gms/location/IDeviceOrientationListener.aidl new file mode 100644 index 00000000..e3d3e6f0 --- /dev/null +++ b/play-services-location-api/src/main/aidl/com/google/android/gms/location/IDeviceOrientationListener.aidl @@ -0,0 +1,7 @@ +package com.google.android.gms.location; + +import com.google.android.gms.location.DeviceOrientation; + +interface IDeviceOrientationListener { + void onDeviceOrientationChanged(in DeviceOrientation deviceOrientation); +} diff --git a/play-services-location-api/src/main/aidl/com/google/android/gms/location/internal/DeviceOrientationRequestUpdateData.aidl b/play-services-location-api/src/main/aidl/com/google/android/gms/location/internal/DeviceOrientationRequestUpdateData.aidl new file mode 100644 index 00000000..e92b0f0d --- /dev/null +++ b/play-services-location-api/src/main/aidl/com/google/android/gms/location/internal/DeviceOrientationRequestUpdateData.aidl @@ -0,0 +1,3 @@ +package com.google.android.gms.location.internal; + +parcelable DeviceOrientationRequestUpdateData; diff --git a/play-services-location-api/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl b/play-services-location-api/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl index 8e78a899..19f9be10 100644 --- a/play-services-location-api/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl +++ b/play-services-location-api/src/main/aidl/com/google/android/gms/location/internal/IGoogleLocationManagerService.aidl @@ -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; } diff --git a/play-services-location-api/src/main/java/com/google/android/gms/location/DeviceOrientation.java b/play-services-location-api/src/main/java/com/google/android/gms/location/DeviceOrientation.java new file mode 100644 index 00000000..61373df0 --- /dev/null +++ b/play-services-location-api/src/main/java/com/google/android/gms/location/DeviceOrientation.java @@ -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 CREATOR = new AutoCreator(DeviceOrientation.class); +} diff --git a/play-services-location-api/src/main/java/com/google/android/gms/location/DeviceOrientationRequest.java b/play-services-location-api/src/main/java/com/google/android/gms/location/DeviceOrientationRequest.java new file mode 100644 index 00000000..14ce93c1 --- /dev/null +++ b/play-services-location-api/src/main/java/com/google/android/gms/location/DeviceOrientationRequest.java @@ -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 CREATOR = new AutoCreator(DeviceOrientationRequest.class); +} diff --git a/play-services-location-api/src/main/java/com/google/android/gms/location/LocationRequest.java b/play-services-location-api/src/main/java/com/google/android/gms/location/LocationRequest.java index 15d159e8..085886c0 100644 --- a/play-services-location-api/src/main/java/com/google/android/gms/location/LocationRequest.java +++ b/play-services-location-api/src/main/java/com/google/android/gms/location/LocationRequest.java @@ -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. *

@@ -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. *

@@ -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. + *

+ * 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. *

@@ -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. + *

+ * Note that this only applies to clients with {@link #PRIORITY_HIGH_ACCURACY} requests. + *

+ * 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 CREATOR = new AutoCreator(LocationRequest.class); diff --git a/play-services-location-api/src/main/java/com/google/android/gms/location/internal/DeviceOrientationRequestInternal.java b/play-services-location-api/src/main/java/com/google/android/gms/location/internal/DeviceOrientationRequestInternal.java new file mode 100644 index 00000000..5b66feaa --- /dev/null +++ b/play-services-location-api/src/main/java/com/google/android/gms/location/internal/DeviceOrientationRequestInternal.java @@ -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 clients; + + @Field(3) + public String tag; + + @Override + public String toString() { + return "DeviceOrientationRequestInternal{" + + "request=" + request + + ", clients=" + clients + + ", tag='" + tag + '\'' + + '}'; + } + + public static final Creator CREATOR = new AutoCreator(DeviceOrientationRequestInternal.class); +} diff --git a/play-services-location-api/src/main/java/com/google/android/gms/location/internal/DeviceOrientationRequestUpdateData.java b/play-services-location-api/src/main/java/com/google/android/gms/location/internal/DeviceOrientationRequestUpdateData.java new file mode 100644 index 00000000..5a2e759e --- /dev/null +++ b/play-services-location-api/src/main/java/com/google/android/gms/location/internal/DeviceOrientationRequestUpdateData.java @@ -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 CREATOR = new AutoCreator(DeviceOrientationRequestUpdateData.class); +} diff --git a/play-services-location-api/src/main/java/com/google/android/gms/location/internal/LocationRequestInternal.java b/play-services-location-api/src/main/java/com/google/android/gms/location/internal/LocationRequestInternal.java index dd70d96a..ee2e09a6 100644 --- a/play-services-location-api/src/main/java/com/google/android/gms/location/internal/LocationRequestInternal.java +++ b/play-services-location-api/src/main/java/com/google/android/gms/location/internal/LocationRequestInternal.java @@ -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 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 + '}'; } diff --git a/play-services-location-core/build.gradle b/play-services-location-core/build.gradle index bc36d2af..db9e8643 100644 --- a/play-services-location-core/build.gradle +++ b/play-services-location-core/build.gradle @@ -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 { diff --git a/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManager.java b/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManager.java index 3ec7ac1b..f8c5d04e 100644 --- a/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManager.java +++ b/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManager.java @@ -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 currentRequests = new ArrayList(); - 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()); + } + } } diff --git a/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManagerService.java b/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManagerService.java index af6a3153..bf6c9870 100644 --- a/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManagerService.java +++ b/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManagerService.java @@ -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); + } } diff --git a/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManagerServiceImpl.java b/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManagerServiceImpl.java index b4315769..8169a4c7 100644 --- a/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManagerServiceImpl.java +++ b/play-services-location-core/src/main/java/org/microg/gms/location/GoogleLocationManagerServiceImpl.java @@ -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; diff --git a/play-services-location-core/src/main/java/org/microg/gms/location/LocationRequestHelper.java b/play-services-location-core/src/main/java/org/microg/gms/location/LocationRequestHelper.java index d1991efb..6fdae8d6 100644 --- a/play-services-location-core/src/main/java/org/microg/gms/location/LocationRequestHelper.java +++ b/play-services-location-core/src/main/java/org/microg/gms/location/LocationRequestHelper.java @@ -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; } } diff --git a/play-services-location-core/src/main/java/org/microg/gms/location/RealLocationProvider.java b/play-services-location-core/src/main/java/org/microg/gms/location/RealLocationProvider.java index 98e1947a..cb4fd496 100644 --- a/play-services-location-core/src/main/java/org/microg/gms/location/RealLocationProvider.java +++ b/play-services-location-core/src/main/java/org/microg/gms/location/RealLocationProvider.java @@ -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); + } + } + } } diff --git a/play-services-location-core/src/main/java/org/microg/gms/location/ReportingServiceImpl.java b/play-services-location-core/src/main/java/org/microg/gms/location/ReportingServiceImpl.java index c091cbde..f369f84e 100644 --- a/play-services-location-core/src/main/java/org/microg/gms/location/ReportingServiceImpl.java +++ b/play-services-location-core/src/main/java/org/microg/gms/location/ReportingServiceImpl.java @@ -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; + } } diff --git a/play-services-location-core/src/main/java/org/microg/gms/location/UnifiedLocationProvider.kt b/play-services-location-core/src/main/java/org/microg/gms/location/UnifiedLocationProvider.kt index fa952dca..f4df00fa 100644 --- a/play-services-location-core/src/main/java/org/microg/gms/location/UnifiedLocationProvider.kt +++ b/play-services-location-core/src/main/java/org/microg/gms/location/UnifiedLocationProvider.kt @@ -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 = ArrayList() - private val listener: UnifiedLocationClient.LocationListener = object : UnifiedLocationClient.LocationListener { - override fun onLocation(location: Location) { - lastLocation = location - changeListener.onLocationChanged() + private val activeRequestIds = hashSetOf() + 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() + 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() - } } diff --git a/play-services-location/src/main/java/org/microg/gms/location/NativeLocationClientImpl.java b/play-services-location/src/main/java/org/microg/gms/location/NativeLocationClientImpl.java index 17a017d9..78e0cd50 100644 --- a/play-services-location/src/main/java/org/microg/gms/location/NativeLocationClientImpl.java +++ b/play-services-location/src/main/java/org/microg/gms/location/NativeLocationClientImpl.java @@ -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); }