diff --git a/api/current.txt b/api/current.txt index cb077aff62557..b890c7a0cc319 100644 --- a/api/current.txt +++ b/api/current.txt @@ -35127,6 +35127,7 @@ package android.os { field public static final int LOCATION_MODE_FOREGROUND_ONLY = 3; // 0x3 field public static final int LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF = 1; // 0x1 field public static final int LOCATION_MODE_NO_CHANGE = 0; // 0x0 + field public static final int LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 4; // 0x4 field public static final int ON_AFTER_RELEASE = 536870912; // 0x20000000 field public static final int PARTIAL_WAKE_LOCK = 1; // 0x1 field public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = 32; // 0x20 diff --git a/api/test-current.txt b/api/test-current.txt index 1089761a3ab1b..107f2d6d8ce2e 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -887,6 +887,7 @@ package android.location { public class LocationManager { method public String[] getBackgroundThrottlingWhitelist(); method public String[] getIgnoreSettingsWhitelist(); + method @NonNull public java.util.List getTestProviderCurrentRequests(String); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(android.location.LocationRequest, android.app.PendingIntent); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, android.os.UserHandle); @@ -900,11 +901,14 @@ package android.location { method public long getInterval(); method public int getNumUpdates(); method public int getQuality(); + method public boolean isLocationSettingsIgnored(); method public android.location.LocationRequest setExpireAt(long); method public android.location.LocationRequest setExpireIn(long); method public android.location.LocationRequest setFastestInterval(long); method public android.location.LocationRequest setInterval(long); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean); method public android.location.LocationRequest setNumUpdates(int); + method public android.location.LocationRequest setProvider(String); method public android.location.LocationRequest setQuality(int); method public void writeToParcel(android.os.Parcel, int); field public static final int ACCURACY_BLOCK = 102; // 0x66 @@ -1977,6 +1981,7 @@ package android.provider { field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled"; field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions"; field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch"; + field public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist"; field public static final String LOW_POWER_MODE = "low_power"; field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky"; field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices"; diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 91ddf82b54004..488d4013e1ba2 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -762,8 +762,14 @@ public final class PowerManager { */ public static final int LOCATION_MODE_FOREGROUND_ONLY = 3; + /** + * In this mode, location will not be turned off, but LocationManager will throttle all + * requests to providers when the device is non-interactive. + */ + public static final int LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF = 4; + static final int MIN_LOCATION_MODE = LOCATION_MODE_NO_CHANGE; - static final int MAX_LOCATION_MODE = LOCATION_MODE_FOREGROUND_ONLY; + static final int MAX_LOCATION_MODE = LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF; /** * @hide @@ -774,9 +780,28 @@ public final class PowerManager { LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF, LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF, LOCATION_MODE_FOREGROUND_ONLY, + LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF, }) public @interface LocationPowerSaveMode {} + /** @hide */ + public static String locationPowerSaveModeToString(@LocationPowerSaveMode int mode) { + switch (mode) { + case LOCATION_MODE_NO_CHANGE: + return "NO_CHANGE"; + case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF: + return "GPS_DISABLED_WHEN_SCREEN_OFF"; + case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF: + return "ALL_DISABLED_WHEN_SCREEN_OFF"; + case LOCATION_MODE_FOREGROUND_ONLY: + return "FOREGROUND_ONLY"; + case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF: + return "THROTTLE_REQUESTS_WHEN_SCREEN_OFF"; + default: + return Integer.toString(mode); + } + } + final Context mContext; final IPowerManager mService; final Handler mHandler; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 0d7e00f708a38..faed323c9b28c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9635,6 +9635,7 @@ public final class Settings { * when user location settings are off), for emergency purposes. * @hide */ + @TestApi public static final String LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST = "location_ignore_settings_package_whitelist"; diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 57a0a725fb410..142f84dc494c2 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -102,6 +102,7 @@ interface ILocationManager void removeTestProvider(String provider, String opPackageName); void setTestProviderLocation(String provider, in Location loc, String opPackageName); void setTestProviderEnabled(String provider, boolean enabled, String opPackageName); + List getTestProviderCurrentRequests(String provider, String opPackageName); // --- deprecated --- void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime, diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 586ee2a436830..6828c597fe9a9 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -1626,6 +1626,23 @@ public class LocationManager { setTestProviderStatus(provider, LocationProvider.AVAILABLE, null, 0L); } + /** + * Get the last list of {@link LocationRequest}s sent to the provider. + * + * @hide + */ + @TestApi + @NonNull + public List getTestProviderCurrentRequests(String providerName) { + checkProvider(providerName); + try { + return mService.getTestProviderCurrentRequests(providerName, + mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + // --- GPS-specific support --- // This class is used to send Gnss status events to the client's specific thread. diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index b3953fddb6226..37770c662c6e9 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -270,7 +270,7 @@ public final class LocationRequest implements Parcelable { * Set the quality of the request. * *

Use with a accuracy constant such as {@link #ACCURACY_FINE}, or a power - * constant such as {@link #POWER_LOW}. You cannot request both and accuracy and + * constant such as {@link #POWER_LOW}. You cannot request both accuracy and * power, only one or the other can be specified. The system will then * maximize accuracy or minimize power as appropriate. * @@ -384,10 +384,8 @@ public final class LocationRequest implements Parcelable { * * @param locationSettingsIgnored Whether to ignore location settings * @return the same object, so that setters can be chained - * @hide */ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) - @SystemApi public LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) { mLocationSettingsIgnored = locationSettingsIgnored; return this; @@ -395,10 +393,7 @@ public final class LocationRequest implements Parcelable { /** * Returns true if location settings will be ignored in order to satisfy this request. - * - * @hide */ - @SystemApi public boolean isLocationSettingsIgnored() { return mLocationSettingsIgnored; } @@ -558,9 +553,6 @@ public final class LocationRequest implements Parcelable { } } - - /** @hide */ - @SystemApi public LocationRequest setProvider(String provider) { checkProvider(provider); mProvider = provider; diff --git a/location/java/com/android/internal/location/ProviderRequest.java b/location/java/com/android/internal/location/ProviderRequest.java index af8123ac52f48..155f788cb33e7 100644 --- a/location/java/com/android/internal/location/ProviderRequest.java +++ b/location/java/com/android/internal/location/ProviderRequest.java @@ -56,7 +56,7 @@ public final class ProviderRequest implements Parcelable { * low power fast interval request. */ @UnsupportedAppUsage - public List locationRequests = new ArrayList(); + public final List locationRequests = new ArrayList<>(); @UnsupportedAppUsage public ProviderRequest() { diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 4b8ba1056c85a..34f415f4bbace 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -22,6 +22,7 @@ import static android.location.LocationManager.GPS_PROVIDER; import static android.location.LocationManager.NETWORK_PROVIDER; import static android.location.LocationManager.PASSIVE_PROVIDER; import static android.location.LocationProvider.AVAILABLE; +import static android.os.PowerManager.locationPowerSaveModeToString; import static android.provider.Settings.Global.LOCATION_DISABLE_STATUS_CALLBACKS; import static com.android.internal.util.Preconditions.checkNotNull; @@ -69,6 +70,8 @@ import android.os.Handler; import android.os.IBinder; import android.os.IInterface; import android.os.PowerManager; +import android.os.PowerManager.ServiceType; +import android.os.PowerManagerInternal; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; @@ -254,6 +257,10 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") private boolean mGnssBatchingInProgress = false; + @GuardedBy("mLock") + @PowerManager.LocationPowerSaveMode + private int mBatterySaverMode; + public LocationManagerService(Context context) { super(); mContext = context; @@ -376,6 +383,14 @@ public class LocationManagerService extends ILocationManager.Stub { } } }, UserHandle.USER_ALL); + PowerManagerInternal localPowerManager = + LocalServices.getService(PowerManagerInternal.class); + localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION, + state -> { + synchronized (mLock) { + onBatterySaverModeChangedLocked(state.locationMode); + } + }); new PackageMonitor() { @Override @@ -390,17 +405,29 @@ public class LocationManagerService extends ILocationManager.Stub { intentFilter.addAction(Intent.ACTION_USER_SWITCHED); intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED); intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); + intentFilter.addAction(Intent.ACTION_SCREEN_OFF); + intentFilter.addAction(Intent.ACTION_SCREEN_ON); mContext.registerReceiverAsUser(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (action == null) { + return; + } synchronized (mLock) { - String action = intent.getAction(); - if (Intent.ACTION_USER_SWITCHED.equals(action)) { - onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); - } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action) - || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { - onUserProfilesChangedLocked(); + switch (action) { + case Intent.ACTION_USER_SWITCHED: + onUserChangedLocked(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0)); + break; + case Intent.ACTION_MANAGED_PROFILE_ADDED: + case Intent.ACTION_MANAGED_PROFILE_REMOVED: + onUserProfilesChangedLocked(); + break; + case Intent.ACTION_SCREEN_ON: + case Intent.ACTION_SCREEN_OFF: + onScreenStateChangedLocked(); + break; } } } @@ -415,6 +442,7 @@ public class LocationManagerService extends ILocationManager.Stub { // initialize in-memory settings values onBackgroundThrottleWhitelistChangedLocked(); onIgnoreSettingsWhitelistChangedLocked(); + onBatterySaverModeChangedLocked(mPowerManager.getLocationPowerSaveMode()); } @GuardedBy("mLock") @@ -434,6 +462,34 @@ public class LocationManagerService extends ILocationManager.Stub { } } + @GuardedBy("mLock") + private void onBatterySaverModeChangedLocked(int newLocationMode) { + if (D) { + Slog.d(TAG, + "Battery Saver location mode changed from " + + locationPowerSaveModeToString(mBatterySaverMode) + " to " + + locationPowerSaveModeToString(newLocationMode)); + } + + if (mBatterySaverMode == newLocationMode) { + return; + } + + mBatterySaverMode = newLocationMode; + for (LocationProvider p : mProviders) { + applyRequirementsLocked(p); + } + } + + @GuardedBy("mLock") + private void onScreenStateChangedLocked() { + if (mBatterySaverMode == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) { + for (LocationProvider p : mProviders) { + applyRequirementsLocked(p); + } + } + } + @GuardedBy("mLock") private void onLocationModeChangedLocked(boolean broadcast) { for (LocationProvider p : mProviders) { @@ -1174,6 +1230,8 @@ public class LocationManagerService extends ILocationManager.Stub { private class MockLocationProvider extends LocationProvider { + private ProviderRequest mCurrentRequest; + private MockLocationProvider(String name) { super(name); } @@ -1212,6 +1270,13 @@ public class LocationManagerService extends ILocationManager.Stub { } } + @Override + @GuardedBy("mLock") + public void setRequestLocked(ProviderRequest request, WorkSource workSource) { + super.setRequestLocked(request, workSource); + mCurrentRequest = request; + } + @GuardedBy("mLock") public void setStatusLocked(int status, Bundle extras, long updateTime) { if (mProvider != null) { @@ -2024,8 +2089,11 @@ public class LocationManagerService extends ILocationManager.Stub { } final boolean isForegroundOnlyMode = - mPowerManager.getLocationPowerSaveMode() - == PowerManager.LOCATION_MODE_FOREGROUND_ONLY; + mBatterySaverMode == PowerManager.LOCATION_MODE_FOREGROUND_ONLY; + final boolean shouldThrottleRequests = + mBatterySaverMode + == PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF + && !mPowerManager.isInteractive(); // initialize the low power mode to true and set to false if any of the records requires providerRequest.lowPowerMode = true; for (UpdateRecord record : records) { @@ -2040,8 +2108,8 @@ public class LocationManagerService extends ILocationManager.Stub { record.mReceiver.mAllowedResolutionLevel)) { continue; } - final boolean isBatterySaverDisablingLocation = - isForegroundOnlyMode && !record.mIsForegroundUid; + final boolean isBatterySaverDisablingLocation = shouldThrottleRequests + || (isForegroundOnlyMode && !record.mIsForegroundUid); if (!provider.isUseableLocked() || isBatterySaverDisablingLocation) { if (isSettingsExemptLocked(record)) { providerRequest.locationSettingsIgnored = true; @@ -3396,6 +3464,32 @@ public class LocationManagerService extends ILocationManager.Stub { } } + @Override + @NonNull + public List getTestProviderCurrentRequests(String providerName, + String opPackageName) { + if (!canCallerAccessMockLocation(opPackageName)) { + return Collections.emptyList(); + } + + synchronized (mLock) { + LocationProvider testProvider = getLocationProviderLocked(providerName); + if (testProvider == null || !testProvider.isMock()) { + throw new IllegalArgumentException("Provider \"" + providerName + "\" unknown"); + } + + MockLocationProvider provider = (MockLocationProvider) testProvider; + if (provider.mCurrentRequest == null) { + return Collections.emptyList(); + } + List requests = new ArrayList<>(); + for (LocationRequest request : provider.mCurrentRequest.locationRequests) { + requests.add(new LocationRequest(request)); + } + return requests; + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; @@ -3411,6 +3505,8 @@ public class LocationManagerService extends ILocationManager.Stub { pw.println(" Current user: " + mCurrentUserId + " " + Arrays.toString( mCurrentUserProfiles)); pw.println(" Location mode: " + isLocationEnabled()); + pw.println(" Battery Saver Location Mode: " + + locationPowerSaveModeToString(mBatterySaverMode)); pw.println(" Location Listeners:"); for (Receiver receiver : mReceivers.values()) { pw.println(" " + receiver); diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java index 94bb3ea09d938..5adcf352e260d 100644 --- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java +++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java @@ -384,7 +384,7 @@ public class BatterySaverController implements BatterySaverPolicyListener { * - When battery saver is on and the battery saver policy changes. * - When adaptive battery saver becomes activated. * - When adaptive battery saver becomes deactivated. - * - When adaptive battery saver policy changes. + * - When adaptive battery saver is active (and full is off) and the policy changes. */ void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) { final LowPowerModeListener[] listeners;