Update location broadcast behavior
Updates location broadcast behavior in preparation for future changes that will remove writes to LOCATION_PROVIDERS_ALLOWED. These changes ensure that clients can properly listen for changes to provider enabled status without being reliant on the deprecated LOCATION_PROVIDERS_ALLOWED. Bug: 145752928 Test: presubmits Change-Id: I073749a895a6a206023290d83ea815a361353460
This commit is contained in:
@@ -23263,6 +23263,8 @@ package android.location {
|
||||
method public void unregisterGnssMeasurementsCallback(@NonNull android.location.GnssMeasurementsEvent.Callback);
|
||||
method public void unregisterGnssNavigationMessageCallback(@NonNull android.location.GnssNavigationMessage.Callback);
|
||||
method public void unregisterGnssStatusCallback(@NonNull android.location.GnssStatus.Callback);
|
||||
field public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
|
||||
field public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
|
||||
field public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
|
||||
field public static final String GPS_PROVIDER = "gps";
|
||||
field public static final String KEY_LOCATION_CHANGED = "location";
|
||||
|
||||
@@ -164,24 +164,51 @@ public class LocationManager {
|
||||
* Broadcast intent action when the set of enabled location providers changes. To check the
|
||||
* status of a provider, use {@link #isProviderEnabled(String)}. From Android Q and above, will
|
||||
* include a string intent extra, {@link #EXTRA_PROVIDER_NAME}, with the name of the provider
|
||||
* whose state has changed.
|
||||
* whose state has changed. From Android R and above, will include a boolean intent extra,
|
||||
* {@link #EXTRA_PROVIDER_ENABLED}, with the enabled state of the provider.
|
||||
*
|
||||
* @see #EXTRA_PROVIDER_NAME
|
||||
* @see #EXTRA_PROVIDER_ENABLED
|
||||
* @see #isProviderEnabled(String)
|
||||
*/
|
||||
public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
|
||||
|
||||
/**
|
||||
* Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the name
|
||||
* of the location provider that has changed, to be used with location provider APIs.
|
||||
* of the location provider that has changed.
|
||||
*
|
||||
* @see #PROVIDERS_CHANGED_ACTION
|
||||
* @see #EXTRA_PROVIDER_ENABLED
|
||||
*/
|
||||
public static final String EXTRA_PROVIDER_NAME = "android.location.extra.PROVIDER_NAME";
|
||||
|
||||
/**
|
||||
* Broadcast intent action when the device location mode changes. To check the location mode,
|
||||
* use {@link #isLocationEnabled()}.
|
||||
* Intent extra included with {@link #PROVIDERS_CHANGED_ACTION} broadcasts, containing the
|
||||
* boolean enabled state of the location provider that has changed.
|
||||
*
|
||||
* @see #PROVIDERS_CHANGED_ACTION
|
||||
* @see #EXTRA_PROVIDER_NAME
|
||||
*/
|
||||
public static final String EXTRA_PROVIDER_ENABLED = "android.location.extra.PROVIDER_ENABLED";
|
||||
|
||||
/**
|
||||
* Broadcast intent action when the device location enabled state changes. From Android R and
|
||||
* above, will include a boolean intent extra, {@link #EXTRA_LOCATION_ENABLED}, with the enabled
|
||||
* state of location.
|
||||
*
|
||||
* @see #EXTRA_LOCATION_ENABLED
|
||||
* @see #isLocationEnabled()
|
||||
*/
|
||||
public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
|
||||
|
||||
/**
|
||||
* Intent extra included with {@link #MODE_CHANGED_ACTION} broadcasts, containing the boolean
|
||||
* enabled state of location.
|
||||
*
|
||||
* @see #MODE_CHANGED_ACTION
|
||||
*/
|
||||
public static final String EXTRA_LOCATION_ENABLED = "android.location.extra.LOCATION_ENABLED";
|
||||
|
||||
/**
|
||||
* Broadcast intent action indicating that a high power location requests
|
||||
* has either started or stopped being active. The current state of
|
||||
|
||||
@@ -81,6 +81,7 @@ import android.text.TextUtils;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -339,7 +340,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
mSettingsStore.addOnLocationEnabledChangedListener((userId) -> {
|
||||
synchronized (mLock) {
|
||||
onLocationModeChangedLocked(userId, true);
|
||||
onLocationModeChangedLocked(userId);
|
||||
}
|
||||
});
|
||||
mSettingsStore.addOnLocationProvidersAllowedChangedListener((userId) -> {
|
||||
@@ -467,36 +468,24 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onLocationModeChangedLocked(int userId, boolean broadcast) {
|
||||
if (!isCurrentProfileLocked(userId)) {
|
||||
return;
|
||||
private void onLocationModeChangedLocked(int userId) {
|
||||
if (D) {
|
||||
Log.d(TAG, "[u" + userId + "] location enabled = " + isLocationEnabledForUser(userId));
|
||||
}
|
||||
|
||||
if (D) {
|
||||
Log.d(TAG, "location enabled is now " + isLocationEnabled());
|
||||
}
|
||||
Intent intent = new Intent(LocationManager.MODE_CHANGED_ACTION);
|
||||
intent.putExtra(LocationManager.EXTRA_LOCATION_ENABLED, isLocationEnabled());
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
|
||||
|
||||
for (LocationProvider p : mProviders) {
|
||||
p.onLocationModeChangedLocked();
|
||||
}
|
||||
|
||||
if (broadcast) {
|
||||
// needs to be sent to everyone because we don't know which user may have changed
|
||||
// LOCATION_MODE state.
|
||||
mContext.sendBroadcastAsUser(
|
||||
new Intent(LocationManager.MODE_CHANGED_ACTION),
|
||||
UserHandle.ALL);
|
||||
p.onLocationModeChangedLocked(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void onProviderAllowedChangedLocked(int userId) {
|
||||
if (!isCurrentProfileLocked(userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (LocationProvider p : mProviders) {
|
||||
p.onAllowedChangedLocked();
|
||||
p.onAllowedChangedLocked(userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -798,21 +787,14 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
Log.d(TAG, "foreground user is changing to " + userId);
|
||||
}
|
||||
|
||||
// let providers know the current user is on the way out before changing the user
|
||||
for (LocationProvider p : mProviders) {
|
||||
p.onUserChangingLocked();
|
||||
}
|
||||
|
||||
int oldUserId = userId;
|
||||
mCurrentUserId = userId;
|
||||
onUserProfilesChangedLocked();
|
||||
|
||||
// if the user changes, per-user settings may also have changed
|
||||
onLocationModeChangedLocked(userId, false);
|
||||
onProviderAllowedChangedLocked(userId);
|
||||
|
||||
// always force useability to be rechecked, even if no per-user settings have changed
|
||||
// let providers know the current user has changed
|
||||
for (LocationProvider p : mProviders) {
|
||||
p.onUseableChangedLocked(false);
|
||||
p.onCurrentUserChangedLocked(oldUserId);
|
||||
p.onCurrentUserChangedLocked(mCurrentUserId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,7 +814,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
protected AbstractLocationProvider mProvider;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean mUseable; // combined state
|
||||
private SparseArray<Boolean> mUseable; // combined state for each user id
|
||||
@GuardedBy("mLock")
|
||||
private boolean mAllowed; // state of LOCATION_PROVIDERS_ALLOWED
|
||||
@GuardedBy("mLock")
|
||||
@@ -851,7 +833,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
mIsManagedBySettings = isManagedBySettings;
|
||||
|
||||
mProvider = null;
|
||||
mUseable = false;
|
||||
mUseable = new SparseArray<>(1);
|
||||
mAllowed = !mIsManagedBySettings;
|
||||
mEnabled = false;
|
||||
mProperties = null;
|
||||
@@ -876,7 +858,10 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
mProvider = provider;
|
||||
onUseableChangedLocked(false);
|
||||
|
||||
// it would be more correct to call this for all users, but we know this can only
|
||||
// affect the current user since providers are disabled for non-current users
|
||||
onUseableChangedLocked(false, mCurrentUserId);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -943,8 +928,8 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
pw.increaseIndent();
|
||||
|
||||
pw.println("useable=" + mUseable);
|
||||
if (!mUseable) {
|
||||
pw.println("useable=" + isUseableLocked(mCurrentUserId));
|
||||
if (!isUseableLocked(mCurrentUserId)) {
|
||||
pw.println("attached=" + (mProvider != null));
|
||||
if (mIsManagedBySettings) {
|
||||
pw.println("allowed=" + mAllowed);
|
||||
@@ -1009,7 +994,10 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
mEnabled = enabled;
|
||||
onUseableChangedLocked(false);
|
||||
|
||||
// it would be more correct to call this for all users, but we know this can only
|
||||
// affect the current user since providers are disabled for non-current users
|
||||
onUseableChangedLocked(false, mCurrentUserId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1021,12 +1009,20 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
public void onLocationModeChangedLocked() {
|
||||
onUseableChangedLocked(false);
|
||||
public void onLocationModeChangedLocked(int userId) {
|
||||
if (!isCurrentProfileLocked(userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
onUseableChangedLocked(false, userId);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
public void onAllowedChangedLocked() {
|
||||
public void onAllowedChangedLocked(int userId) {
|
||||
if (!isCurrentProfileLocked(userId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsManagedBySettings) {
|
||||
boolean allowed = mSettingsStore.getLocationProvidersAllowed(
|
||||
mCurrentUserId).contains(mName);
|
||||
@@ -1040,37 +1036,36 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
}
|
||||
|
||||
mAllowed = allowed;
|
||||
onUseableChangedLocked(true);
|
||||
onUseableChangedLocked(true, userId);
|
||||
}
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
public void onCurrentUserChangedLocked(int userId) {
|
||||
onUseableChangedLocked(false, userId);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
public boolean isUseableLocked() {
|
||||
return isUseableForUserLocked(mCurrentUserId);
|
||||
return isUseableLocked(mCurrentUserId);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
public boolean isUseableForUserLocked(int userId) {
|
||||
return isCurrentProfileLocked(userId) && mUseable;
|
||||
public boolean isUseableLocked(int userId) {
|
||||
return mUseable.get(userId, Boolean.FALSE);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private boolean isUseableIgnoringAllowedLocked() {
|
||||
return mProvider != null && mProviders.contains(this) && isLocationEnabled()
|
||||
&& mEnabled;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
public void onUseableChangedLocked(boolean isAllowedChanged) {
|
||||
public void onUseableChangedLocked(boolean isAllowedChanged, int userId) {
|
||||
// if any property that contributes to "useability" here changes state, it MUST result
|
||||
// in a direct or indrect call to onUseableChangedLocked. this allows the provider to
|
||||
// guarantee that it will always eventually reach the correct state.
|
||||
boolean useableIgnoringAllowed = isUseableIgnoringAllowedLocked();
|
||||
boolean useableIgnoringAllowed = mProvider != null && mProviders.contains(this)
|
||||
&& isCurrentProfileLocked(userId) && isLocationEnabledForUser(userId)
|
||||
&& mEnabled;
|
||||
boolean useable = useableIgnoringAllowed && mAllowed;
|
||||
|
||||
// update deprecated provider allowed settings for backwards compatibility, and do this
|
||||
// even if there is no change in overall useability state. this may result in trying to
|
||||
// overwrite the same value, but Settings handles deduping this.
|
||||
// update deprecated provider allowed settings for backwards compatibility
|
||||
if (mIsManagedBySettings) {
|
||||
// a "-" change derived from the allowed setting should not be overwritten, but a
|
||||
// "+" change should be corrected if necessary
|
||||
@@ -1079,33 +1074,31 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
|
||||
"+" + mName,
|
||||
mCurrentUserId);
|
||||
userId);
|
||||
} else if (!useableIgnoringAllowed) {
|
||||
Settings.Secure.putStringForUser(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
|
||||
"-" + mName,
|
||||
mCurrentUserId);
|
||||
userId);
|
||||
}
|
||||
|
||||
// needs to be sent to all users because whether or not a provider is enabled for
|
||||
// a given user is complicated... we broadcast to everyone and let them figure it
|
||||
// out via isProviderEnabled()
|
||||
Intent intent = new Intent(LocationManager.PROVIDERS_CHANGED_ACTION);
|
||||
intent.putExtra(LocationManager.EXTRA_PROVIDER_NAME, mName);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
|
||||
intent.putExtra(LocationManager.EXTRA_PROVIDER_ENABLED, useable);
|
||||
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
|
||||
}
|
||||
|
||||
if (useable == mUseable) {
|
||||
if (useable == isUseableLocked(userId)) {
|
||||
return;
|
||||
}
|
||||
mUseable = useable;
|
||||
mUseable.put(userId, useable);
|
||||
|
||||
if (D) {
|
||||
Log.d(TAG, mName + " provider useable is now " + mUseable);
|
||||
Log.d(TAG, "[u" + userId + "] " + mName + " provider useable = " + useable);
|
||||
}
|
||||
|
||||
if (!mUseable) {
|
||||
if (!useable) {
|
||||
// If any provider has been disabled, clear all last locations for all
|
||||
// providers. This is to be on the safe side in case a provider has location
|
||||
// derived from this disabled provider.
|
||||
@@ -1115,15 +1108,6 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
updateProviderUseableLocked(this);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
public void onUserChangingLocked() {
|
||||
// when the user is about to change, we set this provider to un-useable, and notify all
|
||||
// of the current user clients. when the user is finished changing, useability will be
|
||||
// updated back via onLocationModeChanged() and onAllowedChanged().
|
||||
mUseable = false;
|
||||
updateProviderUseableLocked(this);
|
||||
}
|
||||
}
|
||||
|
||||
private class MockLocationProvider extends LocationProvider {
|
||||
@@ -1557,14 +1541,20 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
mProviders.add(provider);
|
||||
|
||||
provider.onAllowedChangedLocked(); // allowed state may change while provider was inactive
|
||||
provider.onUseableChangedLocked(false);
|
||||
// allowed state may change while provider was inactive
|
||||
provider.onAllowedChangedLocked(mCurrentUserId);
|
||||
|
||||
// it would be more correct to call this for all users, but we know this can only
|
||||
// affect the current user since providers are disabled for non-current users
|
||||
provider.onUseableChangedLocked(false, mCurrentUserId);
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void removeProviderLocked(LocationProvider provider) {
|
||||
if (mProviders.remove(provider)) {
|
||||
provider.onUseableChangedLocked(false);
|
||||
// it would be more correct to call this for all users, but we know this can only
|
||||
// affect the current user since providers are disabled for non-current users
|
||||
provider.onUseableChangedLocked(false, mCurrentUserId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2851,7 +2841,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
synchronized (mLock) {
|
||||
LocationProvider provider = getLocationProviderLocked(providerName);
|
||||
return provider != null && provider.isUseableForUserLocked(userId);
|
||||
return provider != null && provider.isUseableLocked(userId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user