diff --git a/AndroidManifest.xml b/AndroidManifest.xml index aa98c62f49d..efa57ded87d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1161,7 +1161,7 @@ @@ -1180,7 +1180,7 @@ diff --git a/color-check-baseline.xml b/color-check-baseline.xml index 62c7915a3d3..d28f2d131ec 100644 --- a/color-check-baseline.xml +++ b/color-check-baseline.xml @@ -1213,6 +1213,22 @@ column="5"/> + + + + @@ -1241,7 +1257,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1257,7 +1273,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1273,7 +1289,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1289,7 +1305,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1305,7 +1321,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1321,7 +1337,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1337,7 +1353,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1353,7 +1369,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1369,7 +1385,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1385,7 +1401,7 @@ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> @@ -1853,6 +1869,38 @@ column="17"/> + + + + + + + + + + diff --git a/res/drawable/ic_homepage_location.xml b/res/drawable/ic_homepage_location.xml new file mode 100644 index 00000000000..413801b0a56 --- /dev/null +++ b/res/drawable/ic_homepage_location.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + diff --git a/res/drawable/ic_preference_location.xml b/res/drawable/ic_preference_location.xml new file mode 100644 index 00000000000..e37d629d404 --- /dev/null +++ b/res/drawable/ic_preference_location.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + diff --git a/res/drawable/ic_settings_location.xml b/res/drawable/ic_settings_location.xml index 34bd4f098b7..b7cfd6f2386 100644 --- a/res/drawable/ic_settings_location.xml +++ b/res/drawable/ic_settings_location.xml @@ -17,8 +17,7 @@ android:width="24.0dp" android:height="24.0dp" android:viewportWidth="24.0" - android:viewportHeight="24.0" - android:tint="?android:attr/colorControlNormal"> + android:viewportHeight="24.0"> diff --git a/res/values/colors.xml b/res/values/colors.xml index f398d9225ce..a00fd8a8b1f 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -125,6 +125,7 @@ #757575 #26459C #1A73E8 + #2EC7DC @*android:color/material_red_A700 diff --git a/res/values/dimens.xml b/res/values/dimens.xml index e163f7fe00a..18bcc38a162 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -88,6 +88,9 @@ 6dp + + 12dp + 72dp 16dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 84a807c3b0f..e828ac2b677 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -814,11 +814,13 @@ Location Use location + + Scanning, location history Accounts - Security & location + Security Encryption & credentials @@ -8943,12 +8945,6 @@ %1$s is default - - On - - - Off - Back up disabled diff --git a/res/xml/security_dashboard_settings.xml b/res/xml/security_dashboard_settings.xml index e543ad92406..ce271cc4752 100644 --- a/res/xml/security_dashboard_settings.xml +++ b/res/xml/security_dashboard_settings.xml @@ -95,12 +95,6 @@ android:key="security_settings_misc_category" android:title="@string/security_passwords_title"> - - @@ -35,7 +35,7 @@ android:title="@string/connected_devices_dashboard_title" android:summary="@string/summary_placeholder" android:icon="@drawable/ic_homepage_connected_device" - android:order="-100" + android:order="-110" android:fragment="com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment" settings:controller="com.android.settings.connecteddevice.TopLevelConnectedDevicesPreferenceController"/> @@ -44,7 +44,7 @@ android:title="@string/app_and_notification_dashboard_title" android:summary="@string/app_and_notification_dashboard_summary" android:icon="@drawable/ic_homepage_apps" - android:order="-90" + android:order="-100" android:fragment="com.android.settings.applications.AppAndNotificationDashboardFragment"/> @@ -70,7 +70,7 @@ android:title="@string/sound_settings" android:summary="@string/sound_dashboard_summary" android:icon="@drawable/ic_homepage_sound" - android:order="-60" + android:order="-70" android:fragment="com.android.settings.notification.SoundSettings"/> + + buildPreferenceControllers(Context context, Lifecycle lifecycle, SecuritySettings host) { final List controllers = new ArrayList<>(); - controllers.add(new LocationPreferenceController(context, lifecycle)); controllers.add(new EnterprisePrivacyPreferenceController(context)); controllers.add(new ManageTrustAgentsPreferenceController(context)); controllers.add(new ScreenPinningPreferenceController(context)); diff --git a/src/com/android/settings/slices/CopyableSlice.java b/src/com/android/settings/slices/CopyableSlice.java new file mode 100644 index 00000000000..31fc151d6ba --- /dev/null +++ b/src/com/android/settings/slices/CopyableSlice.java @@ -0,0 +1,28 @@ +/* + * 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 com.android.settings.slices; + +/** + * Provide the copy ability for preference controller to copy the data to the clipboard. + */ +public interface CopyableSlice { + /** + * Copy the key slice information to the clipboard. + * It is highly recommended to show the toast to notify users when implemented this function. + */ + void copy(); +} diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index 33576f5ddcd..fa669bb451a 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -106,6 +106,12 @@ public class SettingsSliceProvider extends SliceProvider { public static final String ACTION_SLIDER_CHANGED = "com.android.settings.slice.action.SLIDER_CHANGED"; + /** + * Action passed for copy data for the Copyable Slices. + */ + public static final String ACTION_COPY = + "com.android.settings.slice.action.COPY"; + /** * Intent Extra passed for the key identifying the Setting Slice. */ diff --git a/src/com/android/settings/slices/SliceBroadcastReceiver.java b/src/com/android/settings/slices/SliceBroadcastReceiver.java index e9e9d2cdb4b..4b86f336332 100644 --- a/src/com/android/settings/slices/SliceBroadcastReceiver.java +++ b/src/com/android/settings/slices/SliceBroadcastReceiver.java @@ -24,6 +24,7 @@ import static com.android.settings.network.telephony.Enhanced4gLteSliceHelper import static com.android.settings.notification.ZenModeSliceBuilder.ACTION_ZEN_MODE_SLICE_CHANGED; import static com.android.settings.slices.SettingsSliceProvider.ACTION_SLIDER_CHANGED; import static com.android.settings.slices.SettingsSliceProvider.ACTION_TOGGLE_CHANGED; +import static com.android.settings.slices.SettingsSliceProvider.ACTION_COPY; import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_KEY; import static com.android.settings.slices.SettingsSliceProvider.EXTRA_SLICE_PLATFORM_DEFINED; import static com.android.settings.wifi.calling.WifiCallingSliceHelper.ACTION_WIFI_CALLING_CHANGED; @@ -115,6 +116,9 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { case ACTION_FLASHLIGHT_SLICE_CHANGED: FlashlightSliceBuilder.handleUriChange(context, intent); break; + case ACTION_COPY: + handleCopyAction(context, key, isPlatformSlice); + break; } } @@ -184,6 +188,29 @@ public class SliceBroadcastReceiver extends BroadcastReceiver { updateUri(context, key, isPlatformSlice); } + private void handleCopyAction(Context context, String key, boolean isPlatformSlice) { + if (TextUtils.isEmpty(key)) { + throw new IllegalArgumentException("No key passed to Intent for controller"); + } + + final BasePreferenceController controller = getPreferenceController(context, key); + + if (!(controller instanceof CopyableSlice)) { + throw new IllegalArgumentException( + "Copyable action passed for a non-copyable key:" + key); + } + + if (!controller.isAvailable()) { + Log.w(TAG, "Can't update " + key + " since the setting is unavailable"); + if (!controller.hasAsyncUpdate()) { + updateUri(context, key, isPlatformSlice); + } + return; + } + + ((CopyableSlice) controller).copy(); + } + /** * Log Slice value update events into MetricsFeatureProvider. The logging schema generally * follows the pattern in SharedPreferenceLogger. diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java index 2432cc698a8..f6cc57f4f0e 100644 --- a/src/com/android/settings/slices/SliceBuilderUtils.java +++ b/src/com/android/settings/slices/SliceBuilderUtils.java @@ -93,6 +93,10 @@ public class SliceBuilderUtils { return buildUnavailableSlice(context, sliceData); } + if (controller instanceof CopyableSlice) { + return buildCopyableSlice(context, sliceData, controller); + } + switch (sliceData.getSliceType()) { case SliceData.SliceType.INTENT: return buildIntentSlice(context, sliceData, controller); @@ -324,6 +328,28 @@ public class SliceBuilderUtils { .build(); } + private static Slice buildCopyableSlice(Context context, SliceData sliceData, + BasePreferenceController controller) { + final SliceAction copyableAction = getCopyableAction(context, sliceData); + final PendingIntent contentIntent = getContentPendingIntent(context, sliceData); + final IconCompat icon = getSafeIcon(context, sliceData); + final SliceAction primaryAction = new SliceAction(contentIntent, icon, + sliceData.getTitle()); + final CharSequence subtitleText = getSubtitleText(context, controller, sliceData); + @ColorInt final int color = Utils.getColorAccentDefaultColor(context); + final Set keywords = buildSliceKeywords(sliceData); + + return new ListBuilder(context, sliceData.getUri(), ListBuilder.INFINITY) + .setAccentColor(color) + .addRow(new RowBuilder() + .setTitle(sliceData.getTitle()) + .setSubtitle(subtitleText) + .setPrimaryAction(primaryAction) + .addEndItem(copyableAction)) + .setKeywords(keywords) + .build(); + } + private static BasePreferenceController getPreferenceController(Context context, String controllerClassName, String controllerKey) { try { @@ -346,6 +372,14 @@ public class SliceBuilderUtils { return getActionIntent(context, SettingsSliceProvider.ACTION_SLIDER_CHANGED, sliceData); } + private static SliceAction getCopyableAction(Context context, SliceData sliceData) { + final PendingIntent intent = getActionIntent(context, + SettingsSliceProvider.ACTION_COPY, sliceData); + final IconCompat icon = IconCompat.createWithResource(context, + R.drawable.ic_content_copy_grey600_24dp); + return new SliceAction(intent, icon, sliceData.getTitle()); + } + private static boolean isValidSummary(Context context, CharSequence summary) { if (summary == null || TextUtils.isEmpty(summary.toString().trim())) { return false; diff --git a/src/com/android/settings/users/AppRestrictionsFragment.java b/src/com/android/settings/users/AppRestrictionsFragment.java index a4e0cff5c3a..5f899ebe8f5 100644 --- a/src/com/android/settings/users/AppRestrictionsFragment.java +++ b/src/com/android/settings/users/AppRestrictionsFragment.java @@ -450,7 +450,7 @@ public class AppRestrictionsFragment extends SettingsPreferenceFragment implemen private void addLocationAppRestrictionsPreference(AppRestrictionsHelper.SelectableAppInfo app, AppRestrictionsPreference p) { String packageName = app.packageName; - p.setIcon(R.drawable.ic_settings_location); + p.setIcon(R.drawable.ic_preference_location); p.setKey(getKeyForPackage(packageName)); ArrayList restrictions = RestrictionUtils.getRestrictions( getActivity(), mUser); diff --git a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java index a4d15676327..26489165d88 100644 --- a/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accounts/AccountDetailDashboardFragmentTest.java @@ -35,8 +35,10 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; import android.os.Bundle; import android.os.UserHandle; +import android.os.UserManager; import androidx.fragment.app.FragmentActivity; import androidx.preference.Preference; @@ -44,9 +46,12 @@ import androidx.preference.Preference; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.dashboard.DashboardFeatureProviderImpl; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.ShadowAccountManager; +import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.Tile; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -54,10 +59,11 @@ import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; import org.robolectric.Shadows; import org.robolectric.annotation.Config; -import org.robolectric.shadows.ShadowAccountManager; +import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = {ShadowAccountManager.class, ShadowUserManager.class}) public class AccountDetailDashboardFragmentTest { private static final String METADATA_CATEGORY = "com.android.settings.category"; @@ -86,6 +92,11 @@ public class AccountDetailDashboardFragmentTest { when(mFragment.getContext()).thenReturn(mContext); } + @After + public void tearDown() { + ShadowAccountManager.reset(); + } + @Test public void testCategory_isAccountDetail() { assertThat(new AccountDetailDashboardFragment().getCategoryKey()) @@ -152,17 +163,45 @@ public class AccountDetailDashboardFragmentTest { } @Test - @Config(shadows = {ShadowAccountManager.class}) public void onResume_accountMissing_shouldFinish() { + ShadowUserManager userManager = Shadow.extract( + mContext.getSystemService(UserManager.class)); + ShadowAccountManager acctMgr = Shadow.extract( + mContext.getSystemService(AccountManager.class)); + + userManager.addProfile(new UserInfo(1, null, 0)); + acctMgr.addAccountForUser(1, new Account("test@test.com", "com.test")); + mFragment.finishIfAccountMissing(); verify(mFragment).finish(); } @Test - @Config(shadows = {ShadowAccountManager.class}) - public void onResume_accountPresent_shouldNotFinish() { - AccountManager mgr = mContext.getSystemService(AccountManager.class); - Shadows.shadowOf(mgr).addAccount(mFragment.mAccount); + public void onResume_accountPresentOneProfile_shouldNotFinish() { + ShadowUserManager userManager = Shadow.extract( + mContext.getSystemService(UserManager.class)); + ShadowAccountManager acctMgr = Shadow.extract( + mContext.getSystemService(AccountManager.class)); + + userManager.addProfile(new UserInfo(1, null, 0)); + acctMgr.addAccountForUser(1, mFragment.mAccount); + + mFragment.finishIfAccountMissing(); + verify(mFragment, never()).finish(); + } + + @Test + public void onResume_accountPresentTwoProfiles_shouldNotFinish() { + ShadowUserManager userManager = Shadow.extract( + mContext.getSystemService(UserManager.class)); + ShadowAccountManager acctMgr = Shadow.extract( + mContext.getSystemService(AccountManager.class)); + + userManager.addProfile(new UserInfo(1, null, 0)); + userManager.addProfile(new UserInfo(2, null, 0)); + acctMgr.addAccountForUser(1, new Account("test@test.com", "com.test")); + acctMgr.addAccountForUser(2, mFragment.mAccount); + mFragment.finishIfAccountMissing(); verify(mFragment, never()).finish(); } diff --git a/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java index 22c2cdb588c..241765e8ecb 100644 --- a/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accounts/ChooseAccountPreferenceControllerTest.java @@ -76,7 +76,7 @@ public class ChooseAccountPreferenceControllerTest { @After public void tearDown() { ShadowContentResolver.reset(); - ShadowAccountManager.resetAuthenticator(); + ShadowAccountManager.reset(); ShadowRestrictedLockUtilsInternal.clearDisabledTypes(); } diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java index 4ef982fe17e..b25508b13d5 100644 --- a/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/CardDatabaseHelperTest.java @@ -74,6 +74,7 @@ public class CardDatabaseHelperTest { CardDatabaseHelper.CardColumns.CARD_ACTION, CardDatabaseHelper.CardColumns.EXPIRE_TIME_MS, CardDatabaseHelper.CardColumns.SUPPORT_HALF_WIDTH, + CardDatabaseHelper.CardColumns.CARD_DISMISSED, }; assertThat(columnNames).isEqualTo(expectedNames); diff --git a/tests/robotests/src/com/android/settings/location/LocationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationPreferenceControllerTest.java deleted file mode 100644 index c12fdc90f7d..00000000000 --- a/tests/robotests/src/com/android/settings/location/LocationPreferenceControllerTest.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2017 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 com.android.settings.location; - -import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE; -import static androidx.lifecycle.Lifecycle.Event.ON_RESUME; - -import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.nullable; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.location.LocationManager; -import android.provider.Settings.Secure; - -import androidx.lifecycle.LifecycleOwner; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settingslib.core.lifecycle.Lifecycle; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Answers; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - -@RunWith(SettingsRobolectricTestRunner.class) -public class LocationPreferenceControllerTest { - @Mock - private Preference mPreference; - @Mock - private PreferenceScreen mScreen; - - private LifecycleOwner mLifecycleOwner; - private Lifecycle mLifecycle; - private LocationPreferenceController mController; - - @Mock(answer = Answers.RETURNS_DEEP_STUBS) - private Context mContext; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mLifecycleOwner = () -> mLifecycle; - mLifecycle = new Lifecycle(mLifecycleOwner); - mController = new LocationPreferenceController(mContext, mLifecycle); - when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); - } - - @Test - public void isAvailable_shouldReturnTrue() { - assertThat(mController.isAvailable()).isTrue(); - } - - @Test - public void updateState_shouldSetSummary() { - mController.updateState(mPreference); - - verify(mPreference).setSummary(nullable(String.class)); - } - - @Test - public void updateSummary_shouldSetSummary() { - mController.displayPreference(mScreen); - mController.updateSummary(); - - verify(mPreference).setSummary(nullable(String.class)); - } - - @Test - public void getLocationSummary_locationOff_shouldSetSummaryOff() { - final ContentResolver contentResolver = mContext.getContentResolver(); - Secure.putInt(contentResolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_OFF); - - final String locationSummary = mController.getLocationSummary(mContext); - assertThat(locationSummary).isEqualTo(mContext.getString(R.string.location_off_summary)); - } - - @Test - public void getLocationSummary_sensorsOnly_shouldSetSummaryOn() { - final ContentResolver contentResolver = mContext.getContentResolver(); - Secure.putInt(contentResolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_SENSORS_ONLY); - - final String locationSummary = mController.getLocationSummary(mContext); - assertThat(locationSummary).isEqualTo(mContext.getString(R.string.location_on_summary)); - } - - @Test - public void getLocationSummary_highAccuracy_shouldSetSummaryOn() { - final ContentResolver contentResolver = mContext.getContentResolver(); - Secure.putInt(contentResolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_HIGH_ACCURACY); - - final String locationSummary = mController.getLocationSummary(mContext); - assertThat(locationSummary).isEqualTo(mContext.getString(R.string.location_on_summary)); - } - - @Test - public void getLocationSummary_batterySaving_shouldSetSummaryOn() { - final ContentResolver contentResolver = mContext.getContentResolver(); - Secure.putInt(contentResolver, Secure.LOCATION_MODE, Secure.LOCATION_MODE_BATTERY_SAVING); - - final String locationSummary = mController.getLocationSummary(mContext); - assertThat(locationSummary).isEqualTo(mContext.getString(R.string.location_on_summary)); - } - - @Test - public void onResume_shouldRegisterObserver() { - mLifecycle.handleLifecycleEvent(ON_RESUME); - verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class)); - } - - @Test - public void onPause_shouldUnregisterObserver() { - mLifecycle.handleLifecycleEvent(ON_RESUME); - mLifecycle.handleLifecycleEvent(ON_PAUSE); - verify(mContext).unregisterReceiver(any(BroadcastReceiver.class)); - } - - @Test - public void locationProvidersChangedReceiver_updatesPreferenceSummary() { - mController.displayPreference(mScreen); - mController.onResume(); - - mController.mLocationProvidersChangedReceiver - .onReceive(mContext, new Intent(LocationManager.PROVIDERS_CHANGED_ACTION)); - - verify(mPreference).setSummary(any()); - } -} diff --git a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java index 1055667f3c0..43712788312 100644 --- a/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java +++ b/tests/robotests/src/com/android/settings/slices/SliceBuilderUtilsTest.java @@ -41,6 +41,7 @@ import androidx.slice.widget.SliceLiveData; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; +import com.android.settings.testutils.FakeCopyableController; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.FakeSliderController; import com.android.settings.testutils.FakeToggleController; @@ -67,6 +68,7 @@ public class SliceBuilderUtilsTest { private final Uri URI = Uri.parse("content://com.android.settings.slices/test"); private final Class TOGGLE_CONTROLLER = FakeToggleController.class; private final Class SLIDER_CONTROLLER = FakeSliderController.class; + private final Class COPYABLE_CONTROLLER = FakeCopyableController.class; private final Class CONTEXT_CONTROLLER = FakeContextOnlyPreferenceController.class; private final boolean IS_DYNAMIC_SUMMARY_ALLOWED = false; @@ -116,7 +118,6 @@ public class SliceBuilderUtilsTest { public void buildSliderSlice_returnsMatchingSlice() { final SliceData data = getDummyData(SLIDER_CONTROLLER, SliceData.SliceType.SLIDER); - final Slice slice = SliceBuilderUtils.buildSlice(mContext, data); verify(mFeatureFactory.metricsFeatureProvider) .action(eq(mContext), eq(MetricsEvent.ACTION_SETTINGS_SLICE_REQUESTED), @@ -130,6 +131,23 @@ public class SliceBuilderUtilsTest { SliceTester.testSettingsSliderSlice(mContext, slice, data); } + @Test + public void buildCopyableSlice_returnsMatchingSlice() { + final SliceData dummyData = getDummyData(COPYABLE_CONTROLLER, -1); + + final Slice slice = SliceBuilderUtils.buildSlice(mContext, dummyData); + verify(mFeatureFactory.metricsFeatureProvider) + .action(eq(mContext), eq(MetricsEvent.ACTION_SETTINGS_SLICE_REQUESTED), + mLoggingArgumentCatpor.capture()); + final Pair capturedLoggingPair = mLoggingArgumentCatpor.getValue(); + + assertThat(capturedLoggingPair.first) + .isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME); + assertThat(capturedLoggingPair.second) + .isEqualTo(dummyData.getKey()); + SliceTester.testSettingsCopyableSlice(mContext, slice, dummyData); + } + @Test public void testUriBuilder_oemAuthority_intentPath_returnsValidSliceUri() { final Uri expectedUri = new Uri.Builder() diff --git a/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java b/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java new file mode 100644 index 00000000000..a02377cf268 --- /dev/null +++ b/tests/robotests/src/com/android/settings/testutils/FakeCopyableController.java @@ -0,0 +1,44 @@ +/* + * 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 com.android.settings.testutils; + +import android.content.Context; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.slices.CopyableSlice; + +public class FakeCopyableController extends BasePreferenceController implements + CopyableSlice { + + public FakeCopyableController(Context context, String preferenceKey) { + super(context, preferenceKey); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public boolean isSliceable() { + return true; + } + + @Override + public void copy() { + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/SliceTester.java b/tests/robotests/src/com/android/settings/testutils/SliceTester.java index 892f948fe19..be4199da2d5 100644 --- a/tests/robotests/src/com/android/settings/testutils/SliceTester.java +++ b/tests/robotests/src/com/android/settings/testutils/SliceTester.java @@ -168,6 +168,43 @@ public class SliceTester { assertKeywords(metadata, sliceData); } + /** + * Test the copyable slice, including: + * - No intent + * - Correct title + * - Correct intent + * - Correct keywords + * - TTL + * - Color + */ + public static void testSettingsCopyableSlice(Context context, Slice slice, + SliceData sliceData) { + final SliceMetadata metadata = SliceMetadata.from(context, slice); + + final SliceItem colorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR); + final int color = colorItem.getInt(); + assertThat(color).isEqualTo(Utils.getColorAccentDefaultColor(context)); + + final SliceAction primaryAction = metadata.getPrimaryAction(); + + final IconCompat expectedIcon = IconCompat.createWithResource(context, + sliceData.getIconResource()); + assertThat(expectedIcon.toString()).isEqualTo(primaryAction.getIcon().toString()); + + final long sliceTTL = metadata.getExpiry(); + assertThat(sliceTTL).isEqualTo(ListBuilder.INFINITY); + + // Check primary intent + final PendingIntent primaryPendingIntent = primaryAction.getAction(); + assertThat(primaryPendingIntent).isEqualTo( + SliceBuilderUtils.getContentPendingIntent(context, sliceData)); + + final List sliceItems = slice.getItems(); + assertTitle(sliceItems, sliceData.getTitle()); + + assertKeywords(metadata, sliceData); + } + /** * Test the contents of an unavailable slice, including: * - No toggles @@ -229,4 +266,4 @@ public class SliceTester { expectedKeywords.add(data.getScreenTitle().toString()); assertThat(keywords).containsExactlyElementsIn(expectedKeywords); } -} \ No newline at end of file +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java index 03aabb5dbb5..4401926c4fd 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccountManager.java @@ -16,19 +16,24 @@ package com.android.settings.testutils.shadow; +import android.accounts.Account; import android.accounts.AccountManager; import android.accounts.AuthenticatorDescription; +import android.annotation.NonNull; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; @Implements(AccountManager.class) public class ShadowAccountManager{ private static final Map sAuthenticators = new HashMap<>(); + private static final Map> sAccountsByUserId = new HashMap<>(); @Implementation public AuthenticatorDescription[] getAuthenticatorTypesAsUser(int userId) { @@ -39,7 +44,24 @@ public class ShadowAccountManager{ sAuthenticators.put(authenticator.type, authenticator); } - public static void resetAuthenticator() { + public static void reset() { sAuthenticators.clear(); + sAccountsByUserId.clear(); + } + + @Implementation @NonNull + public Account[] getAccountsAsUser(int userId) { + if (sAccountsByUserId.containsKey(userId)) { + return sAccountsByUserId.get(userId).toArray(new Account[0]); + } else { + return new Account[0]; + } + } + + public static void addAccountForUser(int userId, Account account) { + if (!sAccountsByUserId.containsKey(userId)) { + sAccountsByUserId.put(userId, new ArrayList<>()); + } + sAccountsByUserId.get(userId).add(account); } }