Refactor how location providers are managed
Put enabled/disabled state under location provider control, and use it to represent whether a location provider may be used, not whether the user has enabled or disabled a location provider. Bug: 118885128 Test: manually Change-Id: I1209c49c13ca8995b223f383ad332322fffc7a96
This commit is contained in:
@@ -451,6 +451,7 @@ java_defaults {
|
||||
"location/java/android/location/IGpsGeofenceHardware.aidl",
|
||||
"location/java/android/location/INetInitiatedListener.aidl",
|
||||
"location/java/com/android/internal/location/ILocationProvider.aidl",
|
||||
"location/java/com/android/internal/location/ILocationProviderManager.aidl",
|
||||
"media/java/android/media/IAudioFocusDispatcher.aidl",
|
||||
"media/java/android/media/IAudioRoutesObserver.aidl",
|
||||
"media/java/android/media/IAudioService.aidl",
|
||||
|
||||
@@ -22732,8 +22732,8 @@ package android.location {
|
||||
method public boolean addNmeaListener(android.location.OnNmeaMessageListener, android.os.Handler);
|
||||
method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
|
||||
method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
|
||||
method public void clearTestProviderEnabled(java.lang.String);
|
||||
method public void clearTestProviderLocation(java.lang.String);
|
||||
method public deprecated void clearTestProviderEnabled(java.lang.String);
|
||||
method public deprecated void clearTestProviderLocation(java.lang.String);
|
||||
method public deprecated void clearTestProviderStatus(java.lang.String);
|
||||
method public java.util.List<java.lang.String> getAllProviders();
|
||||
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
|
||||
|
||||
@@ -1849,13 +1849,16 @@ Lcom/android/internal/location/GpsNetInitiatedHandler;->handleNiNotification(Lco
|
||||
Lcom/android/internal/location/GpsNetInitiatedHandler;->mIsHexInput:Z
|
||||
Lcom/android/internal/location/ILocationProvider$Stub;-><init>()V
|
||||
Lcom/android/internal/location/ILocationProvider$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProvider;
|
||||
Lcom/android/internal/location/ILocationProvider;->disable()V
|
||||
Lcom/android/internal/location/ILocationProvider;->enable()V
|
||||
Lcom/android/internal/location/ILocationProvider;->getProperties()Lcom/android/internal/location/ProviderProperties;
|
||||
Lcom/android/internal/location/ILocationProvider;->getStatus(Landroid/os/Bundle;)I
|
||||
Lcom/android/internal/location/ILocationProvider;->getStatusUpdateTime()J
|
||||
Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)Z
|
||||
Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/String;Landroid/os/Bundle;)V
|
||||
Lcom/android/internal/location/ILocationProvider;->setLocationProviderManager(Lcom/android/internal/location/ILocationProviderManager;)V
|
||||
Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V
|
||||
Lcom/android/internal/location/ILocationProviderManager$Stub;-><init>()V
|
||||
Lcom/android/internal/location/ILocationProviderManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/location/ILocationProviderManager;
|
||||
Lcom/android/internal/location/ILocationProviderManager;->onReportLocation(Landroid/location/Location;)V
|
||||
Lcom/android/internal/location/ILocationProviderManager;->onSetEnabled(Z)V
|
||||
Lcom/android/internal/location/ILocationProviderManager;->onSetProperties(Lcom/android/internal/location/ProviderProperties;)V
|
||||
Lcom/android/internal/logging/MetricsLogger;-><init>()V
|
||||
Lcom/android/internal/net/LegacyVpnInfo;-><init>()V
|
||||
Lcom/android/internal/net/VpnConfig;-><init>()V
|
||||
|
||||
@@ -96,9 +96,7 @@ interface ILocationManager
|
||||
void addTestProvider(String name, in ProviderProperties properties, String opPackageName);
|
||||
void removeTestProvider(String provider, String opPackageName);
|
||||
void setTestProviderLocation(String provider, in Location loc, String opPackageName);
|
||||
void clearTestProviderLocation(String provider, String opPackageName);
|
||||
void setTestProviderEnabled(String provider, boolean enabled, String opPackageName);
|
||||
void clearTestProviderEnabled(String provider, String opPackageName);
|
||||
|
||||
// --- deprecated ---
|
||||
void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime,
|
||||
@@ -108,12 +106,8 @@ interface ILocationManager
|
||||
|
||||
// --- internal ---
|
||||
|
||||
// Used by location providers to tell the location manager when it has a new location.
|
||||
// Passive is true if the location is coming from the passive provider, in which case
|
||||
// it need not be shared with other providers.
|
||||
// --- deprecated ---
|
||||
void reportLocation(in Location location, boolean passive);
|
||||
|
||||
// Used when a (initially Gnss) Location batch arrives
|
||||
void reportLocationBatch(in List<Location> locations);
|
||||
|
||||
// for reporting callback completion
|
||||
|
||||
@@ -1537,14 +1537,11 @@ public class LocationManager {
|
||||
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
|
||||
* allowed} for your app.
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
*
|
||||
* @deprecated This function has always been a no-op, and may be removed in the future.
|
||||
*/
|
||||
public void clearTestProviderLocation(String provider) {
|
||||
try {
|
||||
mService.clearTestProviderLocation(provider, mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
@Deprecated
|
||||
public void clearTestProviderLocation(String provider) {}
|
||||
|
||||
/**
|
||||
* Sets a mock enabled value for the given provider. This value will be used in place
|
||||
@@ -1575,13 +1572,12 @@ public class LocationManager {
|
||||
* mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
|
||||
* allowed} for your app.
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
*
|
||||
* @deprecated Use {@link #setTestProviderEnabled(String, boolean)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void clearTestProviderEnabled(String provider) {
|
||||
try {
|
||||
mService.clearTestProviderEnabled(provider, mContext.getOpPackageName());
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
setTestProviderEnabled(provider, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,29 +16,26 @@
|
||||
|
||||
package com.android.internal.location;
|
||||
|
||||
import android.location.Location;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.WorkSource;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ILocationProviderManager;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
/**
|
||||
* Binder interface for services that implement location providers.
|
||||
* <p>Use {@link LocationProviderBase} as a helper to implement this
|
||||
* interface.
|
||||
* Binder interface for services that implement location providers. Do not implement this directly,
|
||||
* extend {@link LocationProviderBase} instead.
|
||||
* @hide
|
||||
*/
|
||||
interface ILocationProvider {
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
void setRequest(in ProviderRequest request, in WorkSource ws);
|
||||
oneway void setLocationProviderManager(in ILocationProviderManager manager);
|
||||
|
||||
// --- deprecated (but still supported) ---
|
||||
ProviderProperties getProperties();
|
||||
oneway void setRequest(in ProviderRequest request, in WorkSource ws);
|
||||
|
||||
oneway void sendExtraCommand(String command, in Bundle extras);
|
||||
|
||||
// --- deprecated and will be removed the future ---
|
||||
int getStatus(out Bundle extras);
|
||||
long getStatusUpdateTime();
|
||||
boolean sendExtraCommand(String command, inout Bundle extras);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.internal.location;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
|
||||
/**
|
||||
* Binder interface for manager of all location providers.
|
||||
* @hide
|
||||
*/
|
||||
interface ILocationProviderManager {
|
||||
|
||||
void onSetEnabled(boolean enabled);
|
||||
|
||||
void onSetProperties(in ProviderProperties properties);
|
||||
|
||||
void onReportLocation(in Location location);
|
||||
}
|
||||
@@ -16,15 +16,15 @@
|
||||
|
||||
package com.android.internal.location;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
import android.location.LocationRequest;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** @hide */
|
||||
public final class ProviderRequest implements Parcelable {
|
||||
/** Location reporting is requested (true) */
|
||||
@@ -35,6 +35,13 @@ public final class ProviderRequest implements Parcelable {
|
||||
@UnsupportedAppUsage
|
||||
public long interval = Long.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* When this flag is true, providers should ignore all location settings, user consents, power
|
||||
* restrictions or any other restricting factors and always satisfy this request to the best of
|
||||
* their ability. This flag should only be used in event of an emergency.
|
||||
*/
|
||||
public boolean forceLocation = false;
|
||||
|
||||
/**
|
||||
* Whether provider shall make stronger than normal tradeoffs to substantially restrict power
|
||||
* use.
|
||||
|
||||
@@ -8,14 +8,18 @@ package com.android.location.provider {
|
||||
public abstract class LocationProviderBase {
|
||||
ctor public LocationProviderBase(java.lang.String, com.android.location.provider.ProviderPropertiesUnbundled);
|
||||
method public android.os.IBinder getBinder();
|
||||
method public abstract void onDisable();
|
||||
method public void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
|
||||
method public abstract void onEnable();
|
||||
method public deprecated int onGetStatus(android.os.Bundle);
|
||||
method public deprecated long onGetStatusUpdateTime();
|
||||
method public boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
|
||||
method public abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
|
||||
method public final void reportLocation(android.location.Location);
|
||||
method public boolean isEnabled();
|
||||
method protected deprecated void onDisable();
|
||||
method protected void onDump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
|
||||
method protected deprecated void onEnable();
|
||||
method protected deprecated int onGetStatus(android.os.Bundle);
|
||||
method protected deprecated long onGetStatusUpdateTime();
|
||||
method protected void onInit();
|
||||
method protected boolean onSendExtraCommand(java.lang.String, android.os.Bundle);
|
||||
method protected abstract void onSetRequest(com.android.location.provider.ProviderRequestUnbundled, android.os.WorkSource);
|
||||
method public void reportLocation(android.location.Location);
|
||||
method public void setEnabled(boolean);
|
||||
method public void setProperties(com.android.location.provider.ProviderPropertiesUnbundled);
|
||||
field public static final java.lang.String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
|
||||
field public static final java.lang.String FUSED_PROVIDER = "fused";
|
||||
}
|
||||
@@ -38,6 +42,7 @@ package com.android.location.provider {
|
||||
}
|
||||
|
||||
public final class ProviderRequestUnbundled {
|
||||
method public boolean getForceLocation();
|
||||
method public long getInterval();
|
||||
method public java.util.List<com.android.location.provider.LocationRequestUnbundled> getLocationRequests();
|
||||
method public boolean getReportLocation();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.location.provider;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.Location;
|
||||
@@ -29,12 +30,11 @@ import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.location.ILocationProvider;
|
||||
import com.android.internal.location.ILocationProviderManager;
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
import com.android.internal.util.FastPrintWriter;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
@@ -55,12 +55,6 @@ import java.io.PrintWriter;
|
||||
* of this package for more information.
|
||||
*/
|
||||
public abstract class LocationProviderBase {
|
||||
private final String TAG;
|
||||
|
||||
/** @hide */
|
||||
protected final ILocationManager mLocationManager;
|
||||
private final ProviderProperties mProperties;
|
||||
private final IBinder mBinder;
|
||||
|
||||
/**
|
||||
* Bundle key for a version of the location containing no GPS data.
|
||||
@@ -77,49 +71,34 @@ public abstract class LocationProviderBase {
|
||||
*/
|
||||
public static final String FUSED_PROVIDER = LocationManager.FUSED_PROVIDER;
|
||||
|
||||
private final class Service extends ILocationProvider.Stub {
|
||||
@Override
|
||||
public void enable() {
|
||||
onEnable();
|
||||
}
|
||||
@Override
|
||||
public void disable() {
|
||||
onDisable();
|
||||
}
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource ws) {
|
||||
onSetRequest(new ProviderRequestUnbundled(request), ws);
|
||||
}
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return mProperties;
|
||||
}
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
return onGetStatus(extras);
|
||||
}
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
return onGetStatusUpdateTime();
|
||||
}
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
return onSendExtraCommand(command, extras);
|
||||
}
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, String[] args) {
|
||||
PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd));
|
||||
onDump(fd, pw, args);
|
||||
pw.flush();
|
||||
}
|
||||
}
|
||||
private final String mTag;
|
||||
private final IBinder mBinder;
|
||||
|
||||
/**
|
||||
* This field may be removed in the future, do not rely on it.
|
||||
*
|
||||
* @deprecated Do not use this field! Use LocationManager APIs instead. If you use this field
|
||||
* you may be broken in the future.
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
protected final ILocationManager mLocationManager;
|
||||
|
||||
// write locked on mBinder, read lock is optional depending on atomicity requirements
|
||||
@Nullable private volatile ILocationProviderManager mManager;
|
||||
private volatile ProviderProperties mProperties;
|
||||
private volatile boolean mEnabled;
|
||||
|
||||
public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {
|
||||
TAG = tag;
|
||||
IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
|
||||
mLocationManager = ILocationManager.Stub.asInterface(b);
|
||||
mProperties = properties.getProviderProperties();
|
||||
mTag = tag;
|
||||
mBinder = new Service();
|
||||
|
||||
mLocationManager = ILocationManager.Stub.asInterface(
|
||||
ServiceManager.getService(Context.LOCATION_SERVICE));
|
||||
|
||||
mManager = null;
|
||||
mProperties = properties.getProviderProperties();
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
public IBinder getBinder() {
|
||||
@@ -127,51 +106,116 @@ public abstract class LocationProviderBase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the location provider to report new locations.
|
||||
* Sets whether this provider is currently enabled or not. Note that this is specific to the
|
||||
* provider only, and is not related to global location settings. This is a hint to the Location
|
||||
* Manager that this provider will generally be unable to fulfill incoming requests. This
|
||||
* provider may still receive callbacks to onSetRequest while not enabled, and must decide
|
||||
* whether to attempt to satisfy those requests or not.
|
||||
*
|
||||
* @param location new Location to report
|
||||
*
|
||||
* Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
|
||||
* Some guidelines: providers should set their own enabled/disabled status based only on state
|
||||
* "owned" by that provider. For instance, providers should not take into account the state of
|
||||
* the location master setting when setting themselves enabled or disabled, as this state is not
|
||||
* owned by a particular provider. If a provider requires some additional user consent that is
|
||||
* particular to the provider, this should be use to set the enabled/disabled state. If the
|
||||
* provider proxies to another provider, the child provider's enabled/disabled state should be
|
||||
* taken into account in the parent's enabled/disabled state. For most providers, it is expected
|
||||
* that they will be always enabled.
|
||||
*/
|
||||
public final void reportLocation(Location location) {
|
||||
try {
|
||||
mLocationManager.reportLocation(location, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
} catch (Exception e) {
|
||||
// never crash provider, might be running in a system process
|
||||
Log.e(TAG, "Exception", e);
|
||||
public void setEnabled(boolean enabled) {
|
||||
synchronized (mBinder) {
|
||||
if (mEnabled == enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
mEnabled = enabled;
|
||||
}
|
||||
|
||||
ILocationProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
try {
|
||||
manager.onSetEnabled(mEnabled);
|
||||
} catch (RemoteException | RuntimeException e) {
|
||||
Log.w(mTag, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the location provider.
|
||||
* <p>The provider may initialize resources, but does
|
||||
* not yet need to report locations.
|
||||
* Sets the provider properties that may be queried by clients. Generally speaking, providers
|
||||
* should try to avoid changing their properties after construction.
|
||||
*/
|
||||
public abstract void onEnable();
|
||||
public void setProperties(ProviderPropertiesUnbundled properties) {
|
||||
synchronized (mBinder) {
|
||||
mProperties = properties.getProviderProperties();
|
||||
}
|
||||
|
||||
ILocationProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
try {
|
||||
manager.onSetProperties(mProperties);
|
||||
} catch (RemoteException | RuntimeException e) {
|
||||
Log.w(mTag, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable the location provider.
|
||||
* <p>The provider must release resources, and stop
|
||||
* performing work. It may no longer report locations.
|
||||
* Returns true if this provider has been set as enabled. This will be true unless explicitly
|
||||
* set otherwise.
|
||||
*/
|
||||
public abstract void onDisable();
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link ProviderRequest} requirements for this provider.
|
||||
* <p>Each call to this method overrides all previous requests.
|
||||
* <p>This method might trigger the provider to start returning
|
||||
* locations, or to stop returning locations, depending on the
|
||||
* parameters in the request.
|
||||
* Reports a new location from this provider.
|
||||
*/
|
||||
public abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
|
||||
public void reportLocation(Location location) {
|
||||
ILocationProviderManager manager = mManager;
|
||||
if (manager != null) {
|
||||
try {
|
||||
manager.onReportLocation(location);
|
||||
} catch (RemoteException | RuntimeException e) {
|
||||
Log.w(mTag, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void onInit() {
|
||||
// call once so that providers designed for APIs pre-Q are not broken
|
||||
onEnable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This callback will be invoked once when the provider is created to maintain
|
||||
* backwards compatibility with providers not designed for Android Q and above. This method
|
||||
* should only be implemented in location providers that need to support SDKs below Android Q.
|
||||
* Even in this case, it is usually unnecessary to implement this callback with the correct
|
||||
* design. This method may be removed in the future.
|
||||
*/
|
||||
@Deprecated
|
||||
protected void onEnable() {}
|
||||
|
||||
/**
|
||||
* @deprecated This callback will be never be invoked on Android Q and above. This method should
|
||||
* only be implemented in location providers that need to support SDKs below Android Q. Even in
|
||||
* this case, it is usually unnecessary to implement this callback with the correct design. This
|
||||
* method may be removed in the future.
|
||||
*/
|
||||
@Deprecated
|
||||
protected void onDisable() {}
|
||||
|
||||
/**
|
||||
* Set the {@link ProviderRequest} requirements for this provider. Each call to this method
|
||||
* overrides all previous requests. This method might trigger the provider to start returning
|
||||
* locations, or to stop returning locations, depending on the parameters in the request.
|
||||
*/
|
||||
protected abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
|
||||
|
||||
/**
|
||||
* Dump debug information.
|
||||
*/
|
||||
public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
}
|
||||
protected void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {}
|
||||
|
||||
/**
|
||||
* This method will no longer be invoked.
|
||||
@@ -187,10 +231,12 @@ public abstract class LocationProviderBase {
|
||||
* <p>If extras is non-null, additional status information may be
|
||||
* added to it in the form of provider-specific key/value pairs.
|
||||
*
|
||||
* @deprecated This method will no longer be invoked.
|
||||
* @deprecated This callback will be never be invoked on Android Q and above. This method should
|
||||
* only be implemented in location providers that need to support SDKs below Android Q. This
|
||||
* method may be removed in the future.
|
||||
*/
|
||||
@Deprecated
|
||||
public int onGetStatus(Bundle extras) {
|
||||
protected int onGetStatus(Bundle extras) {
|
||||
return LocationProvider.AVAILABLE;
|
||||
}
|
||||
|
||||
@@ -206,24 +252,64 @@ public abstract class LocationProviderBase {
|
||||
*
|
||||
* @return time of last status update in millis since last reboot
|
||||
*
|
||||
* @deprecated This method will no longer be invoked.
|
||||
* @deprecated This callback will be never be invoked on Android Q and above. This method should
|
||||
* only be implemented in location providers that need to support SDKs below Android Q. This
|
||||
* method may be removed in the future.
|
||||
*/
|
||||
@Deprecated
|
||||
public long onGetStatusUpdateTime() {
|
||||
protected long onGetStatusUpdateTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements addditional location provider specific additional commands.
|
||||
*
|
||||
* @param command name of the command to send to the provider.
|
||||
* @param extras optional arguments for the command (or null).
|
||||
* The provider may optionally fill the extras Bundle with results from the command.
|
||||
*
|
||||
* @return true if the command succeeds.
|
||||
* Implements location provider specific custom commands. The return value will be ignored on
|
||||
* Android Q and above.
|
||||
*/
|
||||
public boolean onSendExtraCommand(String command, Bundle extras) {
|
||||
// default implementation
|
||||
protected boolean onSendExtraCommand(@Nullable String command, @Nullable Bundle extras) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private final class Service extends ILocationProvider.Stub {
|
||||
|
||||
@Override
|
||||
public void setLocationProviderManager(ILocationProviderManager manager) {
|
||||
synchronized (mBinder) {
|
||||
try {
|
||||
manager.onSetProperties(mProperties);
|
||||
manager.onSetEnabled(mEnabled);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(mTag, e);
|
||||
}
|
||||
|
||||
mManager = manager;
|
||||
}
|
||||
|
||||
onInit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource ws) {
|
||||
onSetRequest(new ProviderRequestUnbundled(request), ws);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
return onGetStatus(extras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
return onGetStatusUpdateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendExtraCommand(String command, Bundle extras) {
|
||||
onSendExtraCommand(command, extras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
onDump(fd, pw, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package com.android.location.provider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.location.LocationRequest;
|
||||
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class is an interface to Provider Requests for unbundled applications.
|
||||
*
|
||||
@@ -46,6 +46,10 @@ public final class ProviderRequestUnbundled {
|
||||
return mRequest.interval;
|
||||
}
|
||||
|
||||
public boolean getForceLocation() {
|
||||
return mRequest.forceLocation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Never null.
|
||||
*/
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.content.IntentFilter;
|
||||
import android.location.Criteria;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.UserHandle;
|
||||
import android.os.WorkSource;
|
||||
|
||||
@@ -34,87 +33,53 @@ import com.android.location.provider.ProviderRequestUnbundled;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
public class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback {
|
||||
class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback {
|
||||
private static final String TAG = "FusedLocationProvider";
|
||||
|
||||
private static ProviderPropertiesUnbundled PROPERTIES = ProviderPropertiesUnbundled.create(
|
||||
false, false, false, false, true, true, true, Criteria.POWER_LOW,
|
||||
Criteria.ACCURACY_FINE);
|
||||
|
||||
private static final int MSG_ENABLE = 1;
|
||||
private static final int MSG_DISABLE = 2;
|
||||
private static final int MSG_SET_REQUEST = 3;
|
||||
|
||||
private final Context mContext;
|
||||
private final Handler mHandler;
|
||||
private final FusionEngine mEngine;
|
||||
|
||||
private static class RequestWrapper {
|
||||
public ProviderRequestUnbundled request;
|
||||
public WorkSource source;
|
||||
public RequestWrapper(ProviderRequestUnbundled request, WorkSource source) {
|
||||
this.request = request;
|
||||
this.source = source;
|
||||
}
|
||||
}
|
||||
|
||||
public FusedLocationProvider(Context context) {
|
||||
super(TAG, PROPERTIES);
|
||||
mEngine = new FusionEngine(context, Looper.myLooper());
|
||||
|
||||
// listen for user change
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
|
||||
context.registerReceiverAsUser(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
|
||||
mEngine.switchUser();
|
||||
}
|
||||
}
|
||||
}, UserHandle.ALL, intentFilter, null, mHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* For serializing requests to mEngine.
|
||||
*/
|
||||
private Handler mHandler = new Handler() {
|
||||
private final BroadcastReceiver mUserSwitchReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_ENABLE:
|
||||
mEngine.init(FusedLocationProvider.this);
|
||||
break;
|
||||
case MSG_DISABLE:
|
||||
mEngine.deinit();
|
||||
break;
|
||||
case MSG_SET_REQUEST:
|
||||
{
|
||||
RequestWrapper wrapper = (RequestWrapper) msg.obj;
|
||||
mEngine.setRequest(wrapper.request, wrapper.source);
|
||||
break;
|
||||
}
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (Intent.ACTION_USER_SWITCHED.equals(action)) {
|
||||
mEngine.switchUser();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
mHandler.sendEmptyMessage(MSG_ENABLE);
|
||||
FusedLocationProvider(Context context) {
|
||||
super(TAG, PROPERTIES);
|
||||
|
||||
mContext = context;
|
||||
mHandler = new Handler(Looper.myLooper());
|
||||
mEngine = new FusionEngine(context, Looper.myLooper(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
mHandler.sendEmptyMessage(MSG_DISABLE);
|
||||
void init() {
|
||||
// listen for user change
|
||||
mContext.registerReceiverAsUser(mUserSwitchReceiver, UserHandle.ALL,
|
||||
new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
mContext.unregisterReceiver(mUserSwitchReceiver);
|
||||
mHandler.post(() -> mEngine.setRequest(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetRequest(ProviderRequestUnbundled request, WorkSource source) {
|
||||
mHandler.obtainMessage(MSG_SET_REQUEST, new RequestWrapper(request, source)).sendToTarget();
|
||||
mHandler.post(() -> mEngine.setRequest(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
// perform synchronously
|
||||
mEngine.dump(fd, pw, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,27 +21,24 @@ import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class FusedLocationService extends Service {
|
||||
|
||||
private FusedLocationProvider mProvider;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (mProvider == null) {
|
||||
mProvider = new FusedLocationProvider(getApplicationContext());
|
||||
mProvider = new FusedLocationProvider(this);
|
||||
mProvider.init();
|
||||
}
|
||||
|
||||
return mProvider.getBinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onUnbind(Intent intent) {
|
||||
// make sure to stop performing work
|
||||
if (mProvider != null) {
|
||||
mProvider.onDisable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mProvider = null;
|
||||
if (mProvider != null) {
|
||||
mProvider.destroy();
|
||||
mProvider = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,6 @@
|
||||
|
||||
package com.android.location.fused;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.android.location.provider.LocationProviderBase;
|
||||
import com.android.location.provider.LocationRequestUnbundled;
|
||||
import com.android.location.provider.ProviderRequestUnbundled;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
@@ -32,9 +24,16 @@ import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.location.provider.LocationProviderBase;
|
||||
import com.android.location.provider.LocationRequestUnbundled;
|
||||
import com.android.location.provider.ProviderRequestUnbundled;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class FusionEngine implements LocationListener {
|
||||
public interface Callback {
|
||||
void reportLocation(Location location);
|
||||
@@ -47,72 +46,35 @@ public class FusionEngine implements LocationListener {
|
||||
|
||||
public static final long SWITCH_ON_FRESHNESS_CLIFF_NS = 11 * 1000000000L; // 11 seconds
|
||||
|
||||
private final Context mContext;
|
||||
private final LocationManager mLocationManager;
|
||||
private final Looper mLooper;
|
||||
private final Callback mCallback;
|
||||
|
||||
// all fields are only used on mLooper thread. except for in dump() which is not thread-safe
|
||||
private Callback mCallback;
|
||||
private Location mFusedLocation;
|
||||
private Location mGpsLocation;
|
||||
private Location mNetworkLocation;
|
||||
|
||||
private boolean mEnabled;
|
||||
private ProviderRequestUnbundled mRequest;
|
||||
|
||||
private final HashMap<String, ProviderStats> mStats = new HashMap<>();
|
||||
|
||||
public FusionEngine(Context context, Looper looper) {
|
||||
mContext = context;
|
||||
FusionEngine(Context context, Looper looper, Callback callback) {
|
||||
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
mNetworkLocation = new Location("");
|
||||
mNetworkLocation.setAccuracy(Float.MAX_VALUE);
|
||||
mGpsLocation = new Location("");
|
||||
mGpsLocation.setAccuracy(Float.MAX_VALUE);
|
||||
mLooper = looper;
|
||||
mCallback = callback;
|
||||
|
||||
mStats.put(GPS, new ProviderStats());
|
||||
mStats.put(NETWORK, new ProviderStats());
|
||||
|
||||
}
|
||||
|
||||
public void init(Callback callback) {
|
||||
Log.i(TAG, "engine started (" + mContext.getPackageName() + ")");
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to stop doing any work, and release all resources
|
||||
* This can happen when a better fusion engine is installed
|
||||
* in a different package, and this one is no longer needed.
|
||||
* Called on mLooper thread
|
||||
*/
|
||||
public void deinit() {
|
||||
mRequest = null;
|
||||
disable();
|
||||
Log.i(TAG, "engine stopped (" + mContext.getPackageName() + ")");
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
public void enable() {
|
||||
if (!mEnabled) {
|
||||
mEnabled = true;
|
||||
updateRequirements();
|
||||
}
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
public void disable() {
|
||||
if (mEnabled) {
|
||||
mEnabled = false;
|
||||
updateRequirements();
|
||||
}
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
public void setRequest(ProviderRequestUnbundled request, WorkSource source) {
|
||||
public void setRequest(ProviderRequestUnbundled request) {
|
||||
mRequest = request;
|
||||
mEnabled = request.getReportLocation();
|
||||
updateRequirements();
|
||||
}
|
||||
|
||||
@@ -120,6 +82,7 @@ public class FusionEngine implements LocationListener {
|
||||
public boolean requested;
|
||||
public long requestTime;
|
||||
public long minTime;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return (requested ? " REQUESTED" : " ---");
|
||||
@@ -154,7 +117,7 @@ public class FusionEngine implements LocationListener {
|
||||
}
|
||||
|
||||
private void updateRequirements() {
|
||||
if (!mEnabled || mRequest == null) {
|
||||
if (mRequest == null || !mRequest.getReportLocation()) {
|
||||
mRequest = null;
|
||||
disableProvider(NETWORK);
|
||||
disableProvider(GPS);
|
||||
@@ -200,29 +163,30 @@ public class FusionEngine implements LocationListener {
|
||||
* Test whether one location (a) is better to use than another (b).
|
||||
*/
|
||||
private static boolean isBetterThan(Location locationA, Location locationB) {
|
||||
if (locationA == null) {
|
||||
return false;
|
||||
}
|
||||
if (locationB == null) {
|
||||
return true;
|
||||
}
|
||||
// A provider is better if the reading is sufficiently newer. Heading
|
||||
// underground can cause GPS to stop reporting fixes. In this case it's
|
||||
// appropriate to revert to cell, even when its accuracy is less.
|
||||
if (locationA.getElapsedRealtimeNanos() > locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) {
|
||||
return true;
|
||||
}
|
||||
if (locationA == null) {
|
||||
return false;
|
||||
}
|
||||
if (locationB == null) {
|
||||
return true;
|
||||
}
|
||||
// A provider is better if the reading is sufficiently newer. Heading
|
||||
// underground can cause GPS to stop reporting fixes. In this case it's
|
||||
// appropriate to revert to cell, even when its accuracy is less.
|
||||
if (locationA.getElapsedRealtimeNanos()
|
||||
> locationB.getElapsedRealtimeNanos() + SWITCH_ON_FRESHNESS_CLIFF_NS) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// A provider is better if it has better accuracy. Assuming both readings
|
||||
// are fresh (and by that accurate), choose the one with the smaller
|
||||
// accuracy circle.
|
||||
if (!locationA.hasAccuracy()) {
|
||||
return false;
|
||||
}
|
||||
if (!locationB.hasAccuracy()) {
|
||||
return true;
|
||||
}
|
||||
return locationA.getAccuracy() < locationB.getAccuracy();
|
||||
// A provider is better if it has better accuracy. Assuming both readings
|
||||
// are fresh (and by that accurate), choose the one with the smaller
|
||||
// accuracy circle.
|
||||
if (!locationA.hasAccuracy()) {
|
||||
return false;
|
||||
}
|
||||
if (!locationB.hasAccuracy()) {
|
||||
return true;
|
||||
}
|
||||
return locationA.getAccuracy() < locationB.getAccuracy();
|
||||
}
|
||||
|
||||
private void updateFusedLocation() {
|
||||
@@ -252,9 +216,9 @@ public class FusionEngine implements LocationListener {
|
||||
}
|
||||
|
||||
if (mCallback != null) {
|
||||
mCallback.reportLocation(mFusedLocation);
|
||||
mCallback.reportLocation(mFusedLocation);
|
||||
} else {
|
||||
Log.w(TAG, "Location updates received while fusion engine not started");
|
||||
Log.w(TAG, "Location updates received while fusion engine not started");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -272,19 +236,22 @@ public class FusionEngine implements LocationListener {
|
||||
|
||||
/** Called on mLooper thread */
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) { }
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) { }
|
||||
public void onProviderEnabled(String provider) {
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) { }
|
||||
public void onProviderDisabled(String provider) {
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("mEnabled=").append(mEnabled).append(' ').append(mRequest).append('\n');
|
||||
s.append(mRequest).append('\n');
|
||||
s.append("fused=").append(mFusedLocation).append('\n');
|
||||
s.append(String.format("gps %s\n", mGpsLocation));
|
||||
s.append(" ").append(mStats.get(GPS)).append('\n');
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,9 +16,7 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.WorkerThread;
|
||||
import android.app.ActivityManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
@@ -168,13 +166,13 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
// called on handler thread
|
||||
@GuardedBy("mBindLock")
|
||||
protected void onBind() {
|
||||
|
||||
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
|
||||
}
|
||||
|
||||
// called on handler thread
|
||||
@GuardedBy("mBindLock")
|
||||
protected void onUnbind() {
|
||||
|
||||
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -205,12 +203,12 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
|
||||
@Override
|
||||
public void onPackageRemoved(String packageName, int uid) {
|
||||
bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
|
||||
bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPackageChanged(String packageName, int uid, String[] components) {
|
||||
bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
|
||||
bindBestPackage(Objects.equals(packageName, getCurrentPackageName()));
|
||||
return super.onPackageChanged(packageName, uid, components);
|
||||
}
|
||||
}.register(mContext, UserHandle.ALL, true, mHandler);
|
||||
@@ -243,20 +241,16 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns thje name of the currently connected package or null. */
|
||||
/** Returns the name of the currently connected package or null. */
|
||||
@Nullable
|
||||
public String getCurrentPackageName() {
|
||||
ComponentName bestComponent = mBestComponent;
|
||||
return bestComponent == null ? null : bestComponent.getPackageName();
|
||||
}
|
||||
|
||||
public int getCurrentPackageVersion() {
|
||||
return mBestVersion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given BinderRunner if currently connected. Returns true if it was run, and false
|
||||
* otherwise. All invocations to runOnBinder are run serially.
|
||||
* Runs the given BinderRunner if currently connected. All invocations to runOnBinder are run
|
||||
* serially.
|
||||
*/
|
||||
public final void runOnBinder(BinderRunner runner) {
|
||||
synchronized (mBindLock) {
|
||||
@@ -267,7 +261,7 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
} catch (Exception e) {
|
||||
// remote exceptions cannot be allowed to crash system server
|
||||
Log.e(TAG, "exception while while running " + runner + " on " + service
|
||||
+ " from " + mBestComponent.toShortString(), e);
|
||||
+ " from " + this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,14 +274,6 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
UserHandle.USER_SYSTEM).isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches and binds to the best package, or do nothing if the best package
|
||||
* is already bound, unless force rebinding is requested.
|
||||
*
|
||||
* @param forceRebind Force a rebinding to the best package if it's already
|
||||
* bound.
|
||||
*/
|
||||
@WorkerThread
|
||||
private void bindBestPackage(boolean forceRebind) {
|
||||
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
|
||||
|
||||
@@ -365,7 +351,6 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
}
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void bind(ComponentName component, int version, int userId) {
|
||||
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
|
||||
|
||||
@@ -382,7 +367,6 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
UserHandle.of(userId));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void unbind() {
|
||||
Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
|
||||
|
||||
@@ -396,7 +380,6 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
mBestUserId = UserHandle.USER_NULL;
|
||||
}
|
||||
|
||||
@MainThread
|
||||
@Override
|
||||
public final void onServiceConnected(ComponentName component, IBinder binder) {
|
||||
mHandler.post(() -> {
|
||||
@@ -410,7 +393,6 @@ public class ServiceWatcher implements ServiceConnection {
|
||||
});
|
||||
}
|
||||
|
||||
@MainThread
|
||||
@Override
|
||||
public final void onServiceDisconnected(ComponentName component) {
|
||||
mHandler.post(() -> {
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import android.location.Location;
|
||||
import android.location.LocationProvider;
|
||||
import android.os.Bundle;
|
||||
import android.os.WorkSource;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Location Manager's interface for location providers.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class AbstractLocationProvider {
|
||||
|
||||
/**
|
||||
* Interface for communicating from a location provider back to the location service.
|
||||
*/
|
||||
public interface LocationProviderManager {
|
||||
|
||||
/**
|
||||
* Called on location provider construction to make the location service aware of this
|
||||
* provider and what it's initial enabled/disabled state should be.
|
||||
*/
|
||||
void onAttachProvider(AbstractLocationProvider locationProvider, boolean initiallyEnabled);
|
||||
|
||||
/**
|
||||
* May be called to inform the location service of a change in this location provider's
|
||||
* enabled/disabled state.
|
||||
*/
|
||||
void onSetEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* May be called to inform the location service of a change in this location provider's
|
||||
* properties.
|
||||
*/
|
||||
void onSetProperties(ProviderProperties properties);
|
||||
|
||||
/**
|
||||
* May be called to inform the location service that this provider has a new location
|
||||
* available.
|
||||
*/
|
||||
void onReportLocation(Location location);
|
||||
|
||||
/**
|
||||
* May be called to inform the location service that this provider has a new location
|
||||
* available.
|
||||
*/
|
||||
void onReportLocation(List<Location> locations);
|
||||
}
|
||||
|
||||
private final LocationProviderManager mLocationProviderManager;
|
||||
|
||||
protected AbstractLocationProvider(LocationProviderManager locationProviderManager) {
|
||||
this(locationProviderManager, true);
|
||||
}
|
||||
|
||||
protected AbstractLocationProvider(LocationProviderManager locationProviderManager,
|
||||
boolean initiallyEnabled) {
|
||||
mLocationProviderManager = locationProviderManager;
|
||||
mLocationProviderManager.onAttachProvider(this, initiallyEnabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to report a new location. May be called from any thread.
|
||||
*/
|
||||
protected void reportLocation(Location location) {
|
||||
mLocationProviderManager.onReportLocation(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to report a new location. May be called from any thread.
|
||||
*/
|
||||
protected void reportLocation(List<Location> locations) {
|
||||
mLocationProviderManager.onReportLocation(locations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to report a change in provider enabled/disabled status. May be called from
|
||||
* any thread.
|
||||
*/
|
||||
protected void setEnabled(boolean enabled) {
|
||||
mLocationProviderManager.onSetEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method to report a change in provider properties. May be called from
|
||||
* any thread.
|
||||
*/
|
||||
protected void setProperties(ProviderProperties properties) {
|
||||
mLocationProviderManager.onSetProperties(properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the location service delivers a new request for fulfillment to the provider.
|
||||
* Replaces any previous requests completely.
|
||||
*/
|
||||
public abstract void setRequest(ProviderRequest request, WorkSource source);
|
||||
|
||||
/**
|
||||
* Called to dump debug or log information.
|
||||
*/
|
||||
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
|
||||
|
||||
/**
|
||||
* Retrieves the current status of the provider.
|
||||
*
|
||||
* @deprecated Will be removed in a future release.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getStatus(Bundle extras) {
|
||||
return LocationProvider.AVAILABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the last update time of the status of the provider.
|
||||
*
|
||||
* @deprecated Will be removed in a future release.
|
||||
*/
|
||||
@Deprecated
|
||||
public long getStatusUpdateTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Sends a custom command to this provider. */
|
||||
public abstract void sendExtraCommand(String command, Bundle extras);
|
||||
}
|
||||
@@ -34,7 +34,6 @@ import android.location.GnssStatus;
|
||||
import android.location.IGnssStatusListener;
|
||||
import android.location.IGnssStatusProvider;
|
||||
import android.location.IGpsGeofenceHardware;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.INetInitiatedListener;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
@@ -84,6 +83,10 @@ import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -97,8 +100,18 @@ import java.util.Properties;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class GnssLocationProvider extends LocationProviderInterface
|
||||
implements InjectNtpTimeCallback, GnssSatelliteBlacklistCallback {
|
||||
public class GnssLocationProvider extends AbstractLocationProvider implements
|
||||
InjectNtpTimeCallback,
|
||||
GnssSatelliteBlacklistCallback {
|
||||
|
||||
/**
|
||||
* Indicates that this method is a native entry point. Useful purely for IDEs which can
|
||||
* understand entry points, and thus eliminate incorrect warnings about methods not used.
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
private @interface NativeEntryPoint {
|
||||
}
|
||||
|
||||
private static final String TAG = "GnssLocationProvider";
|
||||
|
||||
@@ -249,7 +262,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
|
||||
public void set(int svCount, int meanCn0, int maxCn0) {
|
||||
synchronized(this) {
|
||||
synchronized (this) {
|
||||
mSvCount = svCount;
|
||||
mMeanCn0 = meanCn0;
|
||||
mMaxCn0 = maxCn0;
|
||||
@@ -258,7 +271,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
set(0,0,0);
|
||||
set(0, 0, 0);
|
||||
}
|
||||
|
||||
// Also used by outside methods to add to other bundles
|
||||
@@ -314,7 +327,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
MAX_RETRY_INTERVAL);
|
||||
|
||||
// true if we are enabled, protected by this
|
||||
private boolean mEnabled;
|
||||
private boolean mEnabled = true;
|
||||
|
||||
// states for injecting ntp and downloading xtra data
|
||||
private static final int STATE_PENDING_NETWORK = 0;
|
||||
@@ -328,9 +341,6 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
// true if GPS is navigating
|
||||
private boolean mNavigating;
|
||||
|
||||
// true if GPS engine is on
|
||||
private boolean mEngineOn;
|
||||
|
||||
// requested frequency of fixes, in milliseconds
|
||||
private int mFixInterval = 1000;
|
||||
|
||||
@@ -380,7 +390,6 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
private boolean mSuplEsEnabled = false;
|
||||
|
||||
private final Context mContext;
|
||||
private final ILocationManager mILocationManager;
|
||||
private final LocationExtras mLocationExtras = new LocationExtras();
|
||||
private final GnssStatusListenerHelper mListenerHelper;
|
||||
private final GnssSatelliteBlacklistHelper mGnssSatelliteBlacklistHelper;
|
||||
@@ -479,17 +488,22 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
return;
|
||||
}
|
||||
|
||||
if (action.equals(ALARM_WAKEUP)) {
|
||||
startNavigating(false);
|
||||
} else if (action.equals(ALARM_TIMEOUT)) {
|
||||
hibernate();
|
||||
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
|
||||
|| PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
|
||||
|| Intent.ACTION_SCREEN_OFF.equals(action)
|
||||
|| Intent.ACTION_SCREEN_ON.equals(action)) {
|
||||
updateLowPowerMode();
|
||||
} else if (action.equals(SIM_STATE_CHANGED)) {
|
||||
subscriptionOrSimChanged(context);
|
||||
switch (action) {
|
||||
case ALARM_WAKEUP:
|
||||
startNavigating(false);
|
||||
break;
|
||||
case ALARM_TIMEOUT:
|
||||
hibernate();
|
||||
break;
|
||||
case PowerManager.ACTION_POWER_SAVE_MODE_CHANGED:
|
||||
case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
|
||||
case Intent.ACTION_SCREEN_OFF:
|
||||
case Intent.ACTION_SCREEN_ON:
|
||||
updateLowPowerMode();
|
||||
break;
|
||||
case SIM_STATE_CHANGED:
|
||||
subscriptionOrSimChanged(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -507,9 +521,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
*/
|
||||
@Override
|
||||
public void onUpdateSatelliteBlacklist(int[] constellations, int[] svids) {
|
||||
mHandler.post(()->{
|
||||
native_set_satellite_blacklist(constellations, svids);
|
||||
});
|
||||
mHandler.post(() -> native_set_satellite_blacklist(constellations, svids));
|
||||
}
|
||||
|
||||
private void subscriptionOrSimChanged(Context context) {
|
||||
@@ -572,7 +584,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
|
||||
interface SetCarrierProperty {
|
||||
public boolean set(int value);
|
||||
boolean set(int value);
|
||||
}
|
||||
|
||||
private void reloadGpsProperties(Context context, Properties properties) {
|
||||
@@ -587,7 +599,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
/*
|
||||
* Overlay carrier properties from a debug configuration file.
|
||||
*/
|
||||
loadPropertiesFromFile(DEBUG_PROPERTIES_FILE, properties);
|
||||
loadPropertiesFromFile(properties);
|
||||
// TODO: we should get rid of C2K specific setting.
|
||||
setSuplHostPort(properties.getProperty("SUPL_HOST"),
|
||||
properties.getProperty("SUPL_PORT"));
|
||||
@@ -603,15 +615,15 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
if (native_is_gnss_configuration_supported()) {
|
||||
Map<String, SetCarrierProperty> map = new HashMap<String, SetCarrierProperty>() {
|
||||
{
|
||||
put("SUPL_VER", (val) -> native_set_supl_version(val));
|
||||
put("SUPL_MODE", (val) -> native_set_supl_mode(val));
|
||||
put("SUPL_ES", (val) -> native_set_supl_es(val));
|
||||
put("LPP_PROFILE", (val) -> native_set_lpp_profile(val));
|
||||
put("SUPL_VER", GnssLocationProvider::native_set_supl_version);
|
||||
put("SUPL_MODE", GnssLocationProvider::native_set_supl_mode);
|
||||
put("SUPL_ES", GnssLocationProvider::native_set_supl_es);
|
||||
put("LPP_PROFILE", GnssLocationProvider::native_set_lpp_profile);
|
||||
put("A_GLONASS_POS_PROTOCOL_SELECT",
|
||||
(val) -> native_set_gnss_pos_protocol_select(val));
|
||||
GnssLocationProvider::native_set_gnss_pos_protocol_select);
|
||||
put("USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL",
|
||||
(val) -> native_set_emergency_supl_pdn(val));
|
||||
put("GPS_LOCK", (val) -> native_set_gps_lock(val));
|
||||
GnssLocationProvider::native_set_emergency_supl_pdn);
|
||||
put("GPS_LOCK", GnssLocationProvider::native_set_gps_lock);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -622,7 +634,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
try {
|
||||
int propertyValueInt = Integer.decode(propertyValueString);
|
||||
boolean result = entry.getValue().set(propertyValueInt);
|
||||
if (result == false) {
|
||||
if (!result) {
|
||||
Log.e(TAG, "Unable to set " + propertyName);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
@@ -664,10 +676,9 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
}
|
||||
|
||||
private boolean loadPropertiesFromFile(String filename,
|
||||
Properties properties) {
|
||||
private void loadPropertiesFromFile(Properties properties) {
|
||||
try {
|
||||
File file = new File(filename);
|
||||
File file = new File(DEBUG_PROPERTIES_FILE);
|
||||
FileInputStream stream = null;
|
||||
try {
|
||||
stream = new FileInputStream(file);
|
||||
@@ -677,16 +688,15 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + filename);
|
||||
return false;
|
||||
if (DEBUG) Log.d(TAG, "Could not open GPS configuration file " + DEBUG_PROPERTIES_FILE);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public GnssLocationProvider(Context context, ILocationManager ilocationManager,
|
||||
public GnssLocationProvider(Context context, LocationProviderManager locationProviderManager,
|
||||
Looper looper) {
|
||||
super(locationProviderManager, true);
|
||||
|
||||
mContext = context;
|
||||
mILocationManager = ilocationManager;
|
||||
|
||||
// Create a wake lock
|
||||
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||
@@ -763,19 +773,20 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
mHandler.post(mGnssSatelliteBlacklistHelper::updateSatelliteBlacklist);
|
||||
mGnssBatchingProvider = new GnssBatchingProvider();
|
||||
mGnssGeofenceProvider = new GnssGeofenceProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this provider.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return LocationManager.GPS_PROVIDER;
|
||||
}
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intent.ACTION_SHUTDOWN);
|
||||
mContext.registerReceiverAsUser(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (getSendingUserId() == UserHandle.USER_ALL) {
|
||||
mEnabled = false;
|
||||
handleDisable();
|
||||
}
|
||||
}
|
||||
}, UserHandle.ALL, intentFilter, null, mHandler);
|
||||
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return PROPERTIES;
|
||||
setProperties(PROPERTIES);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -840,9 +851,9 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
locationManager.requestLocationUpdates(provider,
|
||||
LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
|
||||
locationListener, mHandler.getLooper());
|
||||
locationListener.numLocationUpdateRequest++;
|
||||
locationListener.mNumLocationUpdateRequest++;
|
||||
mHandler.postDelayed(() -> {
|
||||
if (--locationListener.numLocationUpdateRequest == 0) {
|
||||
if (--locationListener.mNumLocationUpdateRequest == 0) {
|
||||
Log.i(TAG,
|
||||
String.format("Removing location updates from %s provider.", provider));
|
||||
locationManager.removeUpdates(locationListener);
|
||||
@@ -905,43 +916,40 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
// hold wake lock while task runs
|
||||
mDownloadXtraWakeLock.acquire(DOWNLOAD_XTRA_DATA_TIMEOUT_MS);
|
||||
Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
|
||||
byte[] data = xtraDownloader.downloadXtraData();
|
||||
if (data != null) {
|
||||
if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
|
||||
native_inject_xtra_data(data, data.length);
|
||||
mXtraBackOff.reset();
|
||||
}
|
||||
AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
|
||||
GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
|
||||
byte[] data = xtraDownloader.downloadXtraData();
|
||||
if (data != null) {
|
||||
if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
|
||||
native_inject_xtra_data(data, data.length);
|
||||
mXtraBackOff.reset();
|
||||
}
|
||||
|
||||
sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
|
||||
sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
|
||||
|
||||
if (data == null) {
|
||||
// try again later
|
||||
// since this is delayed and not urgent we do not hold a wake lock here
|
||||
mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
|
||||
mXtraBackOff.nextBackoffMillis());
|
||||
}
|
||||
if (data == null) {
|
||||
// try again later
|
||||
// since this is delayed and not urgent we do not hold a wake lock here
|
||||
mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
|
||||
mXtraBackOff.nextBackoffMillis());
|
||||
}
|
||||
|
||||
// Release wake lock held by task, synchronize on mLock in case multiple
|
||||
// download tasks overrun.
|
||||
synchronized (mLock) {
|
||||
if (mDownloadXtraWakeLock.isHeld()) {
|
||||
// This wakelock may have time-out, if a timeout was specified.
|
||||
// Catch (and ignore) any timeout exceptions.
|
||||
try {
|
||||
mDownloadXtraWakeLock.release();
|
||||
if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
|
||||
} catch (Exception e) {
|
||||
Log.i(TAG, "Wakelock timeout & release race exception in "
|
||||
+ "handleDownloadXtraData()", e);
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "WakeLock expired before release in "
|
||||
+ "handleDownloadXtraData()");
|
||||
// Release wake lock held by task, synchronize on mLock in case multiple
|
||||
// download tasks overrun.
|
||||
synchronized (mLock) {
|
||||
if (mDownloadXtraWakeLock.isHeld()) {
|
||||
// This wakelock may have time-out, if a timeout was specified.
|
||||
// Catch (and ignore) any timeout exceptions.
|
||||
try {
|
||||
mDownloadXtraWakeLock.release();
|
||||
if (DEBUG) Log.d(TAG, "WakeLock released by handleDownloadXtraData()");
|
||||
} catch (Exception e) {
|
||||
Log.i(TAG, "Wakelock timeout & release race exception in "
|
||||
+ "handleDownloadXtraData()", e);
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "WakeLock expired before release in "
|
||||
+ "handleDownloadXtraData()");
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -954,21 +962,6 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables this provider. When enabled, calls to getStatus()
|
||||
* must be handled. Hardware may be started up
|
||||
* when the provider is enabled.
|
||||
*/
|
||||
@Override
|
||||
public void enable() {
|
||||
synchronized (mLock) {
|
||||
if (mEnabled) return;
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
sendMessage(ENABLE, 1, null);
|
||||
}
|
||||
|
||||
private void setSuplHostPort(String hostString, String portString) {
|
||||
if (hostString != null) {
|
||||
mSuplServerHost = hostString;
|
||||
@@ -1052,21 +1045,6 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables this provider. When disabled, calls to getStatus()
|
||||
* need not be handled. Hardware may be shut
|
||||
* down while the provider is disabled.
|
||||
*/
|
||||
@Override
|
||||
public void disable() {
|
||||
synchronized (mLock) {
|
||||
if (!mEnabled) return;
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
sendMessage(ENABLE, 0, null);
|
||||
}
|
||||
|
||||
private void handleDisable() {
|
||||
if (DEBUG) Log.d(TAG, "handleDisable");
|
||||
|
||||
@@ -1083,7 +1061,6 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
mGnssNavigationMessageProvider.onGpsEnabledChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
synchronized (mLock) {
|
||||
return mEnabled;
|
||||
@@ -1147,7 +1124,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
updateClientUids(mWorkSource);
|
||||
|
||||
mFixInterval = (int) mProviderRequest.interval;
|
||||
mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
|
||||
mLowPowerMode = mProviderRequest.lowPowerMode;
|
||||
// check for overflow
|
||||
if (mFixInterval != mProviderRequest.interval) {
|
||||
Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
|
||||
@@ -1171,7 +1148,8 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
// set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
|
||||
// and our fix interval is not short
|
||||
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent); }
|
||||
SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateClientUids(new WorkSource());
|
||||
@@ -1220,16 +1198,14 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
List<WorkChain> goneChains = diffs[1];
|
||||
|
||||
if (newChains != null) {
|
||||
for (int i = 0; i < newChains.size(); ++i) {
|
||||
final WorkChain newChain = newChains.get(i);
|
||||
for (WorkChain newChain : newChains) {
|
||||
mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(),
|
||||
newChain.getAttributionTag());
|
||||
}
|
||||
}
|
||||
|
||||
if (goneChains != null) {
|
||||
for (int i = 0; i < goneChains.size(); i++) {
|
||||
final WorkChain goneChain = goneChains.get(i);
|
||||
for (WorkChain goneChain : goneChains) {
|
||||
mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(),
|
||||
goneChain.getAttributionTag());
|
||||
}
|
||||
@@ -1262,32 +1238,27 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
public void sendExtraCommand(String command, Bundle extras) {
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
boolean result = false;
|
||||
|
||||
if ("delete_aiding_data".equals(command)) {
|
||||
result = deleteAidingData(extras);
|
||||
deleteAidingData(extras);
|
||||
} else if ("force_time_injection".equals(command)) {
|
||||
requestUtcTime();
|
||||
result = true;
|
||||
} else if ("force_xtra_injection".equals(command)) {
|
||||
if (mSupportsXtra) {
|
||||
xtraDownloadRequest();
|
||||
result = true;
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "sendExtraCommand: unknown command " + command);
|
||||
}
|
||||
return result;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean deleteAidingData(Bundle extras) {
|
||||
private void deleteAidingData(Bundle extras) {
|
||||
int flags;
|
||||
|
||||
if (extras == null) {
|
||||
@@ -1311,10 +1282,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
|
||||
if (flags != 0) {
|
||||
native_delete_aiding_data(flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startNavigating(boolean singleShot) {
|
||||
@@ -1358,7 +1326,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
|
||||
int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
|
||||
mLowPowerMode = (boolean) mProviderRequest.lowPowerMode;
|
||||
mLowPowerMode = mProviderRequest.lowPowerMode;
|
||||
if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
|
||||
interval, 0, 0, mLowPowerMode)) {
|
||||
mStarted = false;
|
||||
@@ -1415,10 +1383,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
return ((mEngineCapabilities & capability) != 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* called from native code to update our position.
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportLocation(boolean hasLatLong, Location location) {
|
||||
sendMessage(REPORT_LOCATION, hasLatLong ? 1 : 0, location);
|
||||
}
|
||||
@@ -1444,11 +1409,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
|
||||
location.setExtras(mLocationExtras.getBundle());
|
||||
|
||||
try {
|
||||
mILocationManager.reportLocation(location, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException calling reportLocation");
|
||||
}
|
||||
reportLocation(location);
|
||||
|
||||
if (mStarted) {
|
||||
mGnssMetrics.logReceivedLocationStatus(hasLatLong);
|
||||
@@ -1482,7 +1443,8 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
|
||||
if (mStarted && mStatus != LocationProvider.AVAILABLE) {
|
||||
// For devices that use framework scheduling, a timer may be set to ensure we don't
|
||||
// spend too much power searching for a location, when the requested update rate is slow.
|
||||
// spend too much power searching for a location, when the requested update rate is
|
||||
// slow.
|
||||
// As we just recievied a location, we'll cancel that timer.
|
||||
if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
|
||||
mAlarmManager.cancel(mTimeoutIntent);
|
||||
@@ -1502,9 +1464,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to update our status
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportStatus(int status) {
|
||||
if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
|
||||
|
||||
@@ -1512,16 +1472,13 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
switch (status) {
|
||||
case GPS_STATUS_SESSION_BEGIN:
|
||||
mNavigating = true;
|
||||
mEngineOn = true;
|
||||
break;
|
||||
case GPS_STATUS_SESSION_END:
|
||||
mNavigating = false;
|
||||
break;
|
||||
case GPS_STATUS_ENGINE_ON:
|
||||
mEngineOn = true;
|
||||
break;
|
||||
case GPS_STATUS_ENGINE_OFF:
|
||||
mEngineOn = false;
|
||||
mNavigating = false;
|
||||
break;
|
||||
}
|
||||
@@ -1538,17 +1495,15 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
|
||||
// Helper class to carry data to handler for reportSvStatus
|
||||
private static class SvStatusInfo {
|
||||
public int mSvCount;
|
||||
public int[] mSvidWithFlags;
|
||||
public float[] mCn0s;
|
||||
public float[] mSvElevations;
|
||||
public float[] mSvAzimuths;
|
||||
public float[] mSvCarrierFreqs;
|
||||
private int mSvCount;
|
||||
private int[] mSvidWithFlags;
|
||||
private float[] mCn0s;
|
||||
private float[] mSvElevations;
|
||||
private float[] mSvAzimuths;
|
||||
private float[] mSvCarrierFreqs;
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to update SV info
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportSvStatus(int svCount, int[] svidWithFlags, float[] cn0s,
|
||||
float[] svElevations, float[] svAzimuths, float[] svCarrierFreqs) {
|
||||
SvStatusInfo svStatusInfo = new SvStatusInfo();
|
||||
@@ -1622,16 +1577,12 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to update AGPS status
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
|
||||
mNetworkConnectivityHandler.onReportAGpsStatus(type, status, ipaddr);
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to report NMEA data received
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportNmea(long timestamp) {
|
||||
if (!mItarSpeedLimitExceeded) {
|
||||
int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
|
||||
@@ -1640,57 +1591,38 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code - GNSS measurements callback
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportMeasurementData(GnssMeasurementsEvent event) {
|
||||
if (!mItarSpeedLimitExceeded) {
|
||||
// send to handler to allow native to return quickly
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mGnssMeasurementsProvider.onMeasurementsAvailable(event);
|
||||
}
|
||||
});
|
||||
mHandler.post(() -> mGnssMeasurementsProvider.onMeasurementsAvailable(event));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code - GNSS navigation message callback
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportNavigationMessage(GnssNavigationMessage event) {
|
||||
if (!mItarSpeedLimitExceeded) {
|
||||
// send to handler to allow native to return quickly
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
|
||||
}
|
||||
});
|
||||
mHandler.post(() -> mGnssNavigationMessageProvider.onNavigationMessageAvailable(event));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to inform us what the GPS engine capabilities are
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void setEngineCapabilities(final int capabilities) {
|
||||
// send to handler thread for fast native return, and in-order handling
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mEngineCapabilities = capabilities;
|
||||
mHandler.post(() -> {
|
||||
mEngineCapabilities = capabilities;
|
||||
|
||||
if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
|
||||
mNtpTimeHelper.enablePeriodicTimeInjection();
|
||||
requestUtcTime();
|
||||
}
|
||||
|
||||
mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability(
|
||||
GPS_CAPABILITY_MEASUREMENTS));
|
||||
mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability(
|
||||
GPS_CAPABILITY_NAV_MESSAGES));
|
||||
restartRequests();
|
||||
if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
|
||||
mNtpTimeHelper.enablePeriodicTimeInjection();
|
||||
requestUtcTime();
|
||||
}
|
||||
|
||||
mGnssMeasurementsProvider.onCapabilitiesUpdated(hasCapability(
|
||||
GPS_CAPABILITY_MEASUREMENTS));
|
||||
mGnssNavigationMessageProvider.onCapabilitiesUpdated(hasCapability(
|
||||
GPS_CAPABILITY_NAV_MESSAGES));
|
||||
restartRequests();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1710,27 +1642,21 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
updateRequirements();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native code to inform us the hardware year.
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void setGnssYearOfHardware(final int yearOfHardware) {
|
||||
// mHardwareYear is simply set here, to be read elsewhere, and is volatile for safe sync
|
||||
if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
|
||||
mHardwareYear = yearOfHardware;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native code to inform us the hardware model name.
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void setGnssHardwareModelName(final String modelName) {
|
||||
// mHardwareModelName is simply set here, to be read elsewhere, and volatile for safe sync
|
||||
if (DEBUG) Log.d(TAG, "setGnssModelName called with " + modelName);
|
||||
mHardwareModelName = modelName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native code to inform us GNSS HAL service died.
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportGnssServiceDied() {
|
||||
if (DEBUG) Log.d(TAG, "reportGnssServiceDied");
|
||||
mHandler.post(() -> {
|
||||
@@ -1750,6 +1676,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
* Returns the year of underlying GPS hardware.
|
||||
*/
|
||||
int getGnssYearOfHardware();
|
||||
|
||||
/**
|
||||
* Returns the model name of underlying GPS hardware.
|
||||
*/
|
||||
@@ -1765,6 +1692,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
public int getGnssYearOfHardware() {
|
||||
return mHardwareYear;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGnssHardwareModelName() {
|
||||
return mHardwareModelName;
|
||||
@@ -1790,32 +1718,19 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
* @hide
|
||||
*/
|
||||
public GnssMetricsProvider getGnssMetricsProvider() {
|
||||
return new GnssMetricsProvider() {
|
||||
@Override
|
||||
public String getGnssMetricsAsProtoString() {
|
||||
return mGnssMetrics.dumpGnssMetricsAsProtoString();
|
||||
}
|
||||
};
|
||||
return () -> mGnssMetrics.dumpGnssMetricsAsProtoString();
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code - GNSS location batch callback
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportLocationBatch(Location[] locationArray) {
|
||||
List<Location> locations = new ArrayList<>(Arrays.asList(locationArray));
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Location batch of size " + locationArray.length + " reported");
|
||||
}
|
||||
try {
|
||||
mILocationManager.reportLocationBatch(locations);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException calling reportLocationBatch");
|
||||
}
|
||||
reportLocation(locations);
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to request XTRA data
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void xtraDownloadRequest() {
|
||||
if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
|
||||
sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
|
||||
@@ -1843,10 +1758,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native to report GPS Geofence transition
|
||||
* All geofence callbacks are called on the same thread
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportGeofenceTransition(int geofenceId, Location location, int transition,
|
||||
long transitionTimestamp) {
|
||||
mHandler.post(() -> {
|
||||
@@ -1864,9 +1776,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code to report GPS status change.
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportGeofenceStatus(int status, Location location) {
|
||||
mHandler.post(() -> {
|
||||
if (mGeofenceHardwareImpl == null) {
|
||||
@@ -1884,9 +1794,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code - Geofence Add callback
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportGeofenceAddStatus(int geofenceId, int status) {
|
||||
mHandler.post(() -> {
|
||||
if (mGeofenceHardwareImpl == null) {
|
||||
@@ -1896,9 +1804,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code - Geofence Remove callback
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportGeofenceRemoveStatus(int geofenceId, int status) {
|
||||
mHandler.post(() -> {
|
||||
if (mGeofenceHardwareImpl == null) {
|
||||
@@ -1908,9 +1814,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code - Geofence Pause callback
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportGeofencePauseStatus(int geofenceId, int status) {
|
||||
mHandler.post(() -> {
|
||||
if (mGeofenceHardwareImpl == null) {
|
||||
@@ -1920,9 +1824,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* called from native code - Geofence Resume callback
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void reportGeofenceResumeStatus(int geofenceId, int status) {
|
||||
mHandler.post(() -> {
|
||||
if (mGeofenceHardwareImpl == null) {
|
||||
@@ -1954,7 +1856,8 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
return mNetInitiatedListener;
|
||||
}
|
||||
|
||||
// Called by JNI function to report an NI request.
|
||||
/** Reports a NI notification. */
|
||||
@NativeEntryPoint
|
||||
public void reportNiNotification(
|
||||
int notificationId,
|
||||
int niType,
|
||||
@@ -1997,11 +1900,10 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native code to request set id info.
|
||||
* We should be careful about receiving null string from the TelephonyManager,
|
||||
* because sending null String to JNI function would cause a crash.
|
||||
*/
|
||||
|
||||
@NativeEntryPoint
|
||||
private void requestSetID(int flags) {
|
||||
TelephonyManager phone = (TelephonyManager)
|
||||
mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
@@ -2030,9 +1932,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
native_agps_set_id(type, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native code to request location info.
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void requestLocation(boolean independentFromGnss) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "requestLocation. independentFromGnss: " + independentFromGnss);
|
||||
@@ -2040,17 +1940,13 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
sendMessage(REQUEST_LOCATION, 0, independentFromGnss);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native code to request utc time info
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void requestUtcTime() {
|
||||
if (DEBUG) Log.d(TAG, "utcTimeRequest");
|
||||
sendMessage(INJECT_NTP_TIME, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from native code to request reference location info
|
||||
*/
|
||||
@NativeEntryPoint
|
||||
private void requestRefLocation() {
|
||||
TelephonyManager phone = (TelephonyManager)
|
||||
mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
@@ -2104,11 +2000,7 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
int message = msg.what;
|
||||
switch (message) {
|
||||
case ENABLE:
|
||||
if (msg.arg1 == 1) {
|
||||
handleEnable();
|
||||
} else {
|
||||
handleDisable();
|
||||
}
|
||||
handleEnable();
|
||||
break;
|
||||
case SET_REQUEST:
|
||||
GpsRequest gpsRequest = (GpsRequest) msg.obj;
|
||||
@@ -2153,7 +2045,8 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
|
||||
* This method is bound to {@link #GnssLocationProvider(Context, LocationProviderManager,
|
||||
* Looper)}.
|
||||
* It is in charge of loading properties and registering for events that will be posted to
|
||||
* this handler.
|
||||
*/
|
||||
@@ -2206,12 +2099,11 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
|
||||
long minTime = 0;
|
||||
float minDistance = 0;
|
||||
boolean oneShot = false;
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
|
||||
LocationManager.PASSIVE_PROVIDER,
|
||||
minTime,
|
||||
minDistance,
|
||||
oneShot);
|
||||
false);
|
||||
// Don't keep track of this request since it's done on behalf of other clients
|
||||
// (which are kept track of separately).
|
||||
request.setHideFromAppOps(true);
|
||||
@@ -2219,11 +2111,14 @@ public class GnssLocationProvider extends LocationProviderInterface
|
||||
request,
|
||||
new NetworkLocationListener(),
|
||||
getLooper());
|
||||
|
||||
// enable gps provider, it will never be disabled (legacy behavior)
|
||||
sendEmptyMessage(ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class LocationChangeListener implements LocationListener {
|
||||
int numLocationUpdateRequest;
|
||||
private int mNumLocationUpdateRequest;
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import android.location.LocationProvider;
|
||||
import android.os.Bundle;
|
||||
import android.os.WorkSource;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Location Manager's interface for location providers.
|
||||
* @hide
|
||||
*/
|
||||
public abstract class LocationProviderInterface {
|
||||
|
||||
/** Get name. */
|
||||
public abstract String getName();
|
||||
|
||||
/** Enable. */
|
||||
public abstract void enable();
|
||||
|
||||
/** Disable. */
|
||||
public abstract void disable();
|
||||
|
||||
/** Is enabled. */
|
||||
public abstract boolean isEnabled();
|
||||
|
||||
/** Set request. */
|
||||
public abstract void setRequest(ProviderRequest request, WorkSource source);
|
||||
|
||||
/** dump. */
|
||||
public abstract void dump(FileDescriptor fd, PrintWriter pw, String[] args);
|
||||
|
||||
/** Get properties. */
|
||||
public abstract ProviderProperties getProperties();
|
||||
|
||||
/**
|
||||
* Get status.
|
||||
*
|
||||
* @deprecated Will be removed in a future release.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getStatus(Bundle extras) {
|
||||
return LocationProvider.AVAILABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status update time.
|
||||
*
|
||||
* @deprecated Will be removed in a future release.
|
||||
*/
|
||||
@Deprecated
|
||||
public long getStatusUpdateTime() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Send extra command. */
|
||||
public abstract boolean sendExtraCommand(String command, Bundle extras);
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package com.android.server.location;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationProvider;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
@@ -27,6 +28,7 @@ import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.location.ILocationProvider;
|
||||
import com.android.internal.location.ILocationProviderManager;
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
@@ -41,21 +43,35 @@ import java.io.PrintWriter;
|
||||
/**
|
||||
* Proxy for ILocationProvider implementations.
|
||||
*/
|
||||
public class LocationProviderProxy extends LocationProviderInterface {
|
||||
public class LocationProviderProxy extends AbstractLocationProvider {
|
||||
|
||||
private static final String TAG = "LocationProviderProxy";
|
||||
private static final boolean D = LocationManagerService.D;
|
||||
|
||||
private final ServiceWatcher mServiceWatcher;
|
||||
|
||||
private final String mName;
|
||||
|
||||
// used to ensure that updates to mRequest and mWorkSource are atomic
|
||||
private final Object mRequestLock = new Object();
|
||||
|
||||
private final ServiceWatcher mServiceWatcher;
|
||||
|
||||
private volatile boolean mEnabled = false;
|
||||
@Nullable
|
||||
private volatile ProviderProperties mProperties;
|
||||
private final ILocationProviderManager.Stub mManager = new ILocationProviderManager.Stub() {
|
||||
// executed on binder thread
|
||||
@Override
|
||||
public void onSetEnabled(boolean enabled) {
|
||||
LocationProviderProxy.this.setEnabled(enabled);
|
||||
}
|
||||
|
||||
// executed on binder thread
|
||||
@Override
|
||||
public void onSetProperties(ProviderProperties properties) {
|
||||
LocationProviderProxy.this.setProperties(properties);
|
||||
}
|
||||
|
||||
// executed on binder thread
|
||||
@Override
|
||||
public void onReportLocation(Location location) {
|
||||
LocationProviderProxy.this.reportLocation(location);
|
||||
}
|
||||
};
|
||||
|
||||
@GuardedBy("mRequestLock")
|
||||
@Nullable
|
||||
@@ -69,10 +85,10 @@ public class LocationProviderProxy extends LocationProviderInterface {
|
||||
*/
|
||||
@Nullable
|
||||
public static LocationProviderProxy createAndBind(
|
||||
Context context, String name, String action,
|
||||
Context context, LocationProviderManager locationProviderManager, String action,
|
||||
int overlaySwitchResId, int defaultServicePackageNameResId,
|
||||
int initialPackageNamesResId) {
|
||||
LocationProviderProxy proxy = new LocationProviderProxy(context, name,
|
||||
LocationProviderProxy proxy = new LocationProviderProxy(context, locationProviderManager,
|
||||
action, overlaySwitchResId, defaultServicePackageNameResId,
|
||||
initialPackageNamesResId);
|
||||
if (proxy.bind()) {
|
||||
@@ -82,21 +98,27 @@ public class LocationProviderProxy extends LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
private LocationProviderProxy(Context context, String name,
|
||||
private LocationProviderProxy(Context context, LocationProviderManager locationProviderManager,
|
||||
String action, int overlaySwitchResId, int defaultServicePackageNameResId,
|
||||
int initialPackageNamesResId) {
|
||||
super(locationProviderManager, false);
|
||||
|
||||
mServiceWatcher = new ServiceWatcher(context, TAG, action, overlaySwitchResId,
|
||||
defaultServicePackageNameResId, initialPackageNamesResId,
|
||||
BackgroundThread.getHandler()) {
|
||||
|
||||
@Override
|
||||
protected void onBind() {
|
||||
runOnBinder(LocationProviderProxy.this::initializeService);
|
||||
}
|
||||
};
|
||||
mName = name;
|
||||
|
||||
mProperties = null;
|
||||
@Override
|
||||
protected void onUnbind() {
|
||||
setEnabled(false);
|
||||
setProperties(null);
|
||||
}
|
||||
};
|
||||
|
||||
mRequest = null;
|
||||
mWorkSource = new WorkSource();
|
||||
}
|
||||
@@ -107,83 +129,26 @@ public class LocationProviderProxy extends LocationProviderInterface {
|
||||
|
||||
private void initializeService(IBinder binder) {
|
||||
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
|
||||
if (D) Log.d(TAG, "applying state to connected service");
|
||||
|
||||
ProviderProperties[] properties = new ProviderProperties[1];
|
||||
ProviderRequest request;
|
||||
WorkSource source;
|
||||
synchronized (mRequestLock) {
|
||||
request = mRequest;
|
||||
source = mWorkSource;
|
||||
}
|
||||
if (D) Log.d(TAG, "applying state to connected service " + mServiceWatcher);
|
||||
|
||||
try {
|
||||
// load properties from provider
|
||||
properties[0] = service.getProperties();
|
||||
if (properties[0] == null) {
|
||||
Log.e(TAG, mServiceWatcher.getCurrentPackageName()
|
||||
+ " has invalid location provider properties");
|
||||
}
|
||||
service.setLocationProviderManager(mManager);
|
||||
|
||||
// apply current state to new service
|
||||
if (mEnabled) {
|
||||
service.enable();
|
||||
if (request != null) {
|
||||
service.setRequest(request, source);
|
||||
synchronized (mRequestLock) {
|
||||
if (mRequest != null) {
|
||||
service.setRequest(mRequest, mWorkSource);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
mProperties = properties[0];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getConnectedPackageName() {
|
||||
return mServiceWatcher.getCurrentPackageName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return mProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
mEnabled = true;
|
||||
mServiceWatcher.runOnBinder(binder -> {
|
||||
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
|
||||
try {
|
||||
service.enable();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
mEnabled = false;
|
||||
mServiceWatcher.runOnBinder(binder -> {
|
||||
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
|
||||
try {
|
||||
service.disable();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource source) {
|
||||
synchronized (mRequestLock) {
|
||||
@@ -202,60 +167,53 @@ public class LocationProviderProxy extends LocationProviderInterface {
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.append("REMOTE SERVICE");
|
||||
pw.append(" name=").append(mName);
|
||||
pw.append(" pkg=").append(mServiceWatcher.getCurrentPackageName());
|
||||
pw.append(" version=").append(Integer.toString(mServiceWatcher.getCurrentPackageVersion()));
|
||||
pw.append('\n');
|
||||
pw.println(" service=" + mServiceWatcher);
|
||||
mServiceWatcher.runOnBinder(binder -> {
|
||||
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
|
||||
try {
|
||||
TransferPipe.dumpAsync(service.asBinder(), fd, args);
|
||||
TransferPipe.dumpAsync(binder, fd, args);
|
||||
} catch (IOException | RemoteException e) {
|
||||
pw.println("Failed to dump location provider: " + e);
|
||||
pw.println(" failed to dump location provider: " + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
int[] result = new int[]{LocationProvider.TEMPORARILY_UNAVAILABLE};
|
||||
int[] status = new int[] {LocationProvider.TEMPORARILY_UNAVAILABLE};
|
||||
mServiceWatcher.runOnBinder(binder -> {
|
||||
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
|
||||
try {
|
||||
result[0] = service.getStatus(extras);
|
||||
status[0] = service.getStatus(extras);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
});
|
||||
return result[0];
|
||||
return status[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
long[] result = new long[]{0L};
|
||||
long[] updateTime = new long[] {0L};
|
||||
mServiceWatcher.runOnBinder(binder -> {
|
||||
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
|
||||
try {
|
||||
result[0] = service.getStatusUpdateTime();
|
||||
updateTime[0] = service.getStatusUpdateTime();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
});
|
||||
return result[0];
|
||||
return updateTime[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
boolean[] result = new boolean[]{false};
|
||||
public void sendExtraCommand(String command, Bundle extras) {
|
||||
mServiceWatcher.runOnBinder(binder -> {
|
||||
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
|
||||
try {
|
||||
result[0] = service.sendExtraCommand(command, extras);
|
||||
service.sendExtraCommand(command, extras);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
});
|
||||
return result[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,11 @@
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import android.location.ILocationManager;
|
||||
import android.annotation.Nullable;
|
||||
import android.location.Location;
|
||||
import android.location.LocationProvider;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
import android.util.PrintWriterPrinter;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
@@ -36,62 +33,56 @@ import java.io.PrintWriter;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class MockProvider extends LocationProviderInterface {
|
||||
private final String mName;
|
||||
private final ProviderProperties mProperties;
|
||||
private final ILocationManager mLocationManager;
|
||||
public class MockProvider extends AbstractLocationProvider {
|
||||
|
||||
private final Location mLocation;
|
||||
|
||||
private boolean mHasLocation;
|
||||
private boolean mEnabled;
|
||||
|
||||
|
||||
@Nullable private Location mLocation;
|
||||
private int mStatus;
|
||||
private long mStatusUpdateTime;
|
||||
private Bundle mExtras;
|
||||
|
||||
private static final String TAG = "MockProvider";
|
||||
public MockProvider(
|
||||
LocationProviderManager locationProviderManager, ProviderProperties properties) {
|
||||
super(locationProviderManager, true);
|
||||
|
||||
public MockProvider(String name, ILocationManager locationManager,
|
||||
ProviderProperties properties) {
|
||||
if (properties == null) throw new NullPointerException("properties is null");
|
||||
|
||||
mName = name;
|
||||
mLocationManager = locationManager;
|
||||
mProperties = properties;
|
||||
mLocation = new Location(name);
|
||||
|
||||
mStatus = LocationProvider.AVAILABLE;
|
||||
mStatusUpdateTime = 0L;
|
||||
mExtras = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return mProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
mEnabled = true;
|
||||
mLocation = null;
|
||||
mStatus = LocationProvider.AVAILABLE;
|
||||
mStatusUpdateTime = 0;
|
||||
mExtras = null;
|
||||
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
/** Sets the enabled state of this mock provider. */
|
||||
public void setEnabled(boolean enabled) {
|
||||
mEnabled = enabled;
|
||||
super.setEnabled(enabled);
|
||||
}
|
||||
|
||||
/** Sets the location to report for this mock provider. */
|
||||
public void setLocation(Location l) {
|
||||
mLocation = new Location(l);
|
||||
if (mEnabled) {
|
||||
reportLocation(l);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the status for this mock provider. */
|
||||
public void setStatus(int status, Bundle extras, long updateTime) {
|
||||
mStatus = status;
|
||||
mStatusUpdateTime = updateTime;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(" last location=" + mLocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource source) {}
|
||||
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
if (mExtras != null) {
|
||||
@@ -107,50 +98,6 @@ public class MockProvider extends LocationProviderInterface {
|
||||
return mStatusUpdateTime;
|
||||
}
|
||||
|
||||
public void setLocation(Location l) {
|
||||
mLocation.set(l);
|
||||
mHasLocation = true;
|
||||
if (mEnabled) {
|
||||
try {
|
||||
mLocationManager.reportLocation(mLocation, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException calling reportLocation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clearLocation() {
|
||||
mHasLocation = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Will be removed in a future release.
|
||||
*/
|
||||
@Deprecated
|
||||
public void setStatus(int status, Bundle extras, long updateTime) {
|
||||
mStatus = status;
|
||||
mStatusUpdateTime = updateTime;
|
||||
mExtras = extras;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
dump(pw, "");
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
pw.println(prefix + mName);
|
||||
pw.println(prefix + "mHasLocation=" + mHasLocation);
|
||||
pw.println(prefix + "mLocation:");
|
||||
mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
|
||||
pw.println(prefix + "mExtras=" + mExtras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource source) { }
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
return false;
|
||||
}
|
||||
public void sendExtraCommand(String command, Bundle extras) {}
|
||||
}
|
||||
|
||||
@@ -17,13 +17,9 @@
|
||||
package com.android.server.location;
|
||||
|
||||
import android.location.Criteria;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
@@ -38,41 +34,20 @@ import java.io.PrintWriter;
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class PassiveProvider extends LocationProviderInterface {
|
||||
private static final String TAG = "PassiveProvider";
|
||||
public class PassiveProvider extends AbstractLocationProvider {
|
||||
|
||||
private static final ProviderProperties PROPERTIES = new ProviderProperties(
|
||||
false, false, false, false, false, false, false,
|
||||
Criteria.POWER_LOW, Criteria.ACCURACY_COARSE);
|
||||
|
||||
private final ILocationManager mLocationManager;
|
||||
private boolean mReportLocation;
|
||||
|
||||
public PassiveProvider(ILocationManager locationManager) {
|
||||
mLocationManager = locationManager;
|
||||
}
|
||||
public PassiveProvider(LocationProviderManager locationProviderManager) {
|
||||
super(locationProviderManager, true);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return LocationManager.PASSIVE_PROVIDER;
|
||||
}
|
||||
mReportLocation = false;
|
||||
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return PROPERTIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
setProperties(PROPERTIES);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,22 +57,15 @@ public class PassiveProvider extends LocationProviderInterface {
|
||||
|
||||
public void updateLocation(Location location) {
|
||||
if (mReportLocation) {
|
||||
try {
|
||||
// pass the location back to the location manager
|
||||
mLocationManager.reportLocation(location, true);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException calling reportLocation");
|
||||
}
|
||||
reportLocation(location);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
return false;
|
||||
}
|
||||
public void sendExtraCommand(String command, Bundle extras) {}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println("mReportLocation=" + mReportLocation);
|
||||
pw.println(" report location=" + mReportLocation);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user