Loading location/java/android/location/LocationManager.java +11 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,17 @@ public class LocationManager { */ public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED"; /** * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} is * about to be changed through Settings app or Quick Settings. * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API. * If you're interacting with {@link #isProviderEnabled(String)}, use * {@link #PROVIDERS_CHANGED_ACTION} instead. * * @hide */ public static final String MODE_CHANGING_ACTION = "com.android.settings.location.MODE_CHANGING"; /** * Broadcast intent action indicating that the GPS has either started or * stopped receiving GPS fixes. An intent extra provides this state as a Loading packages/SettingsLib/src/com/android/settingslib/Utils.java +16 −0 Original line number Diff line number Diff line Loading @@ -14,8 +14,10 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.location.LocationManager; import android.net.ConnectivityManager; import android.os.BatteryManager; import android.os.UserHandle; import android.os.UserManager; import android.print.PrintManager; import android.provider.Settings; Loading @@ -26,6 +28,10 @@ import com.android.settingslib.drawable.UserIconDrawable; import java.text.NumberFormat; public class Utils { private static final String CURRENT_MODE_KEY = "CURRENT_MODE"; private static final String NEW_MODE_KEY = "NEW_MODE"; private static Signature[] sSystemSignature; private static String sPermissionControllerPackageName; private static String sServicesSystemSharedLibPackageName; Loading @@ -39,6 +45,16 @@ public class Utils { com.android.internal.R.drawable.ic_wifi_signal_4 }; public static boolean updateLocationMode(Context context, int oldMode, int newMode, int userId) { Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION); intent.putExtra(CURRENT_MODE_KEY, oldMode); intent.putExtra(NEW_MODE_KEY, newMode); context.sendBroadcastAsUser( intent, UserHandle.of(userId), android.Manifest.permission.WRITE_SECURE_SETTINGS); return Settings.Secure.putIntForUser( context.getContentResolver(), Settings.Secure.LOCATION_MODE, newMode, userId); } /** * Return string resource that best describes combination of tethering * options available on this device. Loading packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java +68 −1 Original line number Diff line number Diff line Loading @@ -15,20 +15,45 @@ */ package com.android.settingslib; import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.location.LocationManager; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Secure; import android.text.TextUtils; import java.util.HashMap; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatchers; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.res.Resources; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.shadows.ShadowSettings; @RunWith(SettingsLibRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config( manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {UtilsTest.ShadowSecure.class}) public class UtilsTest { private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100}; private static final String PERCENTAGE_0 = "0%"; Loading @@ -37,6 +62,29 @@ public class UtilsTest { private static final String PERCENTAGE_50 = "50%"; private static final String PERCENTAGE_100 = "100%"; private Context mContext; @Before public void setUp() { mContext = spy(RuntimeEnvironment.application); ShadowSecure.reset(); } @Test public void testUpdateLocationMode_sendBroadcast() { int currentUserId = ActivityManager.getCurrentUser(); Utils.updateLocationMode( mContext, Secure.LOCATION_MODE_OFF, Secure.LOCATION_MODE_HIGH_ACCURACY, currentUserId); verify(mContext).sendBroadcastAsUser( argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)), ArgumentMatchers.eq(UserHandle.of(currentUserId)), ArgumentMatchers.eq(WRITE_SECURE_SETTINGS)); } @Test public void testFormatPercentage_RoundTrue_RoundUpIfPossible() { final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1, Loading Loading @@ -74,4 +122,23 @@ public class UtilsTest { .thenReturn(60); assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60); } private static ArgumentMatcher<Intent> actionMatches(String expected) { return intent -> TextUtils.equals(expected, intent.getAction()); } @Implements(value = Settings.Secure.class) public static class ShadowSecure extends ShadowSettings.ShadowSecure { private static Map<String, Integer> map = new HashMap<>(); @Implementation public static boolean putIntForUser(ContentResolver cr, String name, int value, int userHandle) { map.put(name, value); return true; } public static void reset() { map.clear(); } } } packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java +5 −2 Original line number Diff line number Diff line Loading @@ -39,6 +39,8 @@ import com.android.systemui.util.Utils; import java.util.ArrayList; import java.util.List; import static com.android.settingslib.Utils.updateLocationMode; /** * A controller to manage changes of location related states and update the views accordingly. */ Loading Loading @@ -106,12 +108,13 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio final ContentResolver cr = mContext.getContentResolver(); // When enabling location, a user consent dialog will pop up, and the // setting won't be fully enabled until the user accepts the agreement. int currentMode = Settings.Secure.getIntForUser(cr, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, currentUserId); int mode = enabled ? Settings.Secure.LOCATION_MODE_PREVIOUS : Settings.Secure.LOCATION_MODE_OFF; // QuickSettings always runs as the owner, so specifically set the settings // for the current foreground user. return Settings.Secure .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId); return updateLocationMode(mContext, currentMode, mode, currentUserId); } /** Loading Loading
location/java/android/location/LocationManager.java +11 −0 Original line number Diff line number Diff line Loading @@ -183,6 +183,17 @@ public class LocationManager { */ public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED"; /** * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} is * about to be changed through Settings app or Quick Settings. * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API. * If you're interacting with {@link #isProviderEnabled(String)}, use * {@link #PROVIDERS_CHANGED_ACTION} instead. * * @hide */ public static final String MODE_CHANGING_ACTION = "com.android.settings.location.MODE_CHANGING"; /** * Broadcast intent action indicating that the GPS has either started or * stopped receiving GPS fixes. An intent extra provides this state as a Loading
packages/SettingsLib/src/com/android/settingslib/Utils.java +16 −0 Original line number Diff line number Diff line Loading @@ -14,8 +14,10 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.location.LocationManager; import android.net.ConnectivityManager; import android.os.BatteryManager; import android.os.UserHandle; import android.os.UserManager; import android.print.PrintManager; import android.provider.Settings; Loading @@ -26,6 +28,10 @@ import com.android.settingslib.drawable.UserIconDrawable; import java.text.NumberFormat; public class Utils { private static final String CURRENT_MODE_KEY = "CURRENT_MODE"; private static final String NEW_MODE_KEY = "NEW_MODE"; private static Signature[] sSystemSignature; private static String sPermissionControllerPackageName; private static String sServicesSystemSharedLibPackageName; Loading @@ -39,6 +45,16 @@ public class Utils { com.android.internal.R.drawable.ic_wifi_signal_4 }; public static boolean updateLocationMode(Context context, int oldMode, int newMode, int userId) { Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION); intent.putExtra(CURRENT_MODE_KEY, oldMode); intent.putExtra(NEW_MODE_KEY, newMode); context.sendBroadcastAsUser( intent, UserHandle.of(userId), android.Manifest.permission.WRITE_SECURE_SETTINGS); return Settings.Secure.putIntForUser( context.getContentResolver(), Settings.Secure.LOCATION_MODE, newMode, userId); } /** * Return string resource that best describes combination of tethering * options available on this device. Loading
packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java +68 −1 Original line number Diff line number Diff line Loading @@ -15,20 +15,45 @@ */ package com.android.settingslib; import android.app.ActivityManager; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.location.LocationManager; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Secure; import android.text.TextUtils; import java.util.HashMap; import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentMatcher; import org.mockito.ArgumentMatchers; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.res.Resources; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.shadows.ShadowSettings; @RunWith(SettingsLibRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config( manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {UtilsTest.ShadowSecure.class}) public class UtilsTest { private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100}; private static final String PERCENTAGE_0 = "0%"; Loading @@ -37,6 +62,29 @@ public class UtilsTest { private static final String PERCENTAGE_50 = "50%"; private static final String PERCENTAGE_100 = "100%"; private Context mContext; @Before public void setUp() { mContext = spy(RuntimeEnvironment.application); ShadowSecure.reset(); } @Test public void testUpdateLocationMode_sendBroadcast() { int currentUserId = ActivityManager.getCurrentUser(); Utils.updateLocationMode( mContext, Secure.LOCATION_MODE_OFF, Secure.LOCATION_MODE_HIGH_ACCURACY, currentUserId); verify(mContext).sendBroadcastAsUser( argThat(actionMatches(LocationManager.MODE_CHANGING_ACTION)), ArgumentMatchers.eq(UserHandle.of(currentUserId)), ArgumentMatchers.eq(WRITE_SECURE_SETTINGS)); } @Test public void testFormatPercentage_RoundTrue_RoundUpIfPossible() { final String[] expectedPercentages = {PERCENTAGE_0, PERCENTAGE_0, PERCENTAGE_1, Loading Loading @@ -74,4 +122,23 @@ public class UtilsTest { .thenReturn(60); assertThat(Utils.getDefaultStorageManagerDaysToRetain(resources)).isEqualTo(60); } private static ArgumentMatcher<Intent> actionMatches(String expected) { return intent -> TextUtils.equals(expected, intent.getAction()); } @Implements(value = Settings.Secure.class) public static class ShadowSecure extends ShadowSettings.ShadowSecure { private static Map<String, Integer> map = new HashMap<>(); @Implementation public static boolean putIntForUser(ContentResolver cr, String name, int value, int userHandle) { map.put(name, value); return true; } public static void reset() { map.clear(); } } }
packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationControllerImpl.java +5 −2 Original line number Diff line number Diff line Loading @@ -39,6 +39,8 @@ import com.android.systemui.util.Utils; import java.util.ArrayList; import java.util.List; import static com.android.settingslib.Utils.updateLocationMode; /** * A controller to manage changes of location related states and update the views accordingly. */ Loading Loading @@ -106,12 +108,13 @@ public class LocationControllerImpl extends BroadcastReceiver implements Locatio final ContentResolver cr = mContext.getContentResolver(); // When enabling location, a user consent dialog will pop up, and the // setting won't be fully enabled until the user accepts the agreement. int currentMode = Settings.Secure.getIntForUser(cr, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, currentUserId); int mode = enabled ? Settings.Secure.LOCATION_MODE_PREVIOUS : Settings.Secure.LOCATION_MODE_OFF; // QuickSettings always runs as the owner, so specifically set the settings // for the current foreground user. return Settings.Secure .putIntForUser(cr, Settings.Secure.LOCATION_MODE, mode, currentUserId); return updateLocationMode(mContext, currentMode, mode, currentUserId); } /** Loading