blob: e7a32727e9f1dec42c0aff6b6caf1dd0406b4586 [file] [log] [blame]
/*
* Copyright (C) 2018 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 android.os.cts.batterysaving;
import static android.provider.Settings.Global.BATTERY_SAVER_CONSTANTS;
import static android.provider.Settings.Secure.LOCATION_MODE_OFF;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.compatibility.common.util.BatteryUtils.enableBatterySaver;
import static com.android.compatibility.common.util.BatteryUtils.runDumpsysBatteryUnplug;
import static com.android.compatibility.common.util.BatteryUtils.turnOnScreen;
import static com.android.compatibility.common.util.TestUtils.waitUntil;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.app.UiModeManager;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.location.LocationRequest;
import android.os.Bundle;
import android.os.Looper;
import android.os.PowerManager;
import android.os.Process;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.compatibility.common.util.CallbackAsserter;
import com.android.compatibility.common.util.LocationUtils;
import com.android.compatibility.common.util.RequiredFeatureRule;
import com.android.compatibility.common.util.SettingsUtils;
import com.android.compatibility.common.util.TestUtils.RunnableWithThrow;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.List;
/**
* Tests related to battery saver:
* atest android.os.cts.batterysaving.BatterySaverLocationTest
*/
@MediumTest
@RunWith(AndroidJUnit4.class)
public class BatterySaverLocationTest extends BatterySavingTestBase {
private static final String TAG = "BatterySaverLocationTest";
private static final String TEST_PROVIDER_NAME = "test_provider";
@Rule
public final RequiredFeatureRule mRequireLocationRule =
new RequiredFeatureRule(PackageManager.FEATURE_LOCATION);
@Rule
public final RequiredFeatureRule mRequireLocationGpsRule =
new RequiredFeatureRule(PackageManager.FEATURE_LOCATION_GPS);
private LocationManager mLocationManager;
private static class TestLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
fail("Provider disabled");
}
}
@Before
public void setUp() throws Exception {
LocationUtils.registerMockLocationProvider(getInstrumentation(), true);
mLocationManager = getLocationManager();
// remove test provider if left over from an aborted run
LocationProvider lp = mLocationManager.getProvider(TEST_PROVIDER_NAME);
if (lp != null) {
mLocationManager.removeTestProvider(TEST_PROVIDER_NAME);
}
SettingsUtils.set(SettingsUtils.NAMESPACE_GLOBAL,
Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
"android.os.cts.batterysaving");
getContext().getSystemService(UiModeManager.class).disableCarMode(0);
}
@After
public void tearDown() throws Exception {
LocationUtils.registerMockLocationProvider(getInstrumentation(), false);
SettingsUtils.set(SettingsUtils.NAMESPACE_GLOBAL,
Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
"");
}
private boolean areOnlyIgnoreSettingsRequestsSentToProvider() {
List<LocationRequest> requests =
mLocationManager.getTestProviderCurrentRequests(TEST_PROVIDER_NAME);
for (LocationRequest request : requests) {
if (!request.isLocationSettingsIgnored()) {
return false;
}
}
return true;
}
/**
* Test for the {@link PowerManager#LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF} mode.
*/
@Test
public void testLocationAllDisabled() throws Exception {
assertTrue("Screen is off", getPowerManager().isInteractive());
assertFalse(getPowerManager().isPowerSaveMode());
assertEquals(PowerManager.LOCATION_MODE_NO_CHANGE,
getPowerManager().getLocationPowerSaveMode());
assertEquals(0, getLocationGlobalKillSwitch());
SettingsUtils.set(SettingsUtils.NAMESPACE_GLOBAL, BATTERY_SAVER_CONSTANTS, "gps_mode=2");
assertNotEquals(LOCATION_MODE_OFF, getLocationMode());
assertTrue(getLocationManager().isLocationEnabled());
// Unplug the charger and activate battery saver.
runDumpsysBatteryUnplug();
enableBatterySaver(true);
// Skip if the location mode is not what's expected.
final int mode = getPowerManager().getLocationPowerSaveMode();
if (mode != PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) {
fail("Unexpected location power save mode (" + mode + ").");
}
// Make sure screen is on.
assertTrue(getPowerManager().isInteractive());
// Make sure the kill switch is still off.
assertEquals(0, getLocationGlobalKillSwitch());
// Make sure location is still enabled.
assertNotEquals(LOCATION_MODE_OFF, getLocationMode());
assertTrue(getLocationManager().isLocationEnabled());
// Turn screen off.
runWithExpectingLocationCallback(() -> {
turnOnScreen(false);
waitUntil("Kill switch still off", () -> getLocationGlobalKillSwitch() == 1);
assertEquals(LOCATION_MODE_OFF, getLocationMode());
assertFalse(getLocationManager().isLocationEnabled());
});
// On again.
runWithExpectingLocationCallback(() -> {
turnOnScreen(true);
waitUntil("Kill switch still off", () -> getLocationGlobalKillSwitch() == 0);
assertNotEquals(LOCATION_MODE_OFF, getLocationMode());
assertTrue(getLocationManager().isLocationEnabled());
});
// Off again.
runWithExpectingLocationCallback(() -> {
turnOnScreen(false);
waitUntil("Kill switch still off", () -> getLocationGlobalKillSwitch() == 1);
assertEquals(LOCATION_MODE_OFF, getLocationMode());
assertFalse(getLocationManager().isLocationEnabled());
});
// Disable battery saver and make sure the kill swtich is off.
runWithExpectingLocationCallback(() -> {
enableBatterySaver(false);
waitUntil("Kill switch still on", () -> getLocationGlobalKillSwitch() == 0);
assertNotEquals(LOCATION_MODE_OFF, getLocationMode());
assertTrue(getLocationManager().isLocationEnabled());
});
}
private int getLocationGlobalKillSwitch() {
return Global.getInt(getContext().getContentResolver(),
Global.LOCATION_GLOBAL_KILL_SWITCH, 0);
}
private int getLocationMode() {
return Secure.getInt(getContext().getContentResolver(), Secure.LOCATION_MODE, 0);
}
private void runWithExpectingLocationCallback(RunnableWithThrow r) throws Exception {
CallbackAsserter locationModeBroadcastAsserter = CallbackAsserter.forBroadcast(
new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
CallbackAsserter locationModeObserverAsserter = CallbackAsserter.forContentUri(
Settings.Secure.getUriFor(Settings.Secure.LOCATION_MODE));
r.run();
locationModeBroadcastAsserter.assertCalled("Broadcast not received",
DEFAULT_TIMEOUT_SECONDS);
locationModeObserverAsserter.assertCalled("Observer not notified",
DEFAULT_TIMEOUT_SECONDS);
}
/**
* Test for the {@link PowerManager#LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF} mode.
*/
@Test
public void testLocationRequestThrottling() throws Exception {
mLocationManager.addTestProvider(TEST_PROVIDER_NAME,
true, //requiresNetwork,
false, // requiresSatellite,
false, // requiresCell,
false, // hasMonetaryCost,
true, // supportsAltitude,
false, // supportsSpeed,
true, // supportsBearing,
Criteria.POWER_MEDIUM, // powerRequirement
Criteria.ACCURACY_FINE); // accuracy
mLocationManager.setTestProviderEnabled(TEST_PROVIDER_NAME, true);
LocationRequest normalLocationRequest = LocationRequest.create()
.setExpireIn(300_000)
.setFastestInterval(0)
.setInterval(0)
.setLocationSettingsIgnored(false)
.setProvider(TEST_PROVIDER_NAME)
.setQuality(LocationRequest.ACCURACY_FINE);
LocationRequest ignoreSettingsLocationRequest = LocationRequest.create()
.setExpireIn(300_000)
.setFastestInterval(0)
.setInterval(0)
.setLocationSettingsIgnored(true)
.setProvider(TEST_PROVIDER_NAME)
.setQuality(LocationRequest.ACCURACY_FINE);
mLocationManager.requestLocationUpdates(
normalLocationRequest, new TestLocationListener(), Looper.getMainLooper());
mLocationManager.requestLocationUpdates(
ignoreSettingsLocationRequest, new TestLocationListener(), Looper.getMainLooper());
assertTrue("Not enough requests sent to provider",
mLocationManager.getTestProviderCurrentRequests(TEST_PROVIDER_NAME).size() >= 2);
assertFalse("Normal priority requests not sent to provider",
areOnlyIgnoreSettingsRequestsSentToProvider());
assertTrue("Screen is off", getPowerManager().isInteractive());
SettingsUtils.set(SettingsUtils.NAMESPACE_GLOBAL, BATTERY_SAVER_CONSTANTS, "gps_mode=4");
assertFalse(getPowerManager().isPowerSaveMode());
assertEquals(PowerManager.LOCATION_MODE_NO_CHANGE,
getPowerManager().getLocationPowerSaveMode());
// Make sure location is enabled.
getLocationManager().setLocationEnabledForUser(true, Process.myUserHandle());
assertTrue(getLocationManager().isLocationEnabled());
// Unplug the charger and activate battery saver.
runDumpsysBatteryUnplug();
enableBatterySaver(true);
// Skip if the location mode is not what's expected.
final int mode = getPowerManager().getLocationPowerSaveMode();
if (mode != PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF) {
fail("Unexpected location power save mode (" + mode + "), skipping.");
}
// Make sure screen is on.
assertTrue(getPowerManager().isInteractive());
// Make sure location is still enabled.
assertTrue(getLocationManager().isLocationEnabled());
// Turn screen off.
turnOnScreen(false);
waitUntil("Normal location request still sent to provider",
this::areOnlyIgnoreSettingsRequestsSentToProvider);
assertTrue("Not enough requests sent to provider",
mLocationManager.getTestProviderCurrentRequests(TEST_PROVIDER_NAME).size() >= 1);
// On again.
turnOnScreen(true);
waitUntil("Normal location request not sent to provider",
() -> !areOnlyIgnoreSettingsRequestsSentToProvider());
assertTrue("Not enough requests sent to provider",
mLocationManager.getTestProviderCurrentRequests(TEST_PROVIDER_NAME).size() >= 2);
// Off again.
turnOnScreen(false);
waitUntil("Normal location request still sent to provider",
this::areOnlyIgnoreSettingsRequestsSentToProvider);
assertTrue("Not enough requests sent to provider",
mLocationManager.getTestProviderCurrentRequests(TEST_PROVIDER_NAME).size() >= 1);
// Disable battery saver and make sure the kill switch is off.
enableBatterySaver(false);
waitUntil("Normal location request not sent to provider",
() -> !areOnlyIgnoreSettingsRequestsSentToProvider());
assertTrue("Not enough requests sent to provider",
mLocationManager.getTestProviderCurrentRequests(TEST_PROVIDER_NAME).size() >= 2);
}
}