Loading services/core/java/com/android/server/location/provider/LocationProviderManager.java +74 −17 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY; import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF; import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF; import static android.os.UserHandle.USER_CURRENT; import static com.android.server.location.LocationManagerService.D; import static com.android.server.location.LocationManagerService.TAG; Loading Loading @@ -177,7 +178,7 @@ public class LocationProviderManager extends protected interface LocationTransport { void deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback) throws Exception; @Nullable IRemoteCallback onCompleteCallback) throws Exception; void deliverOnFlushComplete(int requestCode) throws Exception; } Loading @@ -197,9 +198,8 @@ public class LocationProviderManager extends @Override public void deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback) throws RemoteException { mListener.onLocationChanged(locationResult.asList(), SingleUseCallback.wrap(onCompleteCallback)); @Nullable IRemoteCallback onCompleteCallback) throws RemoteException { mListener.onLocationChanged(locationResult.asList(), onCompleteCallback); } @Override Loading Loading @@ -227,7 +227,7 @@ public class LocationProviderManager extends @Override public void deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback) @Nullable IRemoteCallback onCompleteCallback) throws PendingIntent.CanceledException { BroadcastOptions options = BroadcastOptions.makeBasic(); options.setDontSendToRestrictedApps(true); Loading @@ -243,20 +243,34 @@ public class LocationProviderManager extends intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0])); } PendingIntent.OnFinished onFinished = null; // send() SHOULD only run the completion callback if it completes successfully. however, // b/199464864 (which could not be fixed in the S timeframe) means that it's possible // b/201299281 (which could not be fixed in the S timeframe) means that it's possible // for send() to throw an exception AND run the completion callback. if this happens, we // would over-release the wakelock... we take matters into our own hands to ensure that // the completion callback can only be run if send() completes successfully. this means // the completion callback may be run inline - but as we've never specified what thread // the callback is run on, this is fine. GatedCallback gatedCallback = new GatedCallback(onCompleteCallback); GatedCallback gatedCallback; if (onCompleteCallback != null) { gatedCallback = new GatedCallback(() -> { try { onCompleteCallback.sendResult(null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }); onFinished = (pI, i, rC, rD, rE) -> gatedCallback.run(); } else { gatedCallback = new GatedCallback(null); } mPendingIntent.send( mContext, 0, intent, (pI, i, rC, rD, rE) -> gatedCallback.run(), onFinished, null, null, options.toBundle()); Loading Loading @@ -293,7 +307,7 @@ public class LocationProviderManager extends @Override public void deliverOnLocationChanged(@Nullable LocationResult locationResult, @Nullable Runnable onCompleteCallback) @Nullable IRemoteCallback onCompleteCallback) throws RemoteException { // ILocationCallback doesn't currently support completion callbacks Preconditions.checkState(onCompleteCallback == null); Loading Loading @@ -714,6 +728,13 @@ public class LocationProviderManager extends final PowerManager.WakeLock mWakeLock; // b/206340085 - if we allocate a new wakelock releaser object for every delivery we // increase the risk of resource starvation. if a client stops processing deliveries the // system server binder allocation pool will be starved as we continue to queue up // deliveries, each with a new allocation. in order to mitigate this, we use a single // releaser object per registration rather than per delivery. final ExternalWakeLockReleaser mWakeLockReleaser; private volatile ProviderTransport mProviderTransport; private int mNumLocationsDelivered = 0; private long mExpirationRealtimeMs = Long.MAX_VALUE; Loading @@ -727,6 +748,7 @@ public class LocationProviderManager extends .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); mWakeLock.setReferenceCounted(true); mWakeLock.setWorkSource(request.getWorkSource()); mWakeLockReleaser = new ExternalWakeLockReleaser(identity, mWakeLock); } @Override Loading Loading @@ -872,6 +894,10 @@ public class LocationProviderManager extends MAX_FASTEST_INTERVAL_JITTER_MS); if (deltaMs < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) { if (D) { Log.v(TAG, mName + " provider registration " + getIdentity() + " dropped delivery - too fast"); } return false; } Loading @@ -881,6 +907,10 @@ public class LocationProviderManager extends if (smallestDisplacementM > 0.0 && location.distanceTo( mPreviousLocation) <= smallestDisplacementM) { if (D) { Log.v(TAG, mName + " provider registration " + getIdentity() + " dropped delivery - too close"); } return false; } } Loading @@ -898,7 +928,8 @@ public class LocationProviderManager extends if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) { if (D) { Log.w(TAG, "noteOp denied for " + getIdentity()); Log.w(TAG, mName + " provider registration " + getIdentity() + " noteOp denied"); } return null; } Loading Loading @@ -943,7 +974,7 @@ public class LocationProviderManager extends } listener.deliverOnLocationChanged(deliverLocationResult, mUseWakeLock ? mWakeLock::release : null); mUseWakeLock ? mWakeLockReleaser : null); EVENT_LOG.logProviderDeliveredLocations(mName, locationResult.size(), getIdentity()); } Loading Loading @@ -1482,7 +1513,7 @@ public class LocationProviderManager extends public boolean isEnabled(int userId) { if (userId == UserHandle.USER_NULL) { return false; } else if (userId == UserHandle.USER_CURRENT) { } else if (userId == USER_CURRENT) { return isEnabled(mUserHelper.getCurrentUserId()); } Loading Loading @@ -1655,7 +1686,7 @@ public class LocationProviderManager extends } } return lastLocation; } else if (userId == UserHandle.USER_CURRENT) { } else if (userId == USER_CURRENT) { return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel, isBypass, maximumAgeMs); } Loading Loading @@ -1700,7 +1731,7 @@ public class LocationProviderManager extends setLastLocation(location, runningUserIds[i]); } return; } else if (userId == UserHandle.USER_CURRENT) { } else if (userId == USER_CURRENT) { setLastLocation(location, mUserHelper.getCurrentUserId()); return; } Loading Loading @@ -2383,13 +2414,13 @@ public class LocationProviderManager extends filtered = locationResult.filter(location -> { if (!location.isMock()) { if (location.getLatitude() == 0 && location.getLongitude() == 0) { Log.w(TAG, "blocking 0,0 location from " + mName + " provider"); Log.e(TAG, "blocking 0,0 location from " + mName + " provider"); return false; } } if (!location.isComplete()) { Log.w(TAG, "blocking incomplete location from " + mName + " provider"); Log.e(TAG, "blocking incomplete location from " + mName + " provider"); return false; } Loading @@ -2407,6 +2438,12 @@ public class LocationProviderManager extends filtered = locationResult; } Location last = getLastLocationUnsafe(USER_CURRENT, PERMISSION_FINE, true, Long.MAX_VALUE); if (last != null && locationResult.get(0).getElapsedRealtimeNanos() < last.getElapsedRealtimeNanos()) { Log.e(TAG, "non-monotonic location received from " + mName + " provider"); } // update last location setLastLocation(filtered.getLastLocation(), UserHandle.USER_ALL); Loading Loading @@ -2761,7 +2798,7 @@ public class LocationProviderManager extends @GuardedBy("this") private boolean mRun; GatedCallback(Runnable callback) { GatedCallback(@Nullable Runnable callback) { mCallback = callback; } Loading Loading @@ -2796,4 +2833,24 @@ public class LocationProviderManager extends } } } private static class ExternalWakeLockReleaser extends IRemoteCallback.Stub { private final CallerIdentity mIdentity; private final PowerManager.WakeLock mWakeLock; ExternalWakeLockReleaser(CallerIdentity identity, PowerManager.WakeLock wakeLock) { mIdentity = identity; mWakeLock = Objects.requireNonNull(wakeLock); } @Override public void sendResult(Bundle data) { try { mWakeLock.release(); } catch (RuntimeException e) { Log.e(TAG, "wakelock over-released by " + mIdentity, e); } } } } services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java +4 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static com.android.server.location.LocationManagerService.D; import static com.android.server.location.LocationManagerService.TAG; import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG; import static java.lang.Math.max; import android.annotation.Nullable; import android.location.Location; import android.location.LocationResult; Loading Loading @@ -53,6 +55,7 @@ public final class StationaryThrottlingLocationProvider extends DelegateLocation implements DeviceIdleHelper.DeviceIdleListener, DeviceIdleInternal.StationaryListener { private static final long MAX_STATIONARY_LOCATION_AGE_MS = 30000; private static final long MIN_INTERVAL_MS = 1000; final Object mLock = new Object(); Loading Loading @@ -179,7 +182,7 @@ public final class StationaryThrottlingLocationProvider extends DelegateLocation && mLastLocation != null && mLastLocation.getElapsedRealtimeAgeMillis(mDeviceStationaryRealtimeMs) <= MAX_STATIONARY_LOCATION_AGE_MS) { throttlingIntervalMs = mIncomingRequest.getIntervalMillis(); throttlingIntervalMs = max(mIncomingRequest.getIntervalMillis(), MIN_INTERVAL_MS); } ProviderRequest newRequest; Loading services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java +21 −10 Original line number Diff line number Diff line Loading @@ -89,6 +89,19 @@ public class StationaryThrottlingLocationProviderTest { mProvider.getController().stop(); } @Test public void testThrottle_lowInterval() { ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(0).build(); mProvider.getController().setRequest(request); mDelegateProvider.reportLocation(createLocationResult("test_provider", mRandom)); verify(mListener, times(1)).onReportLocation(any(LocationResult.class)); mInjector.getDeviceStationaryHelper().setStationary(true); mInjector.getDeviceIdleHelper().setIdle(true); verify(mListener, after(1500).times(2)).onReportLocation(any(LocationResult.class)); } @Test public void testThrottle_stationaryExit() { ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(50).build(); Loading @@ -104,17 +117,16 @@ public class StationaryThrottlingLocationProviderTest { mInjector.getDeviceIdleHelper().setIdle(true); verify(mDelegate).onSetRequest(ProviderRequest.EMPTY_REQUEST); verify(mListener, timeout(75).times(2)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(75).times(3)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(1100).times(2)).onReportLocation(any(LocationResult.class)); mInjector.getDeviceStationaryHelper().setStationary(false); verify(mDelegate, times(2)).onSetRequest(request); verify(mListener, after(75).times(3)).onReportLocation(any(LocationResult.class)); verify(mListener, after(1000).times(2)).onReportLocation(any(LocationResult.class)); } @Test public void testThrottle_idleExit() { ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(50).build(); ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(1000).build(); mProvider.getController().setRequest(request); verify(mDelegate).onSetRequest(request); Loading @@ -127,17 +139,16 @@ public class StationaryThrottlingLocationProviderTest { mInjector.getDeviceStationaryHelper().setStationary(true); verify(mDelegate).onSetRequest(ProviderRequest.EMPTY_REQUEST); verify(mListener, timeout(75).times(2)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(75).times(3)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(1100).times(2)).onReportLocation(any(LocationResult.class)); mInjector.getDeviceIdleHelper().setIdle(false); verify(mDelegate, times(2)).onSetRequest(request); verify(mListener, after(75).times(3)).onReportLocation(any(LocationResult.class)); verify(mListener, after(1000).times(2)).onReportLocation(any(LocationResult.class)); } @Test public void testThrottle_NoInitialLocation() { ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(50).build(); ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(1000).build(); mProvider.getController().setRequest(request); verify(mDelegate).onSetRequest(request); Loading @@ -149,11 +160,11 @@ public class StationaryThrottlingLocationProviderTest { mDelegateProvider.reportLocation(createLocationResult("test_provider", mRandom)); verify(mListener, times(1)).onReportLocation(any(LocationResult.class)); verify(mDelegate, times(1)).onSetRequest(ProviderRequest.EMPTY_REQUEST); verify(mListener, timeout(75).times(2)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(1100).times(2)).onReportLocation(any(LocationResult.class)); mInjector.getDeviceStationaryHelper().setStationary(false); verify(mDelegate, times(2)).onSetRequest(request); verify(mListener, after(75).times(2)).onReportLocation(any(LocationResult.class)); verify(mListener, after(1000).times(2)).onReportLocation(any(LocationResult.class)); } @Test Loading Loading
services/core/java/com/android/server/location/provider/LocationProviderManager.java +74 −17 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF import static android.os.PowerManager.LOCATION_MODE_FOREGROUND_ONLY; import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF; import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF; import static android.os.UserHandle.USER_CURRENT; import static com.android.server.location.LocationManagerService.D; import static com.android.server.location.LocationManagerService.TAG; Loading Loading @@ -177,7 +178,7 @@ public class LocationProviderManager extends protected interface LocationTransport { void deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback) throws Exception; @Nullable IRemoteCallback onCompleteCallback) throws Exception; void deliverOnFlushComplete(int requestCode) throws Exception; } Loading @@ -197,9 +198,8 @@ public class LocationProviderManager extends @Override public void deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback) throws RemoteException { mListener.onLocationChanged(locationResult.asList(), SingleUseCallback.wrap(onCompleteCallback)); @Nullable IRemoteCallback onCompleteCallback) throws RemoteException { mListener.onLocationChanged(locationResult.asList(), onCompleteCallback); } @Override Loading Loading @@ -227,7 +227,7 @@ public class LocationProviderManager extends @Override public void deliverOnLocationChanged(LocationResult locationResult, @Nullable Runnable onCompleteCallback) @Nullable IRemoteCallback onCompleteCallback) throws PendingIntent.CanceledException { BroadcastOptions options = BroadcastOptions.makeBasic(); options.setDontSendToRestrictedApps(true); Loading @@ -243,20 +243,34 @@ public class LocationProviderManager extends intent.putExtra(KEY_LOCATIONS, locationResult.asList().toArray(new Location[0])); } PendingIntent.OnFinished onFinished = null; // send() SHOULD only run the completion callback if it completes successfully. however, // b/199464864 (which could not be fixed in the S timeframe) means that it's possible // b/201299281 (which could not be fixed in the S timeframe) means that it's possible // for send() to throw an exception AND run the completion callback. if this happens, we // would over-release the wakelock... we take matters into our own hands to ensure that // the completion callback can only be run if send() completes successfully. this means // the completion callback may be run inline - but as we've never specified what thread // the callback is run on, this is fine. GatedCallback gatedCallback = new GatedCallback(onCompleteCallback); GatedCallback gatedCallback; if (onCompleteCallback != null) { gatedCallback = new GatedCallback(() -> { try { onCompleteCallback.sendResult(null); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }); onFinished = (pI, i, rC, rD, rE) -> gatedCallback.run(); } else { gatedCallback = new GatedCallback(null); } mPendingIntent.send( mContext, 0, intent, (pI, i, rC, rD, rE) -> gatedCallback.run(), onFinished, null, null, options.toBundle()); Loading Loading @@ -293,7 +307,7 @@ public class LocationProviderManager extends @Override public void deliverOnLocationChanged(@Nullable LocationResult locationResult, @Nullable Runnable onCompleteCallback) @Nullable IRemoteCallback onCompleteCallback) throws RemoteException { // ILocationCallback doesn't currently support completion callbacks Preconditions.checkState(onCompleteCallback == null); Loading Loading @@ -714,6 +728,13 @@ public class LocationProviderManager extends final PowerManager.WakeLock mWakeLock; // b/206340085 - if we allocate a new wakelock releaser object for every delivery we // increase the risk of resource starvation. if a client stops processing deliveries the // system server binder allocation pool will be starved as we continue to queue up // deliveries, each with a new allocation. in order to mitigate this, we use a single // releaser object per registration rather than per delivery. final ExternalWakeLockReleaser mWakeLockReleaser; private volatile ProviderTransport mProviderTransport; private int mNumLocationsDelivered = 0; private long mExpirationRealtimeMs = Long.MAX_VALUE; Loading @@ -727,6 +748,7 @@ public class LocationProviderManager extends .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); mWakeLock.setReferenceCounted(true); mWakeLock.setWorkSource(request.getWorkSource()); mWakeLockReleaser = new ExternalWakeLockReleaser(identity, mWakeLock); } @Override Loading Loading @@ -872,6 +894,10 @@ public class LocationProviderManager extends MAX_FASTEST_INTERVAL_JITTER_MS); if (deltaMs < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) { if (D) { Log.v(TAG, mName + " provider registration " + getIdentity() + " dropped delivery - too fast"); } return false; } Loading @@ -881,6 +907,10 @@ public class LocationProviderManager extends if (smallestDisplacementM > 0.0 && location.distanceTo( mPreviousLocation) <= smallestDisplacementM) { if (D) { Log.v(TAG, mName + " provider registration " + getIdentity() + " dropped delivery - too close"); } return false; } } Loading @@ -898,7 +928,8 @@ public class LocationProviderManager extends if (!mAppOpsHelper.noteOpNoThrow(LocationPermissions.asAppOp(getPermissionLevel()), getIdentity())) { if (D) { Log.w(TAG, "noteOp denied for " + getIdentity()); Log.w(TAG, mName + " provider registration " + getIdentity() + " noteOp denied"); } return null; } Loading Loading @@ -943,7 +974,7 @@ public class LocationProviderManager extends } listener.deliverOnLocationChanged(deliverLocationResult, mUseWakeLock ? mWakeLock::release : null); mUseWakeLock ? mWakeLockReleaser : null); EVENT_LOG.logProviderDeliveredLocations(mName, locationResult.size(), getIdentity()); } Loading Loading @@ -1482,7 +1513,7 @@ public class LocationProviderManager extends public boolean isEnabled(int userId) { if (userId == UserHandle.USER_NULL) { return false; } else if (userId == UserHandle.USER_CURRENT) { } else if (userId == USER_CURRENT) { return isEnabled(mUserHelper.getCurrentUserId()); } Loading Loading @@ -1655,7 +1686,7 @@ public class LocationProviderManager extends } } return lastLocation; } else if (userId == UserHandle.USER_CURRENT) { } else if (userId == USER_CURRENT) { return getLastLocationUnsafe(mUserHelper.getCurrentUserId(), permissionLevel, isBypass, maximumAgeMs); } Loading Loading @@ -1700,7 +1731,7 @@ public class LocationProviderManager extends setLastLocation(location, runningUserIds[i]); } return; } else if (userId == UserHandle.USER_CURRENT) { } else if (userId == USER_CURRENT) { setLastLocation(location, mUserHelper.getCurrentUserId()); return; } Loading Loading @@ -2383,13 +2414,13 @@ public class LocationProviderManager extends filtered = locationResult.filter(location -> { if (!location.isMock()) { if (location.getLatitude() == 0 && location.getLongitude() == 0) { Log.w(TAG, "blocking 0,0 location from " + mName + " provider"); Log.e(TAG, "blocking 0,0 location from " + mName + " provider"); return false; } } if (!location.isComplete()) { Log.w(TAG, "blocking incomplete location from " + mName + " provider"); Log.e(TAG, "blocking incomplete location from " + mName + " provider"); return false; } Loading @@ -2407,6 +2438,12 @@ public class LocationProviderManager extends filtered = locationResult; } Location last = getLastLocationUnsafe(USER_CURRENT, PERMISSION_FINE, true, Long.MAX_VALUE); if (last != null && locationResult.get(0).getElapsedRealtimeNanos() < last.getElapsedRealtimeNanos()) { Log.e(TAG, "non-monotonic location received from " + mName + " provider"); } // update last location setLastLocation(filtered.getLastLocation(), UserHandle.USER_ALL); Loading Loading @@ -2761,7 +2798,7 @@ public class LocationProviderManager extends @GuardedBy("this") private boolean mRun; GatedCallback(Runnable callback) { GatedCallback(@Nullable Runnable callback) { mCallback = callback; } Loading Loading @@ -2796,4 +2833,24 @@ public class LocationProviderManager extends } } } private static class ExternalWakeLockReleaser extends IRemoteCallback.Stub { private final CallerIdentity mIdentity; private final PowerManager.WakeLock mWakeLock; ExternalWakeLockReleaser(CallerIdentity identity, PowerManager.WakeLock wakeLock) { mIdentity = identity; mWakeLock = Objects.requireNonNull(wakeLock); } @Override public void sendResult(Bundle data) { try { mWakeLock.release(); } catch (RuntimeException e) { Log.e(TAG, "wakelock over-released by " + mIdentity, e); } } } }
services/core/java/com/android/server/location/provider/StationaryThrottlingLocationProvider.java +4 −1 Original line number Diff line number Diff line Loading @@ -23,6 +23,8 @@ import static com.android.server.location.LocationManagerService.D; import static com.android.server.location.LocationManagerService.TAG; import static com.android.server.location.eventlog.LocationEventLog.EVENT_LOG; import static java.lang.Math.max; import android.annotation.Nullable; import android.location.Location; import android.location.LocationResult; Loading Loading @@ -53,6 +55,7 @@ public final class StationaryThrottlingLocationProvider extends DelegateLocation implements DeviceIdleHelper.DeviceIdleListener, DeviceIdleInternal.StationaryListener { private static final long MAX_STATIONARY_LOCATION_AGE_MS = 30000; private static final long MIN_INTERVAL_MS = 1000; final Object mLock = new Object(); Loading Loading @@ -179,7 +182,7 @@ public final class StationaryThrottlingLocationProvider extends DelegateLocation && mLastLocation != null && mLastLocation.getElapsedRealtimeAgeMillis(mDeviceStationaryRealtimeMs) <= MAX_STATIONARY_LOCATION_AGE_MS) { throttlingIntervalMs = mIncomingRequest.getIntervalMillis(); throttlingIntervalMs = max(mIncomingRequest.getIntervalMillis(), MIN_INTERVAL_MS); } ProviderRequest newRequest; Loading
services/tests/mockingservicestests/src/com/android/server/location/provider/StationaryThrottlingLocationProviderTest.java +21 −10 Original line number Diff line number Diff line Loading @@ -89,6 +89,19 @@ public class StationaryThrottlingLocationProviderTest { mProvider.getController().stop(); } @Test public void testThrottle_lowInterval() { ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(0).build(); mProvider.getController().setRequest(request); mDelegateProvider.reportLocation(createLocationResult("test_provider", mRandom)); verify(mListener, times(1)).onReportLocation(any(LocationResult.class)); mInjector.getDeviceStationaryHelper().setStationary(true); mInjector.getDeviceIdleHelper().setIdle(true); verify(mListener, after(1500).times(2)).onReportLocation(any(LocationResult.class)); } @Test public void testThrottle_stationaryExit() { ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(50).build(); Loading @@ -104,17 +117,16 @@ public class StationaryThrottlingLocationProviderTest { mInjector.getDeviceIdleHelper().setIdle(true); verify(mDelegate).onSetRequest(ProviderRequest.EMPTY_REQUEST); verify(mListener, timeout(75).times(2)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(75).times(3)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(1100).times(2)).onReportLocation(any(LocationResult.class)); mInjector.getDeviceStationaryHelper().setStationary(false); verify(mDelegate, times(2)).onSetRequest(request); verify(mListener, after(75).times(3)).onReportLocation(any(LocationResult.class)); verify(mListener, after(1000).times(2)).onReportLocation(any(LocationResult.class)); } @Test public void testThrottle_idleExit() { ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(50).build(); ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(1000).build(); mProvider.getController().setRequest(request); verify(mDelegate).onSetRequest(request); Loading @@ -127,17 +139,16 @@ public class StationaryThrottlingLocationProviderTest { mInjector.getDeviceStationaryHelper().setStationary(true); verify(mDelegate).onSetRequest(ProviderRequest.EMPTY_REQUEST); verify(mListener, timeout(75).times(2)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(75).times(3)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(1100).times(2)).onReportLocation(any(LocationResult.class)); mInjector.getDeviceIdleHelper().setIdle(false); verify(mDelegate, times(2)).onSetRequest(request); verify(mListener, after(75).times(3)).onReportLocation(any(LocationResult.class)); verify(mListener, after(1000).times(2)).onReportLocation(any(LocationResult.class)); } @Test public void testThrottle_NoInitialLocation() { ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(50).build(); ProviderRequest request = new ProviderRequest.Builder().setIntervalMillis(1000).build(); mProvider.getController().setRequest(request); verify(mDelegate).onSetRequest(request); Loading @@ -149,11 +160,11 @@ public class StationaryThrottlingLocationProviderTest { mDelegateProvider.reportLocation(createLocationResult("test_provider", mRandom)); verify(mListener, times(1)).onReportLocation(any(LocationResult.class)); verify(mDelegate, times(1)).onSetRequest(ProviderRequest.EMPTY_REQUEST); verify(mListener, timeout(75).times(2)).onReportLocation(any(LocationResult.class)); verify(mListener, timeout(1100).times(2)).onReportLocation(any(LocationResult.class)); mInjector.getDeviceStationaryHelper().setStationary(false); verify(mDelegate, times(2)).onSetRequest(request); verify(mListener, after(75).times(2)).onReportLocation(any(LocationResult.class)); verify(mListener, after(1000).times(2)).onReportLocation(any(LocationResult.class)); } @Test Loading