Merge "Add ADAS GNSS bypass functionality" into sc-dev am: 9490b84d13 am: fe6e9674ea
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14681780 Change-Id: Ibecf6c1edbed7a64ec210fc031f46f16668b47ab
This commit is contained in:
@@ -1706,6 +1706,10 @@
|
|||||||
config_enableFusedLocationOverlay is false. -->
|
config_enableFusedLocationOverlay is false. -->
|
||||||
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
|
<string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
|
||||||
|
|
||||||
|
<!-- Default value for the ADAS GNSS Location Enabled setting if this setting has never been
|
||||||
|
set before. -->
|
||||||
|
<bool name="config_defaultAdasGnssLocationEnabled" translatable="false">false</bool>
|
||||||
|
|
||||||
<string-array name="config_locationExtraPackageNames" translatable="false"></string-array>
|
<string-array name="config_locationExtraPackageNames" translatable="false"></string-array>
|
||||||
|
|
||||||
<!-- The package name of the default network recommendation app.
|
<!-- The package name of the default network recommendation app.
|
||||||
|
|||||||
@@ -1918,6 +1918,7 @@
|
|||||||
<java-symbol type="bool" name="config_tintNotificationActionButtons" />
|
<java-symbol type="bool" name="config_tintNotificationActionButtons" />
|
||||||
<java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
|
<java-symbol type="bool" name="config_dozeAfterScreenOffByDefault" />
|
||||||
<java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
|
<java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
|
||||||
|
<java-symbol type="bool" name="config_defaultAdasGnssLocationEnabled" />
|
||||||
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
|
<java-symbol type="bool" name="config_enableFusedLocationOverlay" />
|
||||||
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
|
<java-symbol type="bool" name="config_enableGeocoderOverlay" />
|
||||||
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
|
<java-symbol type="bool" name="config_enableGeofenceOverlay" />
|
||||||
|
|||||||
@@ -122,6 +122,9 @@ interface ILocationManager
|
|||||||
boolean isLocationEnabledForUser(int userId);
|
boolean isLocationEnabledForUser(int userId);
|
||||||
void setLocationEnabledForUser(boolean enabled, int userId);
|
void setLocationEnabledForUser(boolean enabled, int userId);
|
||||||
|
|
||||||
|
boolean isAdasGnssLocationEnabledForUser(int userId);
|
||||||
|
void setAdasGnssLocationEnabledForUser(boolean enabled, int userId);
|
||||||
|
|
||||||
void addTestProvider(String name, in ProviderProperties properties,
|
void addTestProvider(String name, in ProviderProperties properties,
|
||||||
in List<String> locationTags, String packageName, @nullable String attributionTag);
|
in List<String> locationTags, String packageName, @nullable String attributionTag);
|
||||||
void removeTestProvider(String provider, String packageName, @nullable String attributionTag);
|
void removeTestProvider(String provider, String packageName, @nullable String attributionTag);
|
||||||
|
|||||||
@@ -34,12 +34,15 @@ import java.util.Objects;
|
|||||||
public final class LastLocationRequest implements Parcelable {
|
public final class LastLocationRequest implements Parcelable {
|
||||||
|
|
||||||
private final boolean mHiddenFromAppOps;
|
private final boolean mHiddenFromAppOps;
|
||||||
|
private final boolean mAdasGnssBypass;
|
||||||
private final boolean mLocationSettingsIgnored;
|
private final boolean mLocationSettingsIgnored;
|
||||||
|
|
||||||
private LastLocationRequest(
|
private LastLocationRequest(
|
||||||
boolean hiddenFromAppOps,
|
boolean hiddenFromAppOps,
|
||||||
|
boolean adasGnssBypass,
|
||||||
boolean locationSettingsIgnored) {
|
boolean locationSettingsIgnored) {
|
||||||
mHiddenFromAppOps = hiddenFromAppOps;
|
mHiddenFromAppOps = hiddenFromAppOps;
|
||||||
|
mAdasGnssBypass = adasGnssBypass;
|
||||||
mLocationSettingsIgnored = locationSettingsIgnored;
|
mLocationSettingsIgnored = locationSettingsIgnored;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,6 +58,21 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
return mHiddenFromAppOps;
|
return mHiddenFromAppOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this request may access GNSS even if location settings would normally deny
|
||||||
|
* this, in order to enable automotive safety features. This field is only respected on
|
||||||
|
* automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
|
||||||
|
* Driving Assistance Systems) application.
|
||||||
|
*
|
||||||
|
* @return true if all limiting factors will be ignored to satisfy GNSS request
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
// TODO: make this system api
|
||||||
|
public boolean isAdasGnssBypass() {
|
||||||
|
return mAdasGnssBypass;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if location settings, throttling, background location limits, and any other
|
* Returns true if location settings, throttling, background location limits, and any other
|
||||||
* possible limiting factors will be ignored in order to satisfy this last location request.
|
* possible limiting factors will be ignored in order to satisfy this last location request.
|
||||||
@@ -65,12 +83,22 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
return mLocationSettingsIgnored;
|
return mLocationSettingsIgnored;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if any bypass flag is set on this request. For internal use only.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean isBypass() {
|
||||||
|
return mAdasGnssBypass || mLocationSettingsIgnored;
|
||||||
|
}
|
||||||
|
|
||||||
public static final @NonNull Parcelable.Creator<LastLocationRequest> CREATOR =
|
public static final @NonNull Parcelable.Creator<LastLocationRequest> CREATOR =
|
||||||
new Parcelable.Creator<LastLocationRequest>() {
|
new Parcelable.Creator<LastLocationRequest>() {
|
||||||
@Override
|
@Override
|
||||||
public LastLocationRequest createFromParcel(Parcel in) {
|
public LastLocationRequest createFromParcel(Parcel in) {
|
||||||
return new LastLocationRequest(
|
return new LastLocationRequest(
|
||||||
/* hiddenFromAppOps= */ in.readBoolean(),
|
/* hiddenFromAppOps= */ in.readBoolean(),
|
||||||
|
/* adasGnssBypass= */ in.readBoolean(),
|
||||||
/* locationSettingsIgnored= */ in.readBoolean());
|
/* locationSettingsIgnored= */ in.readBoolean());
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
@@ -86,6 +114,7 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
@Override
|
@Override
|
||||||
public void writeToParcel(@NonNull Parcel parcel, int flags) {
|
public void writeToParcel(@NonNull Parcel parcel, int flags) {
|
||||||
parcel.writeBoolean(mHiddenFromAppOps);
|
parcel.writeBoolean(mHiddenFromAppOps);
|
||||||
|
parcel.writeBoolean(mAdasGnssBypass);
|
||||||
parcel.writeBoolean(mLocationSettingsIgnored);
|
parcel.writeBoolean(mLocationSettingsIgnored);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,12 +128,13 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
}
|
}
|
||||||
LastLocationRequest that = (LastLocationRequest) o;
|
LastLocationRequest that = (LastLocationRequest) o;
|
||||||
return mHiddenFromAppOps == that.mHiddenFromAppOps
|
return mHiddenFromAppOps == that.mHiddenFromAppOps
|
||||||
|
&& mAdasGnssBypass == that.mAdasGnssBypass
|
||||||
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored;
|
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(mHiddenFromAppOps, mLocationSettingsIgnored);
|
return Objects.hash(mHiddenFromAppOps, mAdasGnssBypass, mLocationSettingsIgnored);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@@ -115,8 +145,11 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
if (mHiddenFromAppOps) {
|
if (mHiddenFromAppOps) {
|
||||||
s.append("hiddenFromAppOps, ");
|
s.append("hiddenFromAppOps, ");
|
||||||
}
|
}
|
||||||
|
if (mAdasGnssBypass) {
|
||||||
|
s.append("adasGnssBypass, ");
|
||||||
|
}
|
||||||
if (mLocationSettingsIgnored) {
|
if (mLocationSettingsIgnored) {
|
||||||
s.append("locationSettingsIgnored, ");
|
s.append("settingsBypass, ");
|
||||||
}
|
}
|
||||||
if (s.length() > "LastLocationRequest[".length()) {
|
if (s.length() > "LastLocationRequest[".length()) {
|
||||||
s.setLength(s.length() - 2);
|
s.setLength(s.length() - 2);
|
||||||
@@ -131,6 +164,7 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
|
|
||||||
private boolean mHiddenFromAppOps;
|
private boolean mHiddenFromAppOps;
|
||||||
|
private boolean mAdasGnssBypass;
|
||||||
private boolean mLocationSettingsIgnored;
|
private boolean mLocationSettingsIgnored;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,6 +172,7 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
public Builder() {
|
public Builder() {
|
||||||
mHiddenFromAppOps = false;
|
mHiddenFromAppOps = false;
|
||||||
|
mAdasGnssBypass = false;
|
||||||
mLocationSettingsIgnored = false;
|
mLocationSettingsIgnored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +181,7 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
*/
|
*/
|
||||||
public Builder(@NonNull LastLocationRequest lastLocationRequest) {
|
public Builder(@NonNull LastLocationRequest lastLocationRequest) {
|
||||||
mHiddenFromAppOps = lastLocationRequest.mHiddenFromAppOps;
|
mHiddenFromAppOps = lastLocationRequest.mHiddenFromAppOps;
|
||||||
|
mAdasGnssBypass = lastLocationRequest.mAdasGnssBypass;
|
||||||
mLocationSettingsIgnored = lastLocationRequest.mLocationSettingsIgnored;
|
mLocationSettingsIgnored = lastLocationRequest.mLocationSettingsIgnored;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,6 +199,25 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, indicates that the client is an ADAS (Advanced Driving Assistance
|
||||||
|
* Systems) client, which requires access to GNSS even if location settings would normally
|
||||||
|
* deny this, in order to enable auto safety features. This field is only respected on
|
||||||
|
* automotive devices, and only if the client is recognized as a legitimate ADAS
|
||||||
|
* application. Defaults to false.
|
||||||
|
*
|
||||||
|
* <p>Permissions enforcement occurs when resulting location request is actually used, not
|
||||||
|
* when this method is invoked.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
// TODO: make this system api
|
||||||
|
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||||
|
public @NonNull LastLocationRequest.Builder setAdasGnssBypass(boolean adasGnssBypass) {
|
||||||
|
mAdasGnssBypass = adasGnssBypass;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to true, indicates that location settings, throttling, background location limits,
|
* If set to true, indicates that location settings, throttling, background location limits,
|
||||||
* and any other possible limiting factors should be ignored in order to satisfy this
|
* and any other possible limiting factors should be ignored in order to satisfy this
|
||||||
@@ -186,6 +241,7 @@ public final class LastLocationRequest implements Parcelable {
|
|||||||
public @NonNull LastLocationRequest build() {
|
public @NonNull LastLocationRequest build() {
|
||||||
return new LastLocationRequest(
|
return new LastLocationRequest(
|
||||||
mHiddenFromAppOps,
|
mHiddenFromAppOps,
|
||||||
|
mAdasGnssBypass,
|
||||||
mLocationSettingsIgnored);
|
mLocationSettingsIgnored);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -314,6 +314,33 @@ public class LocationManager {
|
|||||||
*/
|
*/
|
||||||
public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
|
public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast intent action when the ADAS (Advanced Driving Assistance Systems) GNSS location
|
||||||
|
* enabled state changes. Includes a boolean intent extra, {@link #EXTRA_ADAS_GNSS_ENABLED},
|
||||||
|
* with the enabled state of ADAS GNSS location. This broadcast only has meaning on automotive
|
||||||
|
* devices.
|
||||||
|
*
|
||||||
|
* @see #EXTRA_ADAS_GNSS_ENABLED
|
||||||
|
* @see #isAdasGnssLocationEnabled()
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
// TODO: @SystemApi
|
||||||
|
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||||
|
public static final String ACTION_ADAS_GNSS_ENABLED_CHANGED =
|
||||||
|
"android.location.action.ADAS_GNSS_ENABLED_CHANGED";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intent extra included with {@link #ACTION_ADAS_GNSS_ENABLED_CHANGED} broadcasts, containing
|
||||||
|
* the boolean enabled state of ADAS GNSS location.
|
||||||
|
*
|
||||||
|
* @see #ACTION_ADAS_GNSS_ENABLED_CHANGED
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
// TODO: @SystemApi
|
||||||
|
public static final String EXTRA_ADAS_GNSS_ENABLED = "android.location.extra.ADAS_GNSS_ENABLED";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast intent action indicating that a high power location requests
|
* Broadcast intent action indicating that a high power location requests
|
||||||
* has either started or stopped being active. The current state of
|
* has either started or stopped being active. The current state of
|
||||||
@@ -620,6 +647,42 @@ public class LocationManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current enabled/disabled state of ADAS (Advanced Driving Assistance Systems)
|
||||||
|
* GNSS location access for the given user. This controls safety critical automotive access to
|
||||||
|
* GNSS location. This only has meaning on automotive devices.
|
||||||
|
*
|
||||||
|
* @return true if ADAS location is enabled and false if ADAS location is disabled.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
//TODO: @SystemApi
|
||||||
|
public boolean isAdasGnssLocationEnabled() {
|
||||||
|
try {
|
||||||
|
return mService.isAdasGnssLocationEnabledForUser(mContext.getUser().getIdentifier());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables or disables ADAS (Advanced Driving Assistance Systems) GNSS location access for the
|
||||||
|
* given user. This only has meaning on automotive devices.
|
||||||
|
*
|
||||||
|
* @param enabled true to enable ADAS location and false to disable ADAS location.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
// TODO: @SystemApi
|
||||||
|
@RequiresPermission(WRITE_SECURE_SETTINGS)
|
||||||
|
public void setAdasGnssLocationEnabled(boolean enabled) {
|
||||||
|
try {
|
||||||
|
mService.setAdasGnssLocationEnabledForUser(enabled, mContext.getUser().getIdentifier());
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
throw e.rethrowFromSystemServer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the current enabled/disabled status of the given provider. To listen for changes, see
|
* Returns the current enabled/disabled status of the given provider. To listen for changes, see
|
||||||
* {@link #PROVIDERS_CHANGED_ACTION}.
|
* {@link #PROVIDERS_CHANGED_ACTION}.
|
||||||
|
|||||||
@@ -194,6 +194,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
private float mMinUpdateDistanceMeters;
|
private float mMinUpdateDistanceMeters;
|
||||||
private final long mMaxUpdateDelayMillis;
|
private final long mMaxUpdateDelayMillis;
|
||||||
private boolean mHideFromAppOps;
|
private boolean mHideFromAppOps;
|
||||||
|
private final boolean mAdasGnssBypass;
|
||||||
private boolean mLocationSettingsIgnored;
|
private boolean mLocationSettingsIgnored;
|
||||||
private boolean mLowPower;
|
private boolean mLowPower;
|
||||||
private @Nullable WorkSource mWorkSource;
|
private @Nullable WorkSource mWorkSource;
|
||||||
@@ -236,7 +237,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
|
if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
|
||||||
quality = POWER_NONE;
|
quality = POWER_NONE;
|
||||||
} else if (LocationManager.GPS_PROVIDER.equals(provider)) {
|
} else if (LocationManager.GPS_PROVIDER.equals(provider)) {
|
||||||
quality = ACCURACY_FINE;
|
quality = QUALITY_HIGH_ACCURACY;
|
||||||
} else {
|
} else {
|
||||||
quality = POWER_LOW;
|
quality = POWER_LOW;
|
||||||
}
|
}
|
||||||
@@ -289,6 +290,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
float minUpdateDistanceMeters,
|
float minUpdateDistanceMeters,
|
||||||
long maxUpdateDelayMillis,
|
long maxUpdateDelayMillis,
|
||||||
boolean hiddenFromAppOps,
|
boolean hiddenFromAppOps,
|
||||||
|
boolean adasGnssBypass,
|
||||||
boolean locationSettingsIgnored,
|
boolean locationSettingsIgnored,
|
||||||
boolean lowPower,
|
boolean lowPower,
|
||||||
WorkSource workSource) {
|
WorkSource workSource) {
|
||||||
@@ -302,8 +304,9 @@ public final class LocationRequest implements Parcelable {
|
|||||||
mMinUpdateDistanceMeters = minUpdateDistanceMeters;
|
mMinUpdateDistanceMeters = minUpdateDistanceMeters;
|
||||||
mMaxUpdateDelayMillis = maxUpdateDelayMillis;
|
mMaxUpdateDelayMillis = maxUpdateDelayMillis;
|
||||||
mHideFromAppOps = hiddenFromAppOps;
|
mHideFromAppOps = hiddenFromAppOps;
|
||||||
mLowPower = lowPower;
|
mAdasGnssBypass = adasGnssBypass;
|
||||||
mLocationSettingsIgnored = locationSettingsIgnored;
|
mLocationSettingsIgnored = locationSettingsIgnored;
|
||||||
|
mLowPower = lowPower;
|
||||||
mWorkSource = Objects.requireNonNull(workSource);
|
mWorkSource = Objects.requireNonNull(workSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,15 +342,15 @@ public final class LocationRequest implements Parcelable {
|
|||||||
switch (quality) {
|
switch (quality) {
|
||||||
case POWER_HIGH:
|
case POWER_HIGH:
|
||||||
// fall through
|
// fall through
|
||||||
case ACCURACY_FINE:
|
case QUALITY_HIGH_ACCURACY:
|
||||||
mQuality = QUALITY_HIGH_ACCURACY;
|
mQuality = QUALITY_HIGH_ACCURACY;
|
||||||
break;
|
break;
|
||||||
case ACCURACY_BLOCK:
|
case QUALITY_BALANCED_POWER_ACCURACY:
|
||||||
mQuality = QUALITY_BALANCED_POWER_ACCURACY;
|
mQuality = QUALITY_BALANCED_POWER_ACCURACY;
|
||||||
break;
|
break;
|
||||||
case POWER_LOW:
|
case POWER_LOW:
|
||||||
// fall through
|
// fall through
|
||||||
case ACCURACY_CITY:
|
case QUALITY_LOW_POWER:
|
||||||
mQuality = QUALITY_LOW_POWER;
|
mQuality = QUALITY_LOW_POWER;
|
||||||
break;
|
break;
|
||||||
case POWER_NONE:
|
case POWER_NONE:
|
||||||
@@ -647,6 +650,21 @@ public final class LocationRequest implements Parcelable {
|
|||||||
return mHideFromAppOps;
|
return mHideFromAppOps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this request may access GNSS even if location settings would normally deny
|
||||||
|
* this, in order to enable automotive safety features. This field is only respected on
|
||||||
|
* automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
|
||||||
|
* Driving Assistance Systems) application.
|
||||||
|
*
|
||||||
|
* @return true if all limiting factors will be ignored to satisfy GNSS request
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
// TODO: @SystemApi
|
||||||
|
public boolean isAdasGnssBypass() {
|
||||||
|
return mAdasGnssBypass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
* @deprecated LocationRequests should be treated as immutable.
|
* @deprecated LocationRequests should be treated as immutable.
|
||||||
@@ -672,6 +690,15 @@ public final class LocationRequest implements Parcelable {
|
|||||||
return mLocationSettingsIgnored;
|
return mLocationSettingsIgnored;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if any bypass flag is set on this request. For internal use only.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean isBypass() {
|
||||||
|
return mAdasGnssBypass || mLocationSettingsIgnored;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @hide
|
* @hide
|
||||||
* @deprecated LocationRequests should be treated as immutable.
|
* @deprecated LocationRequests should be treated as immutable.
|
||||||
@@ -749,6 +776,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
/* minUpdateDistanceMeters= */ in.readFloat(),
|
/* minUpdateDistanceMeters= */ in.readFloat(),
|
||||||
/* maxUpdateDelayMillis= */ in.readLong(),
|
/* maxUpdateDelayMillis= */ in.readLong(),
|
||||||
/* hiddenFromAppOps= */ in.readBoolean(),
|
/* hiddenFromAppOps= */ in.readBoolean(),
|
||||||
|
/* adasGnssBypass= */ in.readBoolean(),
|
||||||
/* locationSettingsIgnored= */ in.readBoolean(),
|
/* locationSettingsIgnored= */ in.readBoolean(),
|
||||||
/* lowPower= */ in.readBoolean(),
|
/* lowPower= */ in.readBoolean(),
|
||||||
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
|
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
|
||||||
@@ -777,6 +805,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
parcel.writeFloat(mMinUpdateDistanceMeters);
|
parcel.writeFloat(mMinUpdateDistanceMeters);
|
||||||
parcel.writeLong(mMaxUpdateDelayMillis);
|
parcel.writeLong(mMaxUpdateDelayMillis);
|
||||||
parcel.writeBoolean(mHideFromAppOps);
|
parcel.writeBoolean(mHideFromAppOps);
|
||||||
|
parcel.writeBoolean(mAdasGnssBypass);
|
||||||
parcel.writeBoolean(mLocationSettingsIgnored);
|
parcel.writeBoolean(mLocationSettingsIgnored);
|
||||||
parcel.writeBoolean(mLowPower);
|
parcel.writeBoolean(mLowPower);
|
||||||
parcel.writeTypedObject(mWorkSource, 0);
|
parcel.writeTypedObject(mWorkSource, 0);
|
||||||
@@ -801,6 +830,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
&& Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
|
&& Float.compare(that.mMinUpdateDistanceMeters, mMinUpdateDistanceMeters) == 0
|
||||||
&& mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
|
&& mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
|
||||||
&& mHideFromAppOps == that.mHideFromAppOps
|
&& mHideFromAppOps == that.mHideFromAppOps
|
||||||
|
&& mAdasGnssBypass == that.mAdasGnssBypass
|
||||||
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
|
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
|
||||||
&& mLowPower == that.mLowPower
|
&& mLowPower == that.mLowPower
|
||||||
&& Objects.equals(mProvider, that.mProvider)
|
&& Objects.equals(mProvider, that.mProvider)
|
||||||
@@ -866,8 +896,11 @@ public final class LocationRequest implements Parcelable {
|
|||||||
if (mHideFromAppOps) {
|
if (mHideFromAppOps) {
|
||||||
s.append(", hiddenFromAppOps");
|
s.append(", hiddenFromAppOps");
|
||||||
}
|
}
|
||||||
|
if (mAdasGnssBypass) {
|
||||||
|
s.append(", adasGnssBypass");
|
||||||
|
}
|
||||||
if (mLocationSettingsIgnored) {
|
if (mLocationSettingsIgnored) {
|
||||||
s.append(", locationSettingsIgnored");
|
s.append(", settingsBypass");
|
||||||
}
|
}
|
||||||
if (mWorkSource != null && !mWorkSource.isEmpty()) {
|
if (mWorkSource != null && !mWorkSource.isEmpty()) {
|
||||||
s.append(", ").append(mWorkSource);
|
s.append(", ").append(mWorkSource);
|
||||||
@@ -889,6 +922,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
private float mMinUpdateDistanceMeters;
|
private float mMinUpdateDistanceMeters;
|
||||||
private long mMaxUpdateDelayMillis;
|
private long mMaxUpdateDelayMillis;
|
||||||
private boolean mHiddenFromAppOps;
|
private boolean mHiddenFromAppOps;
|
||||||
|
private boolean mAdasGnssBypass;
|
||||||
private boolean mLocationSettingsIgnored;
|
private boolean mLocationSettingsIgnored;
|
||||||
private boolean mLowPower;
|
private boolean mLowPower;
|
||||||
@Nullable private WorkSource mWorkSource;
|
@Nullable private WorkSource mWorkSource;
|
||||||
@@ -908,6 +942,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
mMinUpdateDistanceMeters = 0;
|
mMinUpdateDistanceMeters = 0;
|
||||||
mMaxUpdateDelayMillis = 0;
|
mMaxUpdateDelayMillis = 0;
|
||||||
mHiddenFromAppOps = false;
|
mHiddenFromAppOps = false;
|
||||||
|
mAdasGnssBypass = false;
|
||||||
mLocationSettingsIgnored = false;
|
mLocationSettingsIgnored = false;
|
||||||
mLowPower = false;
|
mLowPower = false;
|
||||||
mWorkSource = null;
|
mWorkSource = null;
|
||||||
@@ -925,6 +960,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
|
mMinUpdateDistanceMeters = locationRequest.mMinUpdateDistanceMeters;
|
||||||
mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis;
|
mMaxUpdateDelayMillis = locationRequest.mMaxUpdateDelayMillis;
|
||||||
mHiddenFromAppOps = locationRequest.mHideFromAppOps;
|
mHiddenFromAppOps = locationRequest.mHideFromAppOps;
|
||||||
|
mAdasGnssBypass = locationRequest.mAdasGnssBypass;
|
||||||
mLocationSettingsIgnored = locationRequest.mLocationSettingsIgnored;
|
mLocationSettingsIgnored = locationRequest.mLocationSettingsIgnored;
|
||||||
mLowPower = locationRequest.mLowPower;
|
mLowPower = locationRequest.mLowPower;
|
||||||
mWorkSource = locationRequest.mWorkSource;
|
mWorkSource = locationRequest.mWorkSource;
|
||||||
@@ -977,10 +1013,10 @@ public final class LocationRequest implements Parcelable {
|
|||||||
public @NonNull Builder setQuality(@NonNull Criteria criteria) {
|
public @NonNull Builder setQuality(@NonNull Criteria criteria) {
|
||||||
switch (criteria.getAccuracy()) {
|
switch (criteria.getAccuracy()) {
|
||||||
case Criteria.ACCURACY_COARSE:
|
case Criteria.ACCURACY_COARSE:
|
||||||
mQuality = ACCURACY_BLOCK;
|
mQuality = QUALITY_BALANCED_POWER_ACCURACY;
|
||||||
break;
|
break;
|
||||||
case Criteria.ACCURACY_FINE:
|
case Criteria.ACCURACY_FINE:
|
||||||
mQuality = ACCURACY_FINE;
|
mQuality = QUALITY_HIGH_ACCURACY;
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
|
if (criteria.getPowerRequirement() == Criteria.POWER_HIGH) {
|
||||||
@@ -1091,6 +1127,25 @@ public final class LocationRequest implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, indicates that the client is an ADAS (Advanced Driving Assistance
|
||||||
|
* Systems) client, which requires access to GNSS even if location settings would normally
|
||||||
|
* deny this, in order to enable auto safety features. This field is only respected on
|
||||||
|
* automotive devices, and only if the client is recognized as a legitimate ADAS
|
||||||
|
* application. Defaults to false.
|
||||||
|
*
|
||||||
|
* <p>Permissions enforcement occurs when resulting location request is actually used, not
|
||||||
|
* when this method is invoked.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
// TODO: @SystemApi
|
||||||
|
@RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
|
||||||
|
public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
|
||||||
|
mAdasGnssBypass = adasGnssBypass;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to true, indicates that location settings, throttling, background location limits,
|
* If set to true, indicates that location settings, throttling, background location limits,
|
||||||
* and any other possible limiting factors should be ignored in order to satisfy this
|
* and any other possible limiting factors should be ignored in order to satisfy this
|
||||||
@@ -1171,6 +1226,7 @@ public final class LocationRequest implements Parcelable {
|
|||||||
mMinUpdateDistanceMeters,
|
mMinUpdateDistanceMeters,
|
||||||
mMaxUpdateDelayMillis,
|
mMaxUpdateDelayMillis,
|
||||||
mHiddenFromAppOps,
|
mHiddenFromAppOps,
|
||||||
|
mAdasGnssBypass,
|
||||||
mLocationSettingsIgnored,
|
mLocationSettingsIgnored,
|
||||||
mLowPower,
|
mLowPower,
|
||||||
new WorkSource(mWorkSource));
|
new WorkSource(mWorkSource));
|
||||||
|
|||||||
@@ -44,12 +44,19 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
public static final long INTERVAL_DISABLED = Long.MAX_VALUE;
|
public static final long INTERVAL_DISABLED = Long.MAX_VALUE;
|
||||||
|
|
||||||
public static final @NonNull ProviderRequest EMPTY_REQUEST = new ProviderRequest(
|
public static final @NonNull ProviderRequest EMPTY_REQUEST = new ProviderRequest(
|
||||||
INTERVAL_DISABLED, QUALITY_BALANCED_POWER_ACCURACY, 0, false, false, new WorkSource());
|
INTERVAL_DISABLED,
|
||||||
|
QUALITY_BALANCED_POWER_ACCURACY,
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
new WorkSource());
|
||||||
|
|
||||||
private final long mIntervalMillis;
|
private final long mIntervalMillis;
|
||||||
private final @Quality int mQuality;
|
private final @Quality int mQuality;
|
||||||
private final long mMaxUpdateDelayMillis;
|
private final long mMaxUpdateDelayMillis;
|
||||||
private final boolean mLowPower;
|
private final boolean mLowPower;
|
||||||
|
private final boolean mAdasGnssBypass;
|
||||||
private final boolean mLocationSettingsIgnored;
|
private final boolean mLocationSettingsIgnored;
|
||||||
private final WorkSource mWorkSource;
|
private final WorkSource mWorkSource;
|
||||||
|
|
||||||
@@ -72,12 +79,14 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
@Quality int quality,
|
@Quality int quality,
|
||||||
long maxUpdateDelayMillis,
|
long maxUpdateDelayMillis,
|
||||||
boolean lowPower,
|
boolean lowPower,
|
||||||
|
boolean adasGnssBypass,
|
||||||
boolean locationSettingsIgnored,
|
boolean locationSettingsIgnored,
|
||||||
@NonNull WorkSource workSource) {
|
@NonNull WorkSource workSource) {
|
||||||
mIntervalMillis = intervalMillis;
|
mIntervalMillis = intervalMillis;
|
||||||
mQuality = quality;
|
mQuality = quality;
|
||||||
mMaxUpdateDelayMillis = maxUpdateDelayMillis;
|
mMaxUpdateDelayMillis = maxUpdateDelayMillis;
|
||||||
mLowPower = lowPower;
|
mLowPower = lowPower;
|
||||||
|
mAdasGnssBypass = adasGnssBypass;
|
||||||
mLocationSettingsIgnored = locationSettingsIgnored;
|
mLocationSettingsIgnored = locationSettingsIgnored;
|
||||||
mWorkSource = Objects.requireNonNull(workSource);
|
mWorkSource = Objects.requireNonNull(workSource);
|
||||||
}
|
}
|
||||||
@@ -125,6 +134,18 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
return mLowPower;
|
return mLowPower;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this request may access GNSS even if location settings would normally deny
|
||||||
|
* this, in order to enable automotive safety features. This field is only respected on
|
||||||
|
* automotive devices, and only if the client is recognized as a legitimate ADAS (Advanced
|
||||||
|
* Driving Assistance Systems) application.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean isAdasGnssBypass() {
|
||||||
|
return mAdasGnssBypass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the provider should ignore all location settings, user consents, power restrictions
|
* Whether the provider should ignore all location settings, user consents, power restrictions
|
||||||
* or any other restricting factors and always satisfy this request to the best of their
|
* or any other restricting factors and always satisfy this request to the best of their
|
||||||
@@ -134,6 +155,15 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
return mLocationSettingsIgnored;
|
return mLocationSettingsIgnored;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if any bypass flag is set on this request.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public boolean isBypass() {
|
||||||
|
return mAdasGnssBypass || mLocationSettingsIgnored;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The power blame for this provider request.
|
* The power blame for this provider request.
|
||||||
*/
|
*/
|
||||||
@@ -153,6 +183,7 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
/* quality= */ in.readInt(),
|
/* quality= */ in.readInt(),
|
||||||
/* maxUpdateDelayMillis= */ in.readLong(),
|
/* maxUpdateDelayMillis= */ in.readLong(),
|
||||||
/* lowPower= */ in.readBoolean(),
|
/* lowPower= */ in.readBoolean(),
|
||||||
|
/* adasGnssBypass= */ in.readBoolean(),
|
||||||
/* locationSettingsIgnored= */ in.readBoolean(),
|
/* locationSettingsIgnored= */ in.readBoolean(),
|
||||||
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
|
/* workSource= */ in.readTypedObject(WorkSource.CREATOR));
|
||||||
}
|
}
|
||||||
@@ -176,6 +207,7 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
parcel.writeInt(mQuality);
|
parcel.writeInt(mQuality);
|
||||||
parcel.writeLong(mMaxUpdateDelayMillis);
|
parcel.writeLong(mMaxUpdateDelayMillis);
|
||||||
parcel.writeBoolean(mLowPower);
|
parcel.writeBoolean(mLowPower);
|
||||||
|
parcel.writeBoolean(mAdasGnssBypass);
|
||||||
parcel.writeBoolean(mLocationSettingsIgnored);
|
parcel.writeBoolean(mLocationSettingsIgnored);
|
||||||
parcel.writeTypedObject(mWorkSource, flags);
|
parcel.writeTypedObject(mWorkSource, flags);
|
||||||
}
|
}
|
||||||
@@ -198,6 +230,7 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
&& mQuality == that.mQuality
|
&& mQuality == that.mQuality
|
||||||
&& mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
|
&& mMaxUpdateDelayMillis == that.mMaxUpdateDelayMillis
|
||||||
&& mLowPower == that.mLowPower
|
&& mLowPower == that.mLowPower
|
||||||
|
&& mAdasGnssBypass == that.mAdasGnssBypass
|
||||||
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
|
&& mLocationSettingsIgnored == that.mLocationSettingsIgnored
|
||||||
&& mWorkSource.equals(that.mWorkSource);
|
&& mWorkSource.equals(that.mWorkSource);
|
||||||
}
|
}
|
||||||
@@ -229,8 +262,11 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
if (mLowPower) {
|
if (mLowPower) {
|
||||||
s.append(", lowPower");
|
s.append(", lowPower");
|
||||||
}
|
}
|
||||||
|
if (mAdasGnssBypass) {
|
||||||
|
s.append(", adasGnssBypass");
|
||||||
|
}
|
||||||
if (mLocationSettingsIgnored) {
|
if (mLocationSettingsIgnored) {
|
||||||
s.append(", locationSettingsIgnored");
|
s.append(", settingsBypass");
|
||||||
}
|
}
|
||||||
if (!mWorkSource.isEmpty()) {
|
if (!mWorkSource.isEmpty()) {
|
||||||
s.append(", ").append(mWorkSource);
|
s.append(", ").append(mWorkSource);
|
||||||
@@ -246,10 +282,12 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
* A Builder for {@link ProviderRequest}s.
|
* A Builder for {@link ProviderRequest}s.
|
||||||
*/
|
*/
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
|
|
||||||
private long mIntervalMillis = INTERVAL_DISABLED;
|
private long mIntervalMillis = INTERVAL_DISABLED;
|
||||||
private int mQuality = QUALITY_BALANCED_POWER_ACCURACY;
|
private int mQuality = QUALITY_BALANCED_POWER_ACCURACY;
|
||||||
private long mMaxUpdateDelayMillis = 0;
|
private long mMaxUpdateDelayMillis = 0;
|
||||||
private boolean mLowPower;
|
private boolean mLowPower;
|
||||||
|
private boolean mAdasGnssBypass;
|
||||||
private boolean mLocationSettingsIgnored;
|
private boolean mLocationSettingsIgnored;
|
||||||
private WorkSource mWorkSource = new WorkSource();
|
private WorkSource mWorkSource = new WorkSource();
|
||||||
|
|
||||||
@@ -298,6 +336,16 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether this ADAS request should bypass GNSS settings. False by default.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) {
|
||||||
|
this.mAdasGnssBypass = adasGnssBypass;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether location settings should be ignored. False by default.
|
* Sets whether location settings should be ignored. False by default.
|
||||||
*/
|
*/
|
||||||
@@ -326,6 +374,7 @@ public final class ProviderRequest implements Parcelable {
|
|||||||
mQuality,
|
mQuality,
|
||||||
mMaxUpdateDelayMillis,
|
mMaxUpdateDelayMillis,
|
||||||
mLowPower,
|
mLowPower,
|
||||||
|
mAdasGnssBypass,
|
||||||
mLocationSettingsIgnored,
|
mLocationSettingsIgnored,
|
||||||
mWorkSource);
|
mWorkSource);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import android.app.PendingIntent;
|
|||||||
import android.app.compat.CompatChanges;
|
import android.app.compat.CompatChanges;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.location.Criteria;
|
import android.location.Criteria;
|
||||||
import android.location.GeocoderParams;
|
import android.location.GeocoderParams;
|
||||||
import android.location.Geofence;
|
import android.location.Geofence;
|
||||||
@@ -91,6 +92,7 @@ import android.util.IndentingPrintWriter;
|
|||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import com.android.internal.annotations.GuardedBy;
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.util.ArrayUtils;
|
||||||
import com.android.internal.util.DumpUtils;
|
import com.android.internal.util.DumpUtils;
|
||||||
import com.android.internal.util.Preconditions;
|
import com.android.internal.util.Preconditions;
|
||||||
import com.android.server.FgThread;
|
import com.android.server.FgThread;
|
||||||
@@ -134,6 +136,8 @@ import com.android.server.location.provider.PassiveLocationProvider;
|
|||||||
import com.android.server.location.provider.PassiveLocationProviderManager;
|
import com.android.server.location.provider.PassiveLocationProviderManager;
|
||||||
import com.android.server.location.provider.StationaryThrottlingLocationProvider;
|
import com.android.server.location.provider.StationaryThrottlingLocationProvider;
|
||||||
import com.android.server.location.provider.proxy.ProxyLocationProvider;
|
import com.android.server.location.provider.proxy.ProxyLocationProvider;
|
||||||
|
import com.android.server.location.settings.LocationSettings;
|
||||||
|
import com.android.server.location.settings.LocationUserSettings;
|
||||||
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
|
import com.android.server.pm.permission.LegacyPermissionManagerInternal;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
@@ -270,6 +274,8 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
|
|
||||||
mGeofenceManager = new GeofenceManager(mContext, injector);
|
mGeofenceManager = new GeofenceManager(mContext, injector);
|
||||||
|
|
||||||
|
mInjector.getLocationSettings().registerLocationUserSettingsListener(
|
||||||
|
this::onLocationUserSettingsChanged);
|
||||||
mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
|
mInjector.getSettingsHelper().addOnLocationEnabledChangedListener(
|
||||||
this::onLocationModeChanged);
|
this::onLocationModeChanged);
|
||||||
mInjector.getSettingsHelper().addIgnoreSettingsAllowlistChangedListener(
|
mInjector.getSettingsHelper().addIgnoreSettingsAllowlistChangedListener(
|
||||||
@@ -476,6 +482,25 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
|
||||||
|
LocationUserSettings newSettings) {
|
||||||
|
if (oldSettings.isAdasGnssLocationEnabled() != newSettings.isAdasGnssLocationEnabled()) {
|
||||||
|
boolean enabled = newSettings.isAdasGnssLocationEnabled();
|
||||||
|
|
||||||
|
if (D) {
|
||||||
|
Log.d(TAG, "[u" + userId + "] adas gnss location enabled = " + enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
EVENT_LOG.logAdasLocationEnabled(userId, enabled);
|
||||||
|
|
||||||
|
Intent intent = new Intent(LocationManager.ACTION_ADAS_GNSS_ENABLED_CHANGED)
|
||||||
|
.putExtra(LocationManager.EXTRA_ADAS_GNSS_ENABLED, enabled)
|
||||||
|
.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
|
||||||
|
.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
|
||||||
|
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onLocationModeChanged(int userId) {
|
private void onLocationModeChanged(int userId) {
|
||||||
boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
|
boolean enabled = mInjector.getSettingsHelper().isLocationEnabled(userId);
|
||||||
LocationManager.invalidateLocalLocationEnabledCaches();
|
LocationManager.invalidateLocalLocationEnabledCaches();
|
||||||
@@ -661,7 +686,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
// clients in the system process must have an attribution tag set
|
// clients in the system process must have an attribution tag set
|
||||||
Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
|
Preconditions.checkState(identity.getPid() != Process.myPid() || attributionTag != null);
|
||||||
|
|
||||||
request = validateLocationRequest(request, identity);
|
request = validateLocationRequest(provider, request, identity);
|
||||||
|
|
||||||
LocationProviderManager manager = getLocationProviderManager(provider);
|
LocationProviderManager manager = getLocationProviderManager(provider);
|
||||||
Preconditions.checkArgument(manager != null,
|
Preconditions.checkArgument(manager != null,
|
||||||
@@ -687,7 +712,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
new IllegalArgumentException());
|
new IllegalArgumentException());
|
||||||
}
|
}
|
||||||
|
|
||||||
request = validateLocationRequest(request, identity);
|
request = validateLocationRequest(provider, request, identity);
|
||||||
|
|
||||||
LocationProviderManager manager = getLocationProviderManager(provider);
|
LocationProviderManager manager = getLocationProviderManager(provider);
|
||||||
Preconditions.checkArgument(manager != null,
|
Preconditions.checkArgument(manager != null,
|
||||||
@@ -725,7 +750,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
request = validateLocationRequest(request, identity);
|
request = validateLocationRequest(provider, request, identity);
|
||||||
|
|
||||||
LocationProviderManager manager = getLocationProviderManager(provider);
|
LocationProviderManager manager = getLocationProviderManager(provider);
|
||||||
Preconditions.checkArgument(manager != null,
|
Preconditions.checkArgument(manager != null,
|
||||||
@@ -734,33 +759,27 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
|
manager.registerLocationRequest(request, identity, permissionLevel, pendingIntent);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocationRequest validateLocationRequest(LocationRequest request,
|
private LocationRequest validateLocationRequest(String provider, LocationRequest request,
|
||||||
CallerIdentity identity) {
|
CallerIdentity identity) {
|
||||||
|
// validate unsanitized request
|
||||||
if (!request.getWorkSource().isEmpty()) {
|
if (!request.getWorkSource().isEmpty()) {
|
||||||
mContext.enforceCallingOrSelfPermission(
|
mContext.enforceCallingOrSelfPermission(
|
||||||
permission.UPDATE_DEVICE_STATS,
|
permission.UPDATE_DEVICE_STATS,
|
||||||
"setting a work source requires " + permission.UPDATE_DEVICE_STATS);
|
"setting a work source requires " + permission.UPDATE_DEVICE_STATS);
|
||||||
}
|
}
|
||||||
if (request.isHiddenFromAppOps()) {
|
|
||||||
mContext.enforceCallingOrSelfPermission(
|
|
||||||
permission.UPDATE_APP_OPS_STATS,
|
|
||||||
"hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
|
|
||||||
}
|
|
||||||
if (request.isLocationSettingsIgnored()) {
|
|
||||||
mContext.enforceCallingOrSelfPermission(
|
|
||||||
permission.WRITE_SECURE_SETTINGS,
|
|
||||||
"ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// sanitize request
|
||||||
LocationRequest.Builder sanitized = new LocationRequest.Builder(request);
|
LocationRequest.Builder sanitized = new LocationRequest.Builder(request);
|
||||||
|
|
||||||
if (CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS, Binder.getCallingUid())) {
|
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
|
||||||
if (request.isLowPower()) {
|
&& GPS_PROVIDER.equals(provider)
|
||||||
mContext.enforceCallingOrSelfPermission(
|
&& ArrayUtils.contains(mContext.getResources().getStringArray(
|
||||||
permission.LOCATION_HARDWARE,
|
com.android.internal.R.array.config_locationDriverAssistancePackageNames),
|
||||||
"low power request requires " + permission.LOCATION_HARDWARE);
|
identity.getPackageName())) {
|
||||||
}
|
sanitized.setAdasGnssBypass(true);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (!CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS, Binder.getCallingUid())) {
|
||||||
if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
|
if (mContext.checkCallingPermission(permission.LOCATION_HARDWARE)
|
||||||
!= PERMISSION_GRANTED) {
|
!= PERMISSION_GRANTED) {
|
||||||
sanitized.setLowPower(false);
|
sanitized.setLowPower(false);
|
||||||
@@ -786,7 +805,52 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
}
|
}
|
||||||
sanitized.setWorkSource(workSource);
|
sanitized.setWorkSource(workSource);
|
||||||
|
|
||||||
return sanitized.build();
|
request = sanitized.build();
|
||||||
|
|
||||||
|
// validate sanitized request
|
||||||
|
boolean isLocationProvider = mLocalService.isProvider(null, identity);
|
||||||
|
|
||||||
|
if (request.isLowPower() && CompatChanges.isChangeEnabled(LOW_POWER_EXCEPTIONS,
|
||||||
|
identity.getUid())) {
|
||||||
|
mContext.enforceCallingOrSelfPermission(
|
||||||
|
permission.LOCATION_HARDWARE,
|
||||||
|
"low power request requires " + permission.LOCATION_HARDWARE);
|
||||||
|
}
|
||||||
|
if (request.isHiddenFromAppOps()) {
|
||||||
|
mContext.enforceCallingOrSelfPermission(
|
||||||
|
permission.UPDATE_APP_OPS_STATS,
|
||||||
|
"hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
|
||||||
|
}
|
||||||
|
if (request.isAdasGnssBypass()) {
|
||||||
|
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"adas gnss bypass requests are only allowed on automotive devices");
|
||||||
|
}
|
||||||
|
if (!GPS_PROVIDER.equals(provider)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"adas gnss bypass requests are only allowed on the \"gps\" provider");
|
||||||
|
}
|
||||||
|
if (!ArrayUtils.contains(mContext.getResources().getStringArray(
|
||||||
|
com.android.internal.R.array.config_locationDriverAssistancePackageNames),
|
||||||
|
identity.getPackageName())) {
|
||||||
|
throw new SecurityException(
|
||||||
|
"only verified adas packages may use adas gnss bypass requests");
|
||||||
|
}
|
||||||
|
if (!isLocationProvider) {
|
||||||
|
mContext.enforceCallingOrSelfPermission(
|
||||||
|
permission.WRITE_SECURE_SETTINGS,
|
||||||
|
"adas gnss bypass requires " + permission.WRITE_SECURE_SETTINGS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (request.isLocationSettingsIgnored()) {
|
||||||
|
if (!isLocationProvider) {
|
||||||
|
mContext.enforceCallingOrSelfPermission(
|
||||||
|
permission.WRITE_SECURE_SETTINGS,
|
||||||
|
"ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -834,7 +898,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
// clients in the system process must have an attribution tag set
|
// clients in the system process must have an attribution tag set
|
||||||
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
|
Preconditions.checkArgument(identity.getPid() != Process.myPid() || attributionTag != null);
|
||||||
|
|
||||||
request = validateLastLocationRequest(request);
|
request = validateLastLocationRequest(provider, request, identity);
|
||||||
|
|
||||||
LocationProviderManager manager = getLocationProviderManager(provider);
|
LocationProviderManager manager = getLocationProviderManager(provider);
|
||||||
if (manager == null) {
|
if (manager == null) {
|
||||||
@@ -844,16 +908,58 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
return manager.getLastLocation(request, identity, permissionLevel);
|
return manager.getLastLocation(request, identity, permissionLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LastLocationRequest validateLastLocationRequest(LastLocationRequest request) {
|
private LastLocationRequest validateLastLocationRequest(String provider,
|
||||||
|
LastLocationRequest request,
|
||||||
|
CallerIdentity identity) {
|
||||||
|
// sanitize request
|
||||||
|
LastLocationRequest.Builder sanitized = new LastLocationRequest.Builder(request);
|
||||||
|
|
||||||
|
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
|
||||||
|
&& GPS_PROVIDER.equals(provider)
|
||||||
|
&& ArrayUtils.contains(mContext.getResources().getStringArray(
|
||||||
|
com.android.internal.R.array.config_locationDriverAssistancePackageNames),
|
||||||
|
identity.getPackageName())) {
|
||||||
|
sanitized.setAdasGnssBypass(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
request = sanitized.build();
|
||||||
|
|
||||||
|
// validate request
|
||||||
|
boolean isLocationProvider = mLocalService.isProvider(null, identity);
|
||||||
|
|
||||||
if (request.isHiddenFromAppOps()) {
|
if (request.isHiddenFromAppOps()) {
|
||||||
mContext.enforceCallingOrSelfPermission(
|
mContext.enforceCallingOrSelfPermission(
|
||||||
permission.UPDATE_APP_OPS_STATS,
|
permission.UPDATE_APP_OPS_STATS,
|
||||||
"hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
|
"hiding from app ops requires " + permission.UPDATE_APP_OPS_STATS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (request.isAdasGnssBypass()) {
|
||||||
|
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"adas gnss bypass requests are only allowed on automotive devices");
|
||||||
|
}
|
||||||
|
if (!GPS_PROVIDER.equals(provider)) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"adas gnss bypass requests are only allowed on the \"gps\" provider");
|
||||||
|
}
|
||||||
|
if (!ArrayUtils.contains(mContext.getResources().getStringArray(
|
||||||
|
com.android.internal.R.array.config_locationDriverAssistancePackageNames),
|
||||||
|
identity.getPackageName())) {
|
||||||
|
throw new SecurityException(
|
||||||
|
"only verified adas packages may use adas gnss bypass requests");
|
||||||
|
}
|
||||||
|
if (!isLocationProvider) {
|
||||||
|
mContext.enforceCallingOrSelfPermission(
|
||||||
|
permission.WRITE_SECURE_SETTINGS,
|
||||||
|
"adas gnss bypass requires " + permission.WRITE_SECURE_SETTINGS);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (request.isLocationSettingsIgnored()) {
|
if (request.isLocationSettingsIgnored()) {
|
||||||
mContext.enforceCallingOrSelfPermission(
|
if (!isLocationProvider) {
|
||||||
permission.WRITE_SECURE_SETTINGS,
|
mContext.enforceCallingOrSelfPermission(
|
||||||
"ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
|
permission.WRITE_SECURE_SETTINGS,
|
||||||
|
"ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
@@ -1125,6 +1231,24 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
return mInjector.getSettingsHelper().isLocationEnabled(userId);
|
return mInjector.getSettingsHelper().isLocationEnabled(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAdasGnssLocationEnabledForUser(boolean enabled, int userId) {
|
||||||
|
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
|
||||||
|
userId, false, false, "setAdasGnssLocationEnabledForUser", null);
|
||||||
|
|
||||||
|
mContext.enforceCallingOrSelfPermission(permission.WRITE_SECURE_SETTINGS, null);
|
||||||
|
|
||||||
|
mInjector.getLocationSettings().updateUserSettings(userId,
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(enabled));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAdasGnssLocationEnabledForUser(int userId) {
|
||||||
|
userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
|
||||||
|
userId, false, false, "isAdasGnssLocationEnabledForUser", null);
|
||||||
|
return mInjector.getLocationSettings().getUserSettings(userId).isAdasGnssLocationEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isProviderEnabledForUser(String provider, int userId) {
|
public boolean isProviderEnabledForUser(String provider, int userId) {
|
||||||
return mLocalService.isProviderEnabledForUser(provider, userId);
|
return mLocalService.isProviderEnabledForUser(provider, userId);
|
||||||
@@ -1555,11 +1679,12 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SystemInjector implements Injector {
|
private static final class SystemInjector implements Injector {
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
private final UserInfoHelper mUserInfoHelper;
|
private final UserInfoHelper mUserInfoHelper;
|
||||||
|
private final LocationSettings mLocationSettings;
|
||||||
private final AlarmHelper mAlarmHelper;
|
private final AlarmHelper mAlarmHelper;
|
||||||
private final SystemAppOpsHelper mAppOpsHelper;
|
private final SystemAppOpsHelper mAppOpsHelper;
|
||||||
private final SystemLocationPermissionsHelper mLocationPermissionsHelper;
|
private final SystemLocationPermissionsHelper mLocationPermissionsHelper;
|
||||||
@@ -1584,6 +1709,7 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
mContext = context;
|
mContext = context;
|
||||||
|
|
||||||
mUserInfoHelper = userInfoHelper;
|
mUserInfoHelper = userInfoHelper;
|
||||||
|
mLocationSettings = new LocationSettings(context);
|
||||||
mAlarmHelper = new SystemAlarmHelper(context);
|
mAlarmHelper = new SystemAlarmHelper(context);
|
||||||
mAppOpsHelper = new SystemAppOpsHelper(context);
|
mAppOpsHelper = new SystemAppOpsHelper(context);
|
||||||
mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context,
|
mLocationPermissionsHelper = new SystemLocationPermissionsHelper(context,
|
||||||
@@ -1620,6 +1746,11 @@ public class LocationManagerService extends ILocationManager.Stub implements
|
|||||||
return mUserInfoHelper;
|
return mUserInfoHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public LocationSettings getLocationSettings() {
|
||||||
|
return mLocationSettings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AlarmHelper getAlarmHelper() {
|
public AlarmHelper getAlarmHelper() {
|
||||||
return mAlarmHelper;
|
return mAlarmHelper;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.server.location;
|
package com.android.server.location;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.location.Criteria;
|
import android.location.Criteria;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.provider.ProviderProperties;
|
import android.location.provider.ProviderProperties;
|
||||||
@@ -60,6 +61,14 @@ class LocationShellCommand extends BasicShellCommandHandler {
|
|||||||
handleSetLocationEnabled();
|
handleSetLocationEnabled();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
case "is-adas-gnss-location-enabled": {
|
||||||
|
handleIsAdasGnssLocationEnabled();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case "set-adas-gnss-location-enabled": {
|
||||||
|
handleSetAdasGnssLocationEnabled();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
case "providers": {
|
case "providers": {
|
||||||
String command = getNextArgRequired();
|
String command = getNextArgRequired();
|
||||||
return parseProvidersCommand(command);
|
return parseProvidersCommand(command);
|
||||||
@@ -134,6 +143,52 @@ class LocationShellCommand extends BasicShellCommandHandler {
|
|||||||
mService.setLocationEnabledForUser(enabled, userId);
|
mService.setLocationEnabledForUser(enabled, userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleIsAdasGnssLocationEnabled() {
|
||||||
|
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
|
||||||
|
throw new IllegalStateException("command only recognized on automotive devices");
|
||||||
|
}
|
||||||
|
|
||||||
|
int userId = UserHandle.USER_CURRENT_OR_SELF;
|
||||||
|
|
||||||
|
do {
|
||||||
|
String option = getNextOption();
|
||||||
|
if (option == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ("--user".equals(option)) {
|
||||||
|
userId = UserHandle.parseUserArg(getNextArgRequired());
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown option: " + option);
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
getOutPrintWriter().println(mService.isAdasGnssLocationEnabledForUser(userId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleSetAdasGnssLocationEnabled() {
|
||||||
|
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
|
||||||
|
throw new IllegalStateException("command only recognized on automotive devices");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean enabled = Boolean.parseBoolean(getNextArgRequired());
|
||||||
|
|
||||||
|
int userId = UserHandle.USER_CURRENT_OR_SELF;
|
||||||
|
|
||||||
|
do {
|
||||||
|
String option = getNextOption();
|
||||||
|
if (option == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ("--user".equals(option)) {
|
||||||
|
userId = UserHandle.parseUserArg(getNextArgRequired());
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown option: " + option);
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
mService.setAdasGnssLocationEnabledForUser(enabled, userId);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleAddTestProvider() {
|
private void handleAddTestProvider() {
|
||||||
String provider = getNextArgRequired();
|
String provider = getNextArgRequired();
|
||||||
|
|
||||||
@@ -297,6 +352,14 @@ class LocationShellCommand extends BasicShellCommandHandler {
|
|||||||
pw.println(" set-location-enabled true|false [--user <USER_ID>]");
|
pw.println(" set-location-enabled true|false [--user <USER_ID>]");
|
||||||
pw.println(" Sets the master location switch enabled state. If no user is specified,");
|
pw.println(" Sets the master location switch enabled state. If no user is specified,");
|
||||||
pw.println(" the current user is assumed.");
|
pw.println(" the current user is assumed.");
|
||||||
|
if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
|
||||||
|
pw.println(" is-adas-gnss-location-enabled [--user <USER_ID>]");
|
||||||
|
pw.println(" Gets the ADAS GNSS location enabled state. If no user is specified,");
|
||||||
|
pw.println(" the current user is assumed.");
|
||||||
|
pw.println(" set-adas-gnss-location-enabled true|false [--user <USER_ID>]");
|
||||||
|
pw.println(" Sets the ADAS GNSS location enabled state. If no user is specified,");
|
||||||
|
pw.println(" the current user is assumed.");
|
||||||
|
}
|
||||||
pw.println(" providers");
|
pw.println(" providers");
|
||||||
pw.println(" The providers command is followed by a subcommand, as listed below:");
|
pw.println(" The providers command is followed by a subcommand, as listed below:");
|
||||||
pw.println();
|
pw.println();
|
||||||
@@ -323,9 +386,8 @@ class LocationShellCommand extends BasicShellCommandHandler {
|
|||||||
pw.println(" Common commands that may be supported by the gps provider, depending on");
|
pw.println(" Common commands that may be supported by the gps provider, depending on");
|
||||||
pw.println(" hardware and software configurations:");
|
pw.println(" hardware and software configurations:");
|
||||||
pw.println(" delete_aiding_data - requests deletion of any predictive aiding data");
|
pw.println(" delete_aiding_data - requests deletion of any predictive aiding data");
|
||||||
pw.println(" force_time_injection - requests NTP time injection to chipset");
|
pw.println(" force_time_injection - requests NTP time injection");
|
||||||
pw.println(" force_psds_injection - "
|
pw.println(" force_psds_injection - requests predictive aiding data injection");
|
||||||
+ "requests predictive aiding data injection to chipset");
|
pw.println(" request_power_stats - requests GNSS power stats update");
|
||||||
pw.println(" request_power_stats - requests GNSS power stats update from chipset");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,19 +55,20 @@ public class LocationEventLog extends LocalEventLog {
|
|||||||
|
|
||||||
private static final int EVENT_USER_SWITCHED = 1;
|
private static final int EVENT_USER_SWITCHED = 1;
|
||||||
private static final int EVENT_LOCATION_ENABLED = 2;
|
private static final int EVENT_LOCATION_ENABLED = 2;
|
||||||
private static final int EVENT_PROVIDER_ENABLED = 3;
|
private static final int EVENT_ADAS_LOCATION_ENABLED = 3;
|
||||||
private static final int EVENT_PROVIDER_MOCKED = 4;
|
private static final int EVENT_PROVIDER_ENABLED = 4;
|
||||||
private static final int EVENT_PROVIDER_CLIENT_REGISTER = 5;
|
private static final int EVENT_PROVIDER_MOCKED = 5;
|
||||||
private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 6;
|
private static final int EVENT_PROVIDER_CLIENT_REGISTER = 6;
|
||||||
private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 7;
|
private static final int EVENT_PROVIDER_CLIENT_UNREGISTER = 7;
|
||||||
private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 8;
|
private static final int EVENT_PROVIDER_CLIENT_FOREGROUND = 8;
|
||||||
private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 9;
|
private static final int EVENT_PROVIDER_CLIENT_BACKGROUND = 9;
|
||||||
private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 10;
|
private static final int EVENT_PROVIDER_CLIENT_PERMITTED = 10;
|
||||||
private static final int EVENT_PROVIDER_UPDATE_REQUEST = 11;
|
private static final int EVENT_PROVIDER_CLIENT_UNPERMITTED = 11;
|
||||||
private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 12;
|
private static final int EVENT_PROVIDER_UPDATE_REQUEST = 12;
|
||||||
private static final int EVENT_PROVIDER_DELIVER_LOCATION = 13;
|
private static final int EVENT_PROVIDER_RECEIVE_LOCATION = 13;
|
||||||
private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 14;
|
private static final int EVENT_PROVIDER_DELIVER_LOCATION = 14;
|
||||||
private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 15;
|
private static final int EVENT_PROVIDER_STATIONARY_THROTTLED = 15;
|
||||||
|
private static final int EVENT_LOCATION_POWER_SAVE_MODE_CHANGE = 16;
|
||||||
|
|
||||||
@GuardedBy("mAggregateStats")
|
@GuardedBy("mAggregateStats")
|
||||||
private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
|
private final ArrayMap<String, ArrayMap<CallerIdentity, AggregateStats>> mAggregateStats;
|
||||||
@@ -116,6 +117,11 @@ public class LocationEventLog extends LocalEventLog {
|
|||||||
addLogEvent(EVENT_LOCATION_ENABLED, userId, enabled);
|
addLogEvent(EVENT_LOCATION_ENABLED, userId, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Logs a location enabled/disabled event. */
|
||||||
|
public void logAdasLocationEnabled(int userId, boolean enabled) {
|
||||||
|
addLogEvent(EVENT_ADAS_LOCATION_ENABLED, userId, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
/** Logs a location provider enabled/disabled event. */
|
/** Logs a location provider enabled/disabled event. */
|
||||||
public void logProviderEnabled(String provider, int userId, boolean enabled) {
|
public void logProviderEnabled(String provider, int userId, boolean enabled) {
|
||||||
addLogEvent(EVENT_PROVIDER_ENABLED, provider, userId, enabled);
|
addLogEvent(EVENT_PROVIDER_ENABLED, provider, userId, enabled);
|
||||||
@@ -219,6 +225,9 @@ public class LocationEventLog extends LocalEventLog {
|
|||||||
return new UserSwitchedEvent(timeDelta, (Integer) args[0], (Integer) args[1]);
|
return new UserSwitchedEvent(timeDelta, (Integer) args[0], (Integer) args[1]);
|
||||||
case EVENT_LOCATION_ENABLED:
|
case EVENT_LOCATION_ENABLED:
|
||||||
return new LocationEnabledEvent(timeDelta, (Integer) args[0], (Boolean) args[1]);
|
return new LocationEnabledEvent(timeDelta, (Integer) args[0], (Boolean) args[1]);
|
||||||
|
case EVENT_ADAS_LOCATION_ENABLED:
|
||||||
|
return new LocationAdasEnabledEvent(timeDelta, (Integer) args[0],
|
||||||
|
(Boolean) args[1]);
|
||||||
case EVENT_PROVIDER_ENABLED:
|
case EVENT_PROVIDER_ENABLED:
|
||||||
return new ProviderEnabledEvent(timeDelta, (String) args[0], (Integer) args[1],
|
return new ProviderEnabledEvent(timeDelta, (String) args[0], (Integer) args[1],
|
||||||
(Boolean) args[2]);
|
(Boolean) args[2]);
|
||||||
@@ -517,6 +526,23 @@ public class LocationEventLog extends LocalEventLog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class LocationAdasEnabledEvent extends LogEvent {
|
||||||
|
|
||||||
|
private final int mUserId;
|
||||||
|
private final boolean mEnabled;
|
||||||
|
|
||||||
|
LocationAdasEnabledEvent(long timeDelta, int userId, boolean enabled) {
|
||||||
|
super(timeDelta);
|
||||||
|
mUserId = userId;
|
||||||
|
mEnabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLogString() {
|
||||||
|
return "adas location [u" + mUserId + "] " + (mEnabled ? "enabled" : "disabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregate statistics for a single package under a single provider.
|
* Aggregate statistics for a single package under a single provider.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -771,10 +771,10 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
|
|||||||
boolean enabled = mContext.getSystemService(LocationManager.class)
|
boolean enabled = mContext.getSystemService(LocationManager.class)
|
||||||
.isLocationEnabledForUser(UserHandle.CURRENT);
|
.isLocationEnabledForUser(UserHandle.CURRENT);
|
||||||
|
|
||||||
// .. but enable anyway, if there's an active settings-ignored request (e.g. ELS)
|
// .. but enable anyway, if there's an active bypass request (e.g. ELS or ADAS)
|
||||||
enabled |= (mProviderRequest != null
|
enabled |= (mProviderRequest != null
|
||||||
&& mProviderRequest.isActive()
|
&& mProviderRequest.isActive()
|
||||||
&& mProviderRequest.isLocationSettingsIgnored());
|
&& mProviderRequest.isBypass());
|
||||||
|
|
||||||
// ... and, finally, disable anyway, if device is being shut down
|
// ... and, finally, disable anyway, if device is being shut down
|
||||||
enabled &= !mShutdown;
|
enabled &= !mShutdown;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package com.android.server.location.injector;
|
package com.android.server.location.injector;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.location.settings.LocationSettings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injects various location dependencies so that they may be controlled by tests.
|
* Injects various location dependencies so that they may be controlled by tests.
|
||||||
@@ -27,6 +28,9 @@ public interface Injector {
|
|||||||
/** Returns a UserInfoHelper. */
|
/** Returns a UserInfoHelper. */
|
||||||
UserInfoHelper getUserInfoHelper();
|
UserInfoHelper getUserInfoHelper();
|
||||||
|
|
||||||
|
/** Returns a LocationSettings. */
|
||||||
|
LocationSettings getLocationSettings();
|
||||||
|
|
||||||
/** Returns an AlarmHelper. */
|
/** Returns an AlarmHelper. */
|
||||||
AlarmHelper getAlarmHelper();
|
AlarmHelper getAlarmHelper();
|
||||||
|
|
||||||
|
|||||||
@@ -670,8 +670,6 @@ public class SystemSettingsHelper extends SettingsHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static class PackageTagsListSetting extends DeviceConfigSetting {
|
private static class PackageTagsListSetting extends DeviceConfigSetting {
|
||||||
|
|
||||||
private final Supplier<ArrayMap<String, ArraySet<String>>> mBaseValuesSupplier;
|
private final Supplier<ArrayMap<String, ArraySet<String>>> mBaseValuesSupplier;
|
||||||
|
|||||||
@@ -113,6 +113,8 @@ import com.android.server.location.injector.UserInfoHelper;
|
|||||||
import com.android.server.location.injector.UserInfoHelper.UserListener;
|
import com.android.server.location.injector.UserInfoHelper.UserListener;
|
||||||
import com.android.server.location.listeners.ListenerMultiplexer;
|
import com.android.server.location.listeners.ListenerMultiplexer;
|
||||||
import com.android.server.location.listeners.RemoteListenerRegistration;
|
import com.android.server.location.listeners.RemoteListenerRegistration;
|
||||||
|
import com.android.server.location.settings.LocationSettings;
|
||||||
|
import com.android.server.location.settings.LocationUserSettings;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
@@ -548,6 +550,19 @@ public class LocationProviderManager extends
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GuardedBy("mLock")
|
||||||
|
final boolean onAdasGnssLocationEnabledChanged(int userId) {
|
||||||
|
if (Build.IS_DEBUGGABLE) {
|
||||||
|
Preconditions.checkState(Thread.holdsLock(mLock));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getIdentity().getUserId() == userId) {
|
||||||
|
return onProviderLocationRequestChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
final boolean onForegroundChanged(int uid, boolean foreground) {
|
final boolean onForegroundChanged(int uid, boolean foreground) {
|
||||||
if (Build.IS_DEBUGGABLE) {
|
if (Build.IS_DEBUGGABLE) {
|
||||||
@@ -592,8 +607,8 @@ public class LocationProviderManager extends
|
|||||||
onHighPowerUsageChanged();
|
onHighPowerUsageChanged();
|
||||||
updateService();
|
updateService();
|
||||||
|
|
||||||
// if location settings ignored has changed then the active state may have changed
|
// if bypass state has changed then the active state may have changed
|
||||||
return oldRequest.isLocationSettingsIgnored() != newRequest.isLocationSettingsIgnored();
|
return oldRequest.isBypass() != newRequest.isBypass();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocationRequest calculateProviderLocationRequest() {
|
private LocationRequest calculateProviderLocationRequest() {
|
||||||
@@ -616,9 +631,24 @@ public class LocationProviderManager extends
|
|||||||
if (!mSettingsHelper.getIgnoreSettingsAllowlist().contains(
|
if (!mSettingsHelper.getIgnoreSettingsAllowlist().contains(
|
||||||
getIdentity().getPackageName(), getIdentity().getAttributionTag())
|
getIdentity().getPackageName(), getIdentity().getAttributionTag())
|
||||||
&& !mLocationManagerInternal.isProvider(null, getIdentity())) {
|
&& !mLocationManagerInternal.isProvider(null, getIdentity())) {
|
||||||
builder.setLocationSettingsIgnored(false);
|
|
||||||
locationSettingsIgnored = false;
|
locationSettingsIgnored = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder.setLocationSettingsIgnored(locationSettingsIgnored);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean adasGnssBypass = baseRequest.isAdasGnssBypass();
|
||||||
|
if (adasGnssBypass) {
|
||||||
|
// if we are not currently allowed use adas gnss bypass, disable it
|
||||||
|
if (!GPS_PROVIDER.equals(mName)) {
|
||||||
|
Log.e(TAG, "adas gnss bypass request received in non-gps provider");
|
||||||
|
adasGnssBypass = false;
|
||||||
|
} else if (!mLocationSettings.getUserSettings(
|
||||||
|
getIdentity().getUserId()).isAdasGnssLocationEnabled()) {
|
||||||
|
adasGnssBypass = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.setAdasGnssBypass(adasGnssBypass);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!locationSettingsIgnored && !isThrottlingExempt()) {
|
if (!locationSettingsIgnored && !isThrottlingExempt()) {
|
||||||
@@ -769,7 +799,7 @@ public class LocationProviderManager extends
|
|||||||
Location lastLocation = getLastLocationUnsafe(
|
Location lastLocation = getLastLocationUnsafe(
|
||||||
getIdentity().getUserId(),
|
getIdentity().getUserId(),
|
||||||
getPermissionLevel(),
|
getPermissionLevel(),
|
||||||
getRequest().isLocationSettingsIgnored(),
|
getRequest().isBypass(),
|
||||||
maxLocationAgeMs);
|
maxLocationAgeMs);
|
||||||
if (lastLocation != null) {
|
if (lastLocation != null) {
|
||||||
executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
|
executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
|
||||||
@@ -1114,7 +1144,7 @@ public class LocationProviderManager extends
|
|||||||
Location lastLocation = getLastLocationUnsafe(
|
Location lastLocation = getLastLocationUnsafe(
|
||||||
getIdentity().getUserId(),
|
getIdentity().getUserId(),
|
||||||
getPermissionLevel(),
|
getPermissionLevel(),
|
||||||
getRequest().isLocationSettingsIgnored(),
|
getRequest().isBypass(),
|
||||||
MAX_CURRENT_LOCATION_AGE_MS);
|
MAX_CURRENT_LOCATION_AGE_MS);
|
||||||
if (lastLocation != null) {
|
if (lastLocation != null) {
|
||||||
executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
|
executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
|
||||||
@@ -1267,6 +1297,7 @@ public class LocationProviderManager extends
|
|||||||
private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
|
private final CopyOnWriteArrayList<IProviderRequestListener> mProviderRequestListeners;
|
||||||
|
|
||||||
protected final LocationManagerInternal mLocationManagerInternal;
|
protected final LocationManagerInternal mLocationManagerInternal;
|
||||||
|
protected final LocationSettings mLocationSettings;
|
||||||
protected final SettingsHelper mSettingsHelper;
|
protected final SettingsHelper mSettingsHelper;
|
||||||
protected final UserInfoHelper mUserHelper;
|
protected final UserInfoHelper mUserHelper;
|
||||||
protected final AlarmHelper mAlarmHelper;
|
protected final AlarmHelper mAlarmHelper;
|
||||||
@@ -1280,6 +1311,8 @@ public class LocationProviderManager extends
|
|||||||
protected final LocationFudger mLocationFudger;
|
protected final LocationFudger mLocationFudger;
|
||||||
|
|
||||||
private final UserListener mUserChangedListener = this::onUserChanged;
|
private final UserListener mUserChangedListener = this::onUserChanged;
|
||||||
|
private final LocationSettings.LocationUserSettingsListener mLocationUserSettingsListener =
|
||||||
|
this::onLocationUserSettingsChanged;
|
||||||
private final UserSettingChangedListener mLocationEnabledChangedListener =
|
private final UserSettingChangedListener mLocationEnabledChangedListener =
|
||||||
this::onLocationEnabledChanged;
|
this::onLocationEnabledChanged;
|
||||||
private final GlobalSettingChangedListener mBackgroundThrottlePackageWhitelistChangedListener =
|
private final GlobalSettingChangedListener mBackgroundThrottlePackageWhitelistChangedListener =
|
||||||
@@ -1332,6 +1365,7 @@ public class LocationProviderManager extends
|
|||||||
|
|
||||||
mLocationManagerInternal = Objects.requireNonNull(
|
mLocationManagerInternal = Objects.requireNonNull(
|
||||||
LocalServices.getService(LocationManagerInternal.class));
|
LocalServices.getService(LocationManagerInternal.class));
|
||||||
|
mLocationSettings = injector.getLocationSettings();
|
||||||
mSettingsHelper = injector.getSettingsHelper();
|
mSettingsHelper = injector.getSettingsHelper();
|
||||||
mUserHelper = injector.getUserInfoHelper();
|
mUserHelper = injector.getUserInfoHelper();
|
||||||
mAlarmHelper = injector.getAlarmHelper();
|
mAlarmHelper = injector.getAlarmHelper();
|
||||||
@@ -1362,6 +1396,7 @@ public class LocationProviderManager extends
|
|||||||
mStateChangedListener = listener;
|
mStateChangedListener = listener;
|
||||||
|
|
||||||
mUserHelper.addListener(mUserChangedListener);
|
mUserHelper.addListener(mUserChangedListener);
|
||||||
|
mLocationSettings.registerLocationUserSettingsListener(mLocationUserSettingsListener);
|
||||||
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
|
mSettingsHelper.addOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
|
||||||
|
|
||||||
final long identity = Binder.clearCallingIdentity();
|
final long identity = Binder.clearCallingIdentity();
|
||||||
@@ -1389,6 +1424,7 @@ public class LocationProviderManager extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
mUserHelper.removeListener(mUserChangedListener);
|
mUserHelper.removeListener(mUserChangedListener);
|
||||||
|
mLocationSettings.unregisterLocationUserSettingsListener(mLocationUserSettingsListener);
|
||||||
mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
|
mSettingsHelper.removeOnLocationEnabledChangedListener(mLocationEnabledChangedListener);
|
||||||
|
|
||||||
// if external entities are registering listeners it's their responsibility to
|
// if external entities are registering listeners it's their responsibility to
|
||||||
@@ -1550,7 +1586,7 @@ public class LocationProviderManager extends
|
|||||||
|
|
||||||
public @Nullable Location getLastLocation(LastLocationRequest request,
|
public @Nullable Location getLastLocation(LastLocationRequest request,
|
||||||
CallerIdentity identity, @PermissionLevel int permissionLevel) {
|
CallerIdentity identity, @PermissionLevel int permissionLevel) {
|
||||||
if (!isActive(request.isLocationSettingsIgnored(), identity)) {
|
if (!isActive(request.isBypass(), identity)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1564,7 +1600,7 @@ public class LocationProviderManager extends
|
|||||||
getLastLocationUnsafe(
|
getLastLocationUnsafe(
|
||||||
identity.getUserId(),
|
identity.getUserId(),
|
||||||
permissionLevel,
|
permissionLevel,
|
||||||
request.isLocationSettingsIgnored(),
|
request.isBypass(),
|
||||||
Long.MAX_VALUE),
|
Long.MAX_VALUE),
|
||||||
permissionLevel);
|
permissionLevel);
|
||||||
|
|
||||||
@@ -1584,7 +1620,7 @@ public class LocationProviderManager extends
|
|||||||
* location if necessary.
|
* location if necessary.
|
||||||
*/
|
*/
|
||||||
public @Nullable Location getLastLocationUnsafe(int userId,
|
public @Nullable Location getLastLocationUnsafe(int userId,
|
||||||
@PermissionLevel int permissionLevel, boolean ignoreLocationSettings,
|
@PermissionLevel int permissionLevel, boolean isBypass,
|
||||||
long maximumAgeMs) {
|
long maximumAgeMs) {
|
||||||
if (userId == UserHandle.USER_ALL) {
|
if (userId == UserHandle.USER_ALL) {
|
||||||
// find the most recent location across all users
|
// find the most recent location across all users
|
||||||
@@ -1592,7 +1628,7 @@ public class LocationProviderManager extends
|
|||||||
final int[] runningUserIds = mUserHelper.getRunningUserIds();
|
final int[] runningUserIds = mUserHelper.getRunningUserIds();
|
||||||
for (int i = 0; i < runningUserIds.length; i++) {
|
for (int i = 0; i < runningUserIds.length; i++) {
|
||||||
Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel,
|
Location next = getLastLocationUnsafe(runningUserIds[i], permissionLevel,
|
||||||
ignoreLocationSettings, maximumAgeMs);
|
isBypass, maximumAgeMs);
|
||||||
if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos()
|
if (lastLocation == null || (next != null && next.getElapsedRealtimeNanos()
|
||||||
> lastLocation.getElapsedRealtimeNanos())) {
|
> lastLocation.getElapsedRealtimeNanos())) {
|
||||||
lastLocation = next;
|
lastLocation = next;
|
||||||
@@ -1601,7 +1637,7 @@ public class LocationProviderManager extends
|
|||||||
return lastLocation;
|
return lastLocation;
|
||||||
} else if (userId == UserHandle.USER_CURRENT) {
|
} else if (userId == UserHandle.USER_CURRENT) {
|
||||||
return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel,
|
return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel,
|
||||||
ignoreLocationSettings, maximumAgeMs);
|
isBypass, maximumAgeMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
Preconditions.checkArgument(userId >= 0);
|
Preconditions.checkArgument(userId >= 0);
|
||||||
@@ -1613,7 +1649,7 @@ public class LocationProviderManager extends
|
|||||||
if (lastLocation == null) {
|
if (lastLocation == null) {
|
||||||
location = null;
|
location = null;
|
||||||
} else {
|
} else {
|
||||||
location = lastLocation.get(permissionLevel, ignoreLocationSettings);
|
location = lastLocation.get(permissionLevel, isBypass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1925,7 +1961,7 @@ public class LocationProviderManager extends
|
|||||||
// provider, under the assumption that once we send the request off, the provider will
|
// provider, under the assumption that once we send the request off, the provider will
|
||||||
// immediately attempt to deliver a new location satisfying that request.
|
// immediately attempt to deliver a new location satisfying that request.
|
||||||
long delayMs;
|
long delayMs;
|
||||||
if (!oldRequest.isLocationSettingsIgnored() && newRequest.isLocationSettingsIgnored()) {
|
if (!oldRequest.isBypass() && newRequest.isBypass()) {
|
||||||
delayMs = 0;
|
delayMs = 0;
|
||||||
} else if (newRequest.getIntervalMillis() > oldRequest.getIntervalMillis()) {
|
} else if (newRequest.getIntervalMillis() > oldRequest.getIntervalMillis()) {
|
||||||
// if the interval has increased, tell the provider immediately, so it can save power
|
// if the interval has increased, tell the provider immediately, so it can save power
|
||||||
@@ -2002,12 +2038,12 @@ public class LocationProviderManager extends
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean locationSettingsIgnored = registration.getRequest().isLocationSettingsIgnored();
|
boolean isBypass = registration.getRequest().isBypass();
|
||||||
if (!isActive(locationSettingsIgnored, registration.getIdentity())) {
|
if (!isActive(isBypass, registration.getIdentity())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!locationSettingsIgnored) {
|
if (!isBypass) {
|
||||||
switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
|
switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
|
||||||
case LOCATION_MODE_FOREGROUND_ONLY:
|
case LOCATION_MODE_FOREGROUND_ONLY:
|
||||||
if (!registration.isForeground()) {
|
if (!registration.isForeground()) {
|
||||||
@@ -2036,15 +2072,15 @@ public class LocationProviderManager extends
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isActive(boolean locationSettingsIgnored, CallerIdentity identity) {
|
private boolean isActive(boolean isBypass, CallerIdentity identity) {
|
||||||
if (identity.isSystemServer()) {
|
if (identity.isSystemServer()) {
|
||||||
if (!locationSettingsIgnored) {
|
if (!isBypass) {
|
||||||
if (!isEnabled(mUserHelper.getCurrentUserId())) {
|
if (!isEnabled(mUserHelper.getCurrentUserId())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!locationSettingsIgnored) {
|
if (!isBypass) {
|
||||||
if (!isEnabled(identity.getUserId())) {
|
if (!isEnabled(identity.getUserId())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2071,6 +2107,7 @@ public class LocationProviderManager extends
|
|||||||
long intervalMs = ProviderRequest.INTERVAL_DISABLED;
|
long intervalMs = ProviderRequest.INTERVAL_DISABLED;
|
||||||
int quality = LocationRequest.QUALITY_LOW_POWER;
|
int quality = LocationRequest.QUALITY_LOW_POWER;
|
||||||
long maxUpdateDelayMs = Long.MAX_VALUE;
|
long maxUpdateDelayMs = Long.MAX_VALUE;
|
||||||
|
boolean adasGnssBypass = false;
|
||||||
boolean locationSettingsIgnored = false;
|
boolean locationSettingsIgnored = false;
|
||||||
boolean lowPower = true;
|
boolean lowPower = true;
|
||||||
|
|
||||||
@@ -2086,6 +2123,7 @@ public class LocationProviderManager extends
|
|||||||
intervalMs = min(request.getIntervalMillis(), intervalMs);
|
intervalMs = min(request.getIntervalMillis(), intervalMs);
|
||||||
quality = min(request.getQuality(), quality);
|
quality = min(request.getQuality(), quality);
|
||||||
maxUpdateDelayMs = min(request.getMaxUpdateDelayMillis(), maxUpdateDelayMs);
|
maxUpdateDelayMs = min(request.getMaxUpdateDelayMillis(), maxUpdateDelayMs);
|
||||||
|
adasGnssBypass |= request.isAdasGnssBypass();
|
||||||
locationSettingsIgnored |= request.isLocationSettingsIgnored();
|
locationSettingsIgnored |= request.isLocationSettingsIgnored();
|
||||||
lowPower &= request.isLowPower();
|
lowPower &= request.isLowPower();
|
||||||
}
|
}
|
||||||
@@ -2123,6 +2161,7 @@ public class LocationProviderManager extends
|
|||||||
.setIntervalMillis(intervalMs)
|
.setIntervalMillis(intervalMs)
|
||||||
.setQuality(quality)
|
.setQuality(quality)
|
||||||
.setMaxUpdateDelayMillis(maxUpdateDelayMs)
|
.setMaxUpdateDelayMillis(maxUpdateDelayMs)
|
||||||
|
.setAdasGnssBypass(adasGnssBypass)
|
||||||
.setLocationSettingsIgnored(locationSettingsIgnored)
|
.setLocationSettingsIgnored(locationSettingsIgnored)
|
||||||
.setLowPower(lowPower)
|
.setLowPower(lowPower)
|
||||||
.setWorkSource(workSource)
|
.setWorkSource(workSource)
|
||||||
@@ -2191,6 +2230,16 @@ public class LocationProviderManager extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
|
||||||
|
LocationUserSettings newSettings) {
|
||||||
|
if (oldSettings.isAdasGnssLocationEnabled() != newSettings.isAdasGnssLocationEnabled()) {
|
||||||
|
synchronized (mLock) {
|
||||||
|
updateRegistrations(
|
||||||
|
registration -> registration.onAdasGnssLocationEnabledChanged(userId));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void onLocationEnabledChanged(int userId) {
|
private void onLocationEnabledChanged(int userId) {
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
if (mState == STATE_STOPPED) {
|
if (mState == STATE_STOPPED) {
|
||||||
@@ -2560,16 +2609,16 @@ public class LocationProviderManager extends
|
|||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Location get(@PermissionLevel int permissionLevel,
|
public @Nullable Location get(@PermissionLevel int permissionLevel,
|
||||||
boolean ignoreLocationSettings) {
|
boolean isBypass) {
|
||||||
switch (permissionLevel) {
|
switch (permissionLevel) {
|
||||||
case PERMISSION_FINE:
|
case PERMISSION_FINE:
|
||||||
if (ignoreLocationSettings) {
|
if (isBypass) {
|
||||||
return mFineBypassLocation;
|
return mFineBypassLocation;
|
||||||
} else {
|
} else {
|
||||||
return mFineLocation;
|
return mFineLocation;
|
||||||
}
|
}
|
||||||
case PERMISSION_COARSE:
|
case PERMISSION_COARSE:
|
||||||
if (ignoreLocationSettings) {
|
if (isBypass) {
|
||||||
return mCoarseBypassLocation;
|
return mCoarseBypassLocation;
|
||||||
} else {
|
} else {
|
||||||
return mCoarseLocation;
|
return mCoarseLocation;
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.settings;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Environment;
|
||||||
|
import android.util.SparseArray;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.server.FgThread;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessor for location user settings. Ensure there is only ever one instance as multiple instances
|
||||||
|
* don't play nicely with each other.
|
||||||
|
*/
|
||||||
|
public class LocationSettings {
|
||||||
|
|
||||||
|
/** Listens for changes to location user settings. */
|
||||||
|
public interface LocationUserSettingsListener {
|
||||||
|
/** Invoked when location user settings have changed for the given user. */
|
||||||
|
void onLocationUserSettingsChanged(int userId, LocationUserSettings oldSettings,
|
||||||
|
LocationUserSettings newSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String LOCATION_DIRNAME = "location";
|
||||||
|
private static final String LOCATION_SETTINGS_FILENAME = "settings";
|
||||||
|
|
||||||
|
final Context mContext;
|
||||||
|
|
||||||
|
@GuardedBy("mUserSettings")
|
||||||
|
private final SparseArray<LocationUserSettingsStore> mUserSettings;
|
||||||
|
private final CopyOnWriteArrayList<LocationUserSettingsListener> mUserSettingsListeners;
|
||||||
|
|
||||||
|
public LocationSettings(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
mUserSettings = new SparseArray<>(1);
|
||||||
|
mUserSettingsListeners = new CopyOnWriteArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Registers a listener for changes to location user settings. */
|
||||||
|
public final void registerLocationUserSettingsListener(LocationUserSettingsListener listener) {
|
||||||
|
mUserSettingsListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unregisters a listener for changes to location user settings. */
|
||||||
|
public final void unregisterLocationUserSettingsListener(
|
||||||
|
LocationUserSettingsListener listener) {
|
||||||
|
mUserSettingsListeners.remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected File getUserSettingsDir(int userId) {
|
||||||
|
return Environment.getDataSystemDeDirectory(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected LocationUserSettingsStore createUserSettingsStore(int userId, File file) {
|
||||||
|
return new LocationUserSettingsStore(userId, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocationUserSettingsStore getUserSettingsStore(int userId) {
|
||||||
|
synchronized (mUserSettings) {
|
||||||
|
LocationUserSettingsStore settingsStore = mUserSettings.get(userId);
|
||||||
|
if (settingsStore == null) {
|
||||||
|
File file = new File(new File(getUserSettingsDir(userId), LOCATION_DIRNAME),
|
||||||
|
LOCATION_SETTINGS_FILENAME);
|
||||||
|
settingsStore = createUserSettingsStore(userId, file);
|
||||||
|
mUserSettings.put(userId, settingsStore);
|
||||||
|
}
|
||||||
|
return settingsStore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieves the current state of location user settings. */
|
||||||
|
public final LocationUserSettings getUserSettings(int userId) {
|
||||||
|
return getUserSettingsStore(userId).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Updates the current state of location user settings for the given user. */
|
||||||
|
public final void updateUserSettings(int userId,
|
||||||
|
Function<LocationUserSettings, LocationUserSettings> updater) {
|
||||||
|
getUserSettingsStore(userId).update(updater);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final void flushFiles() throws InterruptedException {
|
||||||
|
synchronized (mUserSettings) {
|
||||||
|
int size = mUserSettings.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
mUserSettings.valueAt(i).flushFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final void deleteFiles() throws InterruptedException {
|
||||||
|
synchronized (mUserSettings) {
|
||||||
|
int size = mUserSettings.size();
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
mUserSettings.valueAt(i).deleteFile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final void fireListeners(int userId, LocationUserSettings oldSettings,
|
||||||
|
LocationUserSettings newSettings) {
|
||||||
|
for (LocationUserSettingsListener listener : mUserSettingsListeners) {
|
||||||
|
listener.onLocationUserSettingsChanged(userId, oldSettings, newSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocationUserSettingsStore extends SettingsStore<LocationUserSettings> {
|
||||||
|
|
||||||
|
protected final int mUserId;
|
||||||
|
|
||||||
|
LocationUserSettingsStore(int userId, File file) {
|
||||||
|
super(file);
|
||||||
|
mUserId = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected LocationUserSettings read(int version, DataInput in) throws IOException {
|
||||||
|
return filterSettings(LocationUserSettings.read(mContext.getResources(), version, in));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void write(DataOutput out, LocationUserSettings settings) throws IOException {
|
||||||
|
settings.write(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Function<LocationUserSettings, LocationUserSettings> updater) {
|
||||||
|
super.update(settings -> filterSettings(updater.apply(settings)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onChange(LocationUserSettings oldSettings,
|
||||||
|
LocationUserSettings newSettings) {
|
||||||
|
FgThread.getExecutor().execute(() -> fireListeners(mUserId, oldSettings, newSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
private LocationUserSettings filterSettings(LocationUserSettings settings) {
|
||||||
|
if (settings.isAdasGnssLocationEnabled()
|
||||||
|
&& !mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE)) {
|
||||||
|
// prevent non-automotive devices from ever enabling this
|
||||||
|
settings = settings.withAdasGnssLocationEnabled(false);
|
||||||
|
}
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.settings;
|
||||||
|
|
||||||
|
import android.content.res.Resources;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/** Holds the state of location user settings. */
|
||||||
|
public final class LocationUserSettings implements SettingsStore.VersionedSettings {
|
||||||
|
|
||||||
|
// remember to bump this version code and add the appropriate upgrade logic whenever the format
|
||||||
|
// is changed.
|
||||||
|
private static final int VERSION = 1;
|
||||||
|
|
||||||
|
private final boolean mAdasGnssLocationEnabled;
|
||||||
|
|
||||||
|
private LocationUserSettings(boolean adasGnssLocationEnabled) {
|
||||||
|
mAdasGnssLocationEnabled = adasGnssLocationEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVersion() {
|
||||||
|
return VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAdasGnssLocationEnabled() {
|
||||||
|
return mAdasGnssLocationEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns an instance with ADAS GNSS location enabled state set as given. */
|
||||||
|
public LocationUserSettings withAdasGnssLocationEnabled(boolean adasEnabled) {
|
||||||
|
if (adasEnabled == mAdasGnssLocationEnabled) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LocationUserSettings(adasEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write(DataOutput out) throws IOException {
|
||||||
|
out.writeBoolean(mAdasGnssLocationEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LocationUserSettings read(Resources resources, int version, DataInput in)
|
||||||
|
throws IOException {
|
||||||
|
boolean adasGnssLocationEnabled;
|
||||||
|
|
||||||
|
// upgrade code goes here. remember to bump the version field when changing the format
|
||||||
|
switch (version) {
|
||||||
|
default:
|
||||||
|
// set all fields to defaults
|
||||||
|
adasGnssLocationEnabled = resources.getBoolean(
|
||||||
|
R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
adasGnssLocationEnabled = in.readBoolean();
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LocationUserSettings(adasGnssLocationEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!(o instanceof LocationUserSettings)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LocationUserSettings that = (LocationUserSettings) o;
|
||||||
|
return mAdasGnssLocationEnabled == that.mAdasGnssLocationEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(mAdasGnssLocationEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.settings;
|
||||||
|
|
||||||
|
import static com.android.server.location.LocationManagerService.TAG;
|
||||||
|
import static com.android.server.location.settings.SettingsStore.VersionedSettings.VERSION_DOES_NOT_EXIST;
|
||||||
|
|
||||||
|
import android.util.AtomicFile;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
|
import com.android.internal.os.BackgroundThread;
|
||||||
|
import com.android.internal.util.Preconditions;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInput;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/** Base class for read/write/versioning functionality for storing persistent settings to a file. */
|
||||||
|
abstract class SettingsStore<T extends SettingsStore.VersionedSettings> {
|
||||||
|
|
||||||
|
interface VersionedSettings {
|
||||||
|
/** Represents that the settings do not exist. */
|
||||||
|
int VERSION_DOES_NOT_EXIST = Integer.MAX_VALUE;
|
||||||
|
|
||||||
|
/** Must always return a version number less than {@link #VERSION_DOES_NOT_EXIST}. */
|
||||||
|
int getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final AtomicFile mFile;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
private boolean mInitialized;
|
||||||
|
@GuardedBy("this")
|
||||||
|
private T mCache;
|
||||||
|
|
||||||
|
protected SettingsStore(File file) {
|
||||||
|
mFile = new AtomicFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be implemented to read in a settings instance, and upgrade to the appropriate version
|
||||||
|
* where necessary. If the provided version is {@link VersionedSettings#VERSION_DOES_NOT_EXIST}
|
||||||
|
* then the DataInput will be empty, and the method should return a settings instance with all
|
||||||
|
* settings set to the default value.
|
||||||
|
*/
|
||||||
|
protected abstract T read(int version, DataInput in) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be implemented to write the given settings to the given DataOutput.
|
||||||
|
*/
|
||||||
|
protected abstract void write(DataOutput out, T settings) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invoked when settings change, and while holding the internal lock. If used to invoke
|
||||||
|
* listeners, ensure they are not invoked while holding the lock (ie, asynchronously).
|
||||||
|
*/
|
||||||
|
protected abstract void onChange(T oldSettings, T newSettings);
|
||||||
|
|
||||||
|
public final synchronized void initializeCache() {
|
||||||
|
if (!mInitialized) {
|
||||||
|
if (mFile.exists()) {
|
||||||
|
try (DataInputStream is = new DataInputStream(mFile.openRead())) {
|
||||||
|
mCache = read(is.readInt(), is);
|
||||||
|
Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "error reading location settings (" + mFile
|
||||||
|
+ "), falling back to defaults", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mCache == null) {
|
||||||
|
try {
|
||||||
|
mCache = read(VERSION_DOES_NOT_EXIST,
|
||||||
|
new DataInputStream(new ByteArrayInputStream(new byte[0])));
|
||||||
|
Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mInitialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final synchronized T get() {
|
||||||
|
initializeCache();
|
||||||
|
return mCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void update(Function<T, T> updater) {
|
||||||
|
initializeCache();
|
||||||
|
|
||||||
|
T oldSettings = mCache;
|
||||||
|
T newSettings = Objects.requireNonNull(updater.apply(oldSettings));
|
||||||
|
if (oldSettings.equals(newSettings)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mCache = newSettings;
|
||||||
|
Preconditions.checkState(mCache.getVersion() < VERSION_DOES_NOT_EXIST);
|
||||||
|
|
||||||
|
writeLazily(newSettings);
|
||||||
|
|
||||||
|
onChange(oldSettings, newSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
synchronized void flushFile() throws InterruptedException {
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
BackgroundThread.getExecutor().execute(latch::countDown);
|
||||||
|
latch.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
synchronized void deleteFile() throws InterruptedException {
|
||||||
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
BackgroundThread.getExecutor().execute(() -> {
|
||||||
|
mFile.delete();
|
||||||
|
latch.countDown();
|
||||||
|
});
|
||||||
|
latch.await();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeLazily(T settings) {
|
||||||
|
BackgroundThread.getExecutor().execute(() -> {
|
||||||
|
FileOutputStream os = null;
|
||||||
|
try {
|
||||||
|
os = mFile.startWrite();
|
||||||
|
DataOutputStream out = new DataOutputStream(os);
|
||||||
|
out.writeInt(settings.getVersion());
|
||||||
|
write(out, settings);
|
||||||
|
mFile.finishWrite(os);
|
||||||
|
} catch (IOException e) {
|
||||||
|
mFile.failWrite(os);
|
||||||
|
Log.e(TAG, "failure serializing location settings", e);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
mFile.failWrite(os);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@ package com.android.server.location.gnss;
|
|||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
@@ -49,6 +50,7 @@ public class GnssGeofenceProxyTest {
|
|||||||
private static final int NOTIFICATION_RESPONSIVENESS = 0;
|
private static final int NOTIFICATION_RESPONSIVENESS = 0;
|
||||||
private static final int UNKNOWN_TIMER = 0;
|
private static final int UNKNOWN_TIMER = 0;
|
||||||
|
|
||||||
|
private @Mock Context mContext;
|
||||||
private @Mock GnssConfiguration mMockConfiguration;
|
private @Mock GnssConfiguration mMockConfiguration;
|
||||||
private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks;
|
private @Mock GnssNative.GeofenceCallbacks mGeofenceCallbacks;
|
||||||
|
|
||||||
@@ -63,7 +65,7 @@ public class GnssGeofenceProxyTest {
|
|||||||
GnssNative.setGnssHalForTest(mFakeHal);
|
GnssNative.setGnssHalForTest(mFakeHal);
|
||||||
|
|
||||||
GnssNative gnssNative = Objects.requireNonNull(
|
GnssNative gnssNative = Objects.requireNonNull(
|
||||||
GnssNative.create(new TestInjector(), mMockConfiguration));
|
GnssNative.create(new TestInjector(mContext), mMockConfiguration));
|
||||||
gnssNative.setGeofenceCallbacks(mGeofenceCallbacks);
|
gnssNative.setGeofenceCallbacks(mGeofenceCallbacks);
|
||||||
mTestProvider = new GnssGeofenceProxy(gnssNative);
|
mTestProvider = new GnssGeofenceProxy(gnssNative);
|
||||||
gnssNative.register();
|
gnssNative.register();
|
||||||
|
|||||||
@@ -29,9 +29,10 @@ import java.util.HashMap;
|
|||||||
public class FakeAppOpsHelper extends AppOpsHelper {
|
public class FakeAppOpsHelper extends AppOpsHelper {
|
||||||
|
|
||||||
private static class AppOp {
|
private static class AppOp {
|
||||||
private boolean mAllowed = true;
|
AppOp() {}
|
||||||
private boolean mStarted = false;
|
boolean mAllowed = true;
|
||||||
private int mNoteCount = 0;
|
boolean mStarted = false;
|
||||||
|
int mNoteCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final HashMap<String, SparseArray<AppOp>> mAppOps;
|
private final HashMap<String, SparseArray<AppOp>> mAppOps;
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import java.util.Set;
|
|||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version of AppOpsHelper for testing. Settings are initialized to reasonable defaults (location is
|
* Version of SettingsHelper for testing. Settings are initialized to reasonable defaults (location
|
||||||
* enabled by default).
|
* is enabled by default).
|
||||||
*/
|
*/
|
||||||
public class FakeSettingsHelper extends SettingsHelper {
|
public class FakeSettingsHelper extends SettingsHelper {
|
||||||
|
|
||||||
|
|||||||
@@ -16,9 +16,14 @@
|
|||||||
|
|
||||||
package com.android.server.location.injector;
|
package com.android.server.location.injector;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.android.server.location.settings.FakeLocationSettings;
|
||||||
|
|
||||||
public class TestInjector implements Injector {
|
public class TestInjector implements Injector {
|
||||||
|
|
||||||
private final FakeUserInfoHelper mUserInfoHelper;
|
private final FakeUserInfoHelper mUserInfoHelper;
|
||||||
|
private final FakeLocationSettings mLocationSettings;
|
||||||
private final FakeAlarmHelper mAlarmHelper;
|
private final FakeAlarmHelper mAlarmHelper;
|
||||||
private final FakeAppOpsHelper mAppOpsHelper;
|
private final FakeAppOpsHelper mAppOpsHelper;
|
||||||
private final FakeLocationPermissionsHelper mLocationPermissionsHelper;
|
private final FakeLocationPermissionsHelper mLocationPermissionsHelper;
|
||||||
@@ -32,8 +37,9 @@ public class TestInjector implements Injector {
|
|||||||
private final FakeEmergencyHelper mEmergencyHelper;
|
private final FakeEmergencyHelper mEmergencyHelper;
|
||||||
private final LocationUsageLogger mLocationUsageLogger;
|
private final LocationUsageLogger mLocationUsageLogger;
|
||||||
|
|
||||||
public TestInjector() {
|
public TestInjector(Context context) {
|
||||||
mUserInfoHelper = new FakeUserInfoHelper();
|
mUserInfoHelper = new FakeUserInfoHelper();
|
||||||
|
mLocationSettings = new FakeLocationSettings(context);
|
||||||
mAlarmHelper = new FakeAlarmHelper();
|
mAlarmHelper = new FakeAlarmHelper();
|
||||||
mAppOpsHelper = new FakeAppOpsHelper();
|
mAppOpsHelper = new FakeAppOpsHelper();
|
||||||
mLocationPermissionsHelper = new FakeLocationPermissionsHelper(mAppOpsHelper);
|
mLocationPermissionsHelper = new FakeLocationPermissionsHelper(mAppOpsHelper);
|
||||||
@@ -53,6 +59,11 @@ public class TestInjector implements Injector {
|
|||||||
return mUserInfoHelper;
|
return mUserInfoHelper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FakeLocationSettings getLocationSettings() {
|
||||||
|
return mLocationSettings;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FakeAlarmHelper getAlarmHelper() {
|
public FakeAlarmHelper getAlarmHelper() {
|
||||||
return mAlarmHelper;
|
return mAlarmHelper;
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ package com.android.server.location.provider;
|
|||||||
import static android.app.AppOpsManager.OP_FINE_LOCATION;
|
import static android.app.AppOpsManager.OP_FINE_LOCATION;
|
||||||
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
|
import static android.app.AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION;
|
||||||
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
|
import static android.app.AppOpsManager.OP_MONITOR_LOCATION;
|
||||||
|
import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
|
||||||
|
import static android.location.LocationManager.GPS_PROVIDER;
|
||||||
import static android.location.LocationRequest.PASSIVE_INTERVAL;
|
import static android.location.LocationRequest.PASSIVE_INTERVAL;
|
||||||
import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH;
|
import static android.location.provider.ProviderProperties.POWER_USAGE_HIGH;
|
||||||
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
|
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
|
||||||
@@ -56,6 +58,8 @@ import static org.mockito.MockitoAnnotations.initMocks;
|
|||||||
import static org.testng.Assert.assertThrows;
|
import static org.testng.Assert.assertThrows;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.res.Resources;
|
||||||
import android.location.ILocationCallback;
|
import android.location.ILocationCallback;
|
||||||
import android.location.ILocationListener;
|
import android.location.ILocationListener;
|
||||||
import android.location.LastLocationRequest;
|
import android.location.LastLocationRequest;
|
||||||
@@ -82,6 +86,7 @@ import android.util.Log;
|
|||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
import com.android.server.FgThread;
|
import com.android.server.FgThread;
|
||||||
import com.android.server.LocalServices;
|
import com.android.server.LocalServices;
|
||||||
import com.android.server.location.injector.FakeUserInfoHelper;
|
import com.android.server.location.injector.FakeUserInfoHelper;
|
||||||
@@ -139,6 +144,10 @@ public class LocationProviderManagerTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
@Mock
|
@Mock
|
||||||
|
private Resources mResources;
|
||||||
|
@Mock
|
||||||
|
private PackageManager mPackageManager;
|
||||||
|
@Mock
|
||||||
private PowerManager mPowerManager;
|
private PowerManager mPowerManager;
|
||||||
@Mock
|
@Mock
|
||||||
private PowerManager.WakeLock mWakeLock;
|
private PowerManager.WakeLock mWakeLock;
|
||||||
@@ -161,20 +170,28 @@ public class LocationProviderManagerTest {
|
|||||||
LocalServices.addService(LocationManagerInternal.class, mInternal);
|
LocalServices.addService(LocationManagerInternal.class, mInternal);
|
||||||
|
|
||||||
doReturn("android").when(mContext).getPackageName();
|
doReturn("android").when(mContext).getPackageName();
|
||||||
|
doReturn(mResources).when(mContext).getResources();
|
||||||
|
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||||
doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
|
doReturn(mPowerManager).when(mContext).getSystemService(PowerManager.class);
|
||||||
doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
|
doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
|
||||||
|
|
||||||
mInjector = new TestInjector();
|
mInjector = new TestInjector(mContext);
|
||||||
mInjector.getUserInfoHelper().startUser(OTHER_USER);
|
mInjector.getUserInfoHelper().startUser(OTHER_USER);
|
||||||
|
|
||||||
mPassive = new PassiveLocationProviderManager(mContext, mInjector);
|
mPassive = new PassiveLocationProviderManager(mContext, mInjector);
|
||||||
mPassive.startManager(null);
|
mPassive.startManager(null);
|
||||||
mPassive.setRealProvider(new PassiveLocationProvider(mContext));
|
mPassive.setRealProvider(new PassiveLocationProvider(mContext));
|
||||||
|
|
||||||
|
createManager(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createManager(String name) {
|
||||||
|
mStateChangedListener = mock(LocationProviderManager.StateChangedListener.class);
|
||||||
|
|
||||||
mProvider = new TestProvider(PROPERTIES, PROVIDER_IDENTITY);
|
mProvider = new TestProvider(PROPERTIES, PROVIDER_IDENTITY);
|
||||||
mProvider.setProviderAllowed(true);
|
mProvider.setProviderAllowed(true);
|
||||||
|
|
||||||
mManager = new LocationProviderManager(mContext, mInjector, NAME, mPassive);
|
mManager = new LocationProviderManager(mContext, mInjector, name, mPassive);
|
||||||
mManager.startManager(mStateChangedListener);
|
mManager.startManager(mStateChangedListener);
|
||||||
mManager.setRealProvider(mProvider);
|
mManager.setRealProvider(mProvider);
|
||||||
}
|
}
|
||||||
@@ -1016,6 +1033,95 @@ public class LocationProviderManagerTest {
|
|||||||
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
|
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProviderRequest_AdasGnssBypass() {
|
||||||
|
doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
|
||||||
|
doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
|
||||||
|
createManager(GPS_PROVIDER);
|
||||||
|
|
||||||
|
ILocationListener listener1 = createMockLocationListener();
|
||||||
|
LocationRequest request1 = new LocationRequest.Builder(5)
|
||||||
|
.setWorkSource(WORK_SOURCE)
|
||||||
|
.build();
|
||||||
|
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
|
||||||
|
|
||||||
|
assertThat(mProvider.getRequest().isActive()).isTrue();
|
||||||
|
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
|
||||||
|
assertThat(mProvider.getRequest().isAdasGnssBypass()).isFalse();
|
||||||
|
|
||||||
|
ILocationListener listener2 = createMockLocationListener();
|
||||||
|
LocationRequest request2 = new LocationRequest.Builder(1)
|
||||||
|
.setAdasGnssBypass(true)
|
||||||
|
.setWorkSource(WORK_SOURCE)
|
||||||
|
.build();
|
||||||
|
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
|
||||||
|
|
||||||
|
assertThat(mProvider.getRequest().isActive()).isTrue();
|
||||||
|
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(1);
|
||||||
|
assertThat(mProvider.getRequest().isAdasGnssBypass()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProviderRequest_AdasGnssBypass_ProviderDisabled() {
|
||||||
|
doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
|
||||||
|
doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
|
||||||
|
createManager(GPS_PROVIDER);
|
||||||
|
|
||||||
|
ILocationListener listener1 = createMockLocationListener();
|
||||||
|
LocationRequest request1 = new LocationRequest.Builder(1)
|
||||||
|
.setWorkSource(WORK_SOURCE)
|
||||||
|
.build();
|
||||||
|
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
|
||||||
|
|
||||||
|
ILocationListener listener2 = createMockLocationListener();
|
||||||
|
LocationRequest request2 = new LocationRequest.Builder(5)
|
||||||
|
.setAdasGnssBypass(true)
|
||||||
|
.setWorkSource(WORK_SOURCE)
|
||||||
|
.build();
|
||||||
|
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
|
||||||
|
|
||||||
|
mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
|
||||||
|
|
||||||
|
assertThat(mProvider.getRequest().isActive()).isTrue();
|
||||||
|
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
|
||||||
|
assertThat(mProvider.getRequest().isAdasGnssBypass()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testProviderRequest_AdasGnssBypass_ProviderDisabled_AdasDisabled() {
|
||||||
|
mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
|
||||||
|
new PackageTagsList.Builder().add(
|
||||||
|
IDENTITY.getPackageName()).build());
|
||||||
|
doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
|
||||||
|
doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
|
||||||
|
createManager(GPS_PROVIDER);
|
||||||
|
|
||||||
|
ILocationListener listener1 = createMockLocationListener();
|
||||||
|
LocationRequest request1 = new LocationRequest.Builder(5)
|
||||||
|
.setLocationSettingsIgnored(true)
|
||||||
|
.setWorkSource(WORK_SOURCE)
|
||||||
|
.build();
|
||||||
|
mManager.registerLocationRequest(request1, IDENTITY, PERMISSION_FINE, listener1);
|
||||||
|
|
||||||
|
ILocationListener listener2 = createMockLocationListener();
|
||||||
|
LocationRequest request2 = new LocationRequest.Builder(1)
|
||||||
|
.setAdasGnssBypass(true)
|
||||||
|
.setWorkSource(WORK_SOURCE)
|
||||||
|
.build();
|
||||||
|
mManager.registerLocationRequest(request2, IDENTITY, PERMISSION_FINE, listener2);
|
||||||
|
|
||||||
|
mInjector.getLocationSettings().updateUserSettings(IDENTITY.getUserId(),
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(false));
|
||||||
|
mInjector.getSettingsHelper().setLocationEnabled(false, IDENTITY.getUserId());
|
||||||
|
|
||||||
|
assertThat(mProvider.getRequest().isActive()).isTrue();
|
||||||
|
assertThat(mProvider.getRequest().getIntervalMillis()).isEqualTo(5);
|
||||||
|
assertThat(mProvider.getRequest().isAdasGnssBypass()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProviderRequest_BatterySaver_ScreenOnOff() {
|
public void testProviderRequest_BatterySaver_ScreenOnOff() {
|
||||||
mInjector.getLocationPowerSaveModeHelper().setLocationPowerSaveMode(
|
mInjector.getLocationPowerSaveModeHelper().setLocationPowerSaveMode(
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.times;
|
|||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.MockitoAnnotations.initMocks;
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.location.LocationResult;
|
import android.location.LocationResult;
|
||||||
import android.location.provider.ProviderRequest;
|
import android.location.provider.ProviderRequest;
|
||||||
@@ -58,6 +59,7 @@ public class StationaryThrottlingLocationProviderTest {
|
|||||||
private TestInjector mInjector;
|
private TestInjector mInjector;
|
||||||
private FakeProvider mDelegateProvider;
|
private FakeProvider mDelegateProvider;
|
||||||
|
|
||||||
|
private @Mock Context mContext;
|
||||||
private @Mock AbstractLocationProvider.Listener mListener;
|
private @Mock AbstractLocationProvider.Listener mListener;
|
||||||
private @Mock FakeProvider.FakeProviderInterface mDelegate;
|
private @Mock FakeProvider.FakeProviderInterface mDelegate;
|
||||||
|
|
||||||
@@ -72,7 +74,7 @@ public class StationaryThrottlingLocationProviderTest {
|
|||||||
|
|
||||||
mRandom = new Random(seed);
|
mRandom = new Random(seed);
|
||||||
|
|
||||||
mInjector = new TestInjector();
|
mInjector = new TestInjector(mContext);
|
||||||
mDelegateProvider = new FakeProvider(mDelegate);
|
mDelegateProvider = new FakeProvider(mDelegate);
|
||||||
|
|
||||||
mProvider = new StationaryThrottlingLocationProvider("test_provider", mInjector,
|
mProvider = new StationaryThrottlingLocationProvider("test_provider", mInjector,
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.settings;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class FakeLocationSettings extends LocationSettings {
|
||||||
|
|
||||||
|
public FakeLocationSettings(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected File getUserSettingsDir(int userId) {
|
||||||
|
return ApplicationProvider.getApplicationContext().getCacheDir();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected LocationUserSettingsStore createUserSettingsStore(int userId, File file) {
|
||||||
|
return new FakeLocationUserSettingsStore(userId, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FakeLocationUserSettingsStore extends LocationUserSettingsStore {
|
||||||
|
|
||||||
|
FakeLocationUserSettingsStore(int userId, File file) {
|
||||||
|
super(userId, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onChange(LocationUserSettings oldSettings,
|
||||||
|
LocationUserSettings newSettings) {
|
||||||
|
fireListeners(mUserId, oldSettings, newSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 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.settings;
|
||||||
|
|
||||||
|
import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyInt;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.after;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.timeout;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.MockitoAnnotations.initMocks;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
@Presubmit
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class LocationSettingsTest {
|
||||||
|
|
||||||
|
private @Mock Context mContext;
|
||||||
|
private @Mock Resources mResources;
|
||||||
|
private @Mock PackageManager mPackageManager;
|
||||||
|
|
||||||
|
private LocationSettings mLocationSettings;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
initMocks(this);
|
||||||
|
|
||||||
|
doReturn(mResources).when(mContext).getResources();
|
||||||
|
doReturn(mPackageManager).when(mContext).getPackageManager();
|
||||||
|
doReturn(true).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
|
||||||
|
|
||||||
|
resetLocationSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
mLocationSettings.deleteFiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetLocationSettings() {
|
||||||
|
mLocationSettings = new LocationSettings(mContext) {
|
||||||
|
@Override
|
||||||
|
protected File getUserSettingsDir(int userId) {
|
||||||
|
return ApplicationProvider.getApplicationContext().getCacheDir();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadDefaults() {
|
||||||
|
doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
|
||||||
|
|
||||||
|
doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
assertThat(mLocationSettings.getUserSettings(2).isAdasGnssLocationEnabled()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdate() {
|
||||||
|
doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
mLocationSettings.updateUserSettings(1,
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(true));
|
||||||
|
assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
|
||||||
|
|
||||||
|
mLocationSettings.updateUserSettings(1,
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(false));
|
||||||
|
assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSerialization() throws Exception {
|
||||||
|
doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
mLocationSettings.updateUserSettings(1,
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(true));
|
||||||
|
assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
|
||||||
|
|
||||||
|
mLocationSettings.flushFiles();
|
||||||
|
resetLocationSettings();
|
||||||
|
assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListeners() {
|
||||||
|
doReturn(false).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
LocationSettings.LocationUserSettingsListener listener = mock(
|
||||||
|
LocationSettings.LocationUserSettingsListener.class);
|
||||||
|
|
||||||
|
mLocationSettings.registerLocationUserSettingsListener(listener);
|
||||||
|
|
||||||
|
ArgumentCaptor<LocationUserSettings> oldCaptor = ArgumentCaptor.forClass(
|
||||||
|
LocationUserSettings.class);
|
||||||
|
ArgumentCaptor<LocationUserSettings> newCaptor = ArgumentCaptor.forClass(
|
||||||
|
LocationUserSettings.class);
|
||||||
|
mLocationSettings.updateUserSettings(1,
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(true));
|
||||||
|
verify(listener, timeout(500).times(1)).onLocationUserSettingsChanged(eq(1),
|
||||||
|
oldCaptor.capture(), newCaptor.capture());
|
||||||
|
assertThat(oldCaptor.getValue().isAdasGnssLocationEnabled()).isFalse();
|
||||||
|
assertThat(newCaptor.getValue().isAdasGnssLocationEnabled()).isTrue();
|
||||||
|
|
||||||
|
oldCaptor = ArgumentCaptor.forClass(LocationUserSettings.class);
|
||||||
|
newCaptor = ArgumentCaptor.forClass(LocationUserSettings.class);
|
||||||
|
mLocationSettings.updateUserSettings(1,
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(false));
|
||||||
|
verify(listener, timeout(500).times(2)).onLocationUserSettingsChanged(eq(1),
|
||||||
|
oldCaptor.capture(), newCaptor.capture());
|
||||||
|
assertThat(oldCaptor.getValue().isAdasGnssLocationEnabled()).isTrue();
|
||||||
|
assertThat(newCaptor.getValue().isAdasGnssLocationEnabled()).isFalse();
|
||||||
|
|
||||||
|
mLocationSettings.unregisterLocationUserSettingsListener(listener);
|
||||||
|
mLocationSettings.updateUserSettings(1,
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(true));
|
||||||
|
verify(listener, after(500).times(2)).onLocationUserSettingsChanged(anyInt(), any(), any());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNonAutomotive() {
|
||||||
|
doReturn(false).when(mPackageManager).hasSystemFeature(FEATURE_AUTOMOTIVE);
|
||||||
|
doReturn(true).when(mResources).getBoolean(R.bool.config_defaultAdasGnssLocationEnabled);
|
||||||
|
|
||||||
|
LocationSettings.LocationUserSettingsListener listener = mock(
|
||||||
|
LocationSettings.LocationUserSettingsListener.class);
|
||||||
|
mLocationSettings.registerLocationUserSettingsListener(listener);
|
||||||
|
|
||||||
|
assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
|
||||||
|
mLocationSettings.updateUserSettings(1,
|
||||||
|
settings -> settings.withAdasGnssLocationEnabled(true));
|
||||||
|
assertThat(mLocationSettings.getUserSettings(1).isAdasGnssLocationEnabled()).isFalse();
|
||||||
|
verify(listener, after(500).never()).onLocationUserSettingsChanged(anyInt(), any(), any());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user