From d65184faef1076280e121c5cbc1db863f3f37924 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 19 Sep 2016 17:45:24 -0700 Subject: [PATCH] Log visibility change for DialogCreatable in Settings. Bug: 30681529 Test: adb logcat -b events | egrep "(sysui_|notification_)" Test: make RunSettingsRoboTests Change-Id: I51754d258ba1ddfae24323681f21cd02de4dbb4e --- src/com/android/settings/ApnSettings.java | 8 ++ src/com/android/settings/DialogCreatable.java | 2 + src/com/android/settings/DreamSettings.java | 8 ++ .../settings/EncryptionInterstitial.java | 8 ++ src/com/android/settings/ProxySelector.java | 5 ++ .../settings/SettingsPreferenceFragment.java | 24 ++++- src/com/android/settings/TetherSettings.java | 8 ++ ...ccessibilityServicePreferenceFragment.java | 9 ++ .../accounts/AccountSyncSettings.java | 18 +++- .../InstrumentedDialogFragment.java | 13 +++ .../display/NightDisplaySettings.java | 11 +++ .../users/RestrictedProfileSettings.java | 13 +++ .../settings/users/UserDetailsSettings.java | 15 ++++ .../android/settings/users/UserSettings.java | 26 ++++++ .../wifi/SavedAccessPointsWifiSettings.java | 11 +++ .../android/settings/wifi/WifiSettings.java | 16 ++++ .../settings/wifi/p2p/WifiP2pSettings.java | 15 ++++ .../settings/SettingsDialogFragmentTest.java | 88 +++++++++++++++++++ .../settings/SummaryPreferenceTest.java | 15 ++++ 19 files changed, 307 insertions(+), 6 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java diff --git a/src/com/android/settings/ApnSettings.java b/src/com/android/settings/ApnSettings.java index 9865fb24298..a32e421a01e 100644 --- a/src/com/android/settings/ApnSettings.java +++ b/src/com/android/settings/ApnSettings.java @@ -507,4 +507,12 @@ public class ApnSettings extends RestrictedSettingsFragment implements } return null; } + + @Override + public int getDialogMetricsCategory(int dialogId) { + if (dialogId == DIALOG_RESTORE_DEFAULTAPN) { + return MetricsEvent.DIALOG_APN_RESTORE_DEFAULT; + } + return 0; + } } diff --git a/src/com/android/settings/DialogCreatable.java b/src/com/android/settings/DialogCreatable.java index a0de2e03bff..ca0d3d1a158 100644 --- a/src/com/android/settings/DialogCreatable.java +++ b/src/com/android/settings/DialogCreatable.java @@ -26,4 +26,6 @@ import android.app.Dialog; public interface DialogCreatable { Dialog onCreateDialog(int dialogId); + + int getDialogMetricsCategory(int dialogId); } diff --git a/src/com/android/settings/DreamSettings.java b/src/com/android/settings/DreamSettings.java index 2a7c852b470..6587097ddfe 100644 --- a/src/com/android/settings/DreamSettings.java +++ b/src/com/android/settings/DreamSettings.java @@ -183,6 +183,14 @@ public class DreamSettings extends SettingsPreferenceFragment implements return super.onCreateDialog(dialogId); } + @Override + public int getDialogMetricsCategory(int dialogId) { + if (dialogId == DIALOG_WHEN_TO_DREAM) { + return MetricsEvent.DIALOG_DREAM_START_DELAY; + } + return 0; + } + private Dialog createWhenToDreamDialog() { final CharSequence[] items = { mContext.getString(R.string.screensaver_settings_summary_dock), diff --git a/src/com/android/settings/EncryptionInterstitial.java b/src/com/android/settings/EncryptionInterstitial.java index a26d0dcad9e..81945dfc836 100644 --- a/src/com/android/settings/EncryptionInterstitial.java +++ b/src/com/android/settings/EncryptionInterstitial.java @@ -259,6 +259,14 @@ public class EncryptionInterstitial extends SettingsActivity { } } + @Override + public int getDialogMetricsCategory(int dialogId) { + if (dialogId == ACCESSIBILITY_WARNING_DIALOG) { + return MetricsEvent.DIALOG_ENCRYPTION_INTERSTITIAL_ACCESSIBILITY; + } + return 0; + } + private void setRequirePasswordState(boolean required) { mPasswordRequired = required; } diff --git a/src/com/android/settings/ProxySelector.java b/src/com/android/settings/ProxySelector.java index ae5dd8b98f3..80de9da2ca4 100644 --- a/src/com/android/settings/ProxySelector.java +++ b/src/com/android/settings/ProxySelector.java @@ -108,6 +108,11 @@ public class ProxySelector extends InstrumentedFragment implements DialogCreatab return null; } + @Override + public int getDialogMetricsCategory(int dialogId) { + return MetricsEvent.DIALOG_PROXY_SELECTOR_ERROR; + } + private void showDialog(int dialogId) { if (mDialogFragment != null) { Log.e(TAG, "Old dialog fragment not null!"); diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java index cc87c056518..28230a97aac 100644 --- a/src/com/android/settings/SettingsPreferenceFragment.java +++ b/src/com/android/settings/SettingsPreferenceFragment.java @@ -46,9 +46,11 @@ import android.widget.Button; import com.android.settings.applications.LayoutPreference; import com.android.settings.core.InstrumentedFragment; +import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.HelpUtils; import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; /** * Base class for Settings fragments, with some helper functions and dialog management. @@ -501,10 +503,16 @@ public abstract class SettingsPreferenceFragment extends InstrumentedFragment mDialogFragment.show(getChildFragmentManager(), Integer.toString(dialogId)); } + @Override public Dialog onCreateDialog(int dialogId) { return null; } + @Override + public int getDialogMetricsCategory(int dialogId) { + return 0; + } + protected void removeDialog(int dialogId) { // mDialogFragment may not be visible yet in parent fragment's onResume(). // To be able to dismiss dialog at that time, don't check @@ -569,12 +577,10 @@ public abstract class SettingsPreferenceFragment extends InstrumentedFragment onDialogShowing(); } - public static class SettingsDialogFragment extends DialogFragment { + public static class SettingsDialogFragment extends InstrumentedDialogFragment { private static final String KEY_DIALOG_ID = "key_dialog_id"; private static final String KEY_PARENT_FRAGMENT_ID = "key_parent_fragment_id"; - private int mDialogId; - private Fragment mParentFragment; private DialogInterface.OnCancelListener mOnCancelListener; @@ -585,7 +591,7 @@ public abstract class SettingsPreferenceFragment extends InstrumentedFragment } public SettingsDialogFragment(DialogCreatable fragment, int dialogId) { - mDialogId = dialogId; + super(fragment, dialogId); if (!(fragment instanceof Fragment)) { throw new IllegalArgumentException("fragment argument must be an instance of " + Fragment.class.getName()); @@ -593,6 +599,16 @@ public abstract class SettingsPreferenceFragment extends InstrumentedFragment mParentFragment = (Fragment) fragment; } + + @Override + public int getMetricsCategory() { + final int metricsCategory = mDialogCreatable.getDialogMetricsCategory(mDialogId); + if (metricsCategory <= 0) { + throw new IllegalStateException("Dialog must provide a metrics category"); + } + return metricsCategory; + } + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); diff --git a/src/com/android/settings/TetherSettings.java b/src/com/android/settings/TetherSettings.java index 74853281edb..40c91cef46d 100644 --- a/src/com/android/settings/TetherSettings.java +++ b/src/com/android/settings/TetherSettings.java @@ -259,6 +259,14 @@ public class TetherSettings extends RestrictedSettingsFragment return null; } + @Override + public int getDialogMetricsCategory(int dialogId) { + if (dialogId == DIALOG_AP_SETTINGS) { + return MetricsEvent.DIALOG_AP_SETTINGS; + } + return 0; + } + private class TetherChangeReceiver extends BroadcastReceiver { @Override public void onReceive(Context content, Intent intent) { diff --git a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java index 31681788858..85358500de3 100644 --- a/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java +++ b/src/com/android/settings/accessibility/ToggleAccessibilityServicePreferenceFragment.java @@ -202,6 +202,15 @@ public class ToggleAccessibilityServicePreferenceFragment } } + @Override + public int getDialogMetricsCategory(int dialogId) { + if (dialogId == DIALOG_ID_ENABLE_WARNING) { + return MetricsEvent.DIALOG_ACCESSIBILITY_SERVICE_ENABLE; + } else { + return MetricsEvent.DIALOG_ACCESSIBILITY_SERVICE_DISABLE; + } + } + private void updateSwitchBarToggleSwitch() { final boolean checked = AccessibilityUtils.getEnabledServicesFromSettings(getActivity()) .contains(mComponentName); diff --git a/src/com/android/settings/accounts/AccountSyncSettings.java b/src/com/android/settings/accounts/AccountSyncSettings.java index 6b6791e025c..ae06f9c5bd7 100644 --- a/src/com/android/settings/accounts/AccountSyncSettings.java +++ b/src/com/android/settings/accounts/AccountSyncSettings.java @@ -52,13 +52,13 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import com.google.android.collect.Lists; - import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.Utils; import com.android.settingslib.RestrictedLockUtils; +import com.google.android.collect.Lists; + import java.io.IOException; import java.util.ArrayList; import java.util.Date; @@ -152,6 +152,20 @@ public class AccountSyncSettings extends AccountPreferenceBase { return MetricsEvent.ACCOUNTS_ACCOUNT_SYNC; } + @Override + public int getDialogMetricsCategory(int dialogId) { + switch (dialogId) { + case REALLY_REMOVE_DIALOG: + return MetricsEvent.DIALOG_ACCOUNT_SYNC_REMOVE; + case FAILED_REMOVAL_DIALOG: + return MetricsEvent.DIALOG_ACCOUNT_SYNC_FAILED_REMOVAL; + case CANT_DO_ONETIME_SYNC_DIALOG: + return MetricsEvent.DIALOG_ACCOUNT_SYNC_CANNOT_ONETIME_SYNC; + default: + return 0; + } + } + @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); diff --git a/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java b/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java index 6f970681cf4..f0a3fed8f76 100644 --- a/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java +++ b/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java @@ -15,12 +15,25 @@ */ package com.android.settings.core.instrumentation; +import com.android.settings.DialogCreatable; import com.android.settings.core.lifecycle.ObservableDialogFragment; public abstract class InstrumentedDialogFragment extends ObservableDialogFragment implements Instrumentable { + protected final DialogCreatable mDialogCreatable; + protected int mDialogId; + public InstrumentedDialogFragment() { + this(null /* parentFragment */, 0 /* dialogId */); + } + + /** + * Use this if the dialog is created via {@code DialogCreatable} + */ + public InstrumentedDialogFragment(DialogCreatable dialogCreatable, int dialogId) { + mDialogCreatable = dialogCreatable; + mDialogId = dialogId; mLifecycle.addObserver(new VisibilityLoggerMixin(getMetricsCategory())); } diff --git a/src/com/android/settings/display/NightDisplaySettings.java b/src/com/android/settings/display/NightDisplaySettings.java index 98352a76fc1..b37e2e2149a 100644 --- a/src/com/android/settings/display/NightDisplaySettings.java +++ b/src/com/android/settings/display/NightDisplaySettings.java @@ -155,6 +155,17 @@ public class NightDisplaySettings extends SettingsPreferenceFragment return super.onCreateDialog(dialogId); } + @Override + public int getDialogMetricsCategory(int dialogId) { + switch (dialogId) { + case DIALOG_START_TIME: + return MetricsEvent.DIALOG_NIGHT_DISPLAY_SET_START_TIME; + case DIALOG_END_TIME: + return MetricsEvent.DIALOG_NIGHT_DISPLAY_SET_END_TIME; + default: + return 0; + } + } @Override public void onActivated(boolean activated) { mActivatedPreference.setChecked(activated); diff --git a/src/com/android/settings/users/RestrictedProfileSettings.java b/src/com/android/settings/users/RestrictedProfileSettings.java index 182053f5be3..31722e25f7c 100644 --- a/src/com/android/settings/users/RestrictedProfileSettings.java +++ b/src/com/android/settings/users/RestrictedProfileSettings.java @@ -26,6 +26,7 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import com.android.internal.logging.MetricsProto; import com.android.settings.R; import com.android.settings.Utils; @@ -133,6 +134,18 @@ public class RestrictedProfileSettings extends AppRestrictionsFragment return null; } + @Override + public int getDialogMetricsCategory(int dialogId) { + switch (dialogId) { + case DIALOG_ID_EDIT_USER_INFO: + return MetricsProto.MetricsEvent.DIALOG_USER_EDIT; + case DIALOG_CONFIRM_REMOVE: + return MetricsProto.MetricsEvent.DIALOG_USER_REMOVE; + default: + return 0; + } + } + private void removeUser() { getView().post(new Runnable() { public void run() { diff --git a/src/com/android/settings/users/UserDetailsSettings.java b/src/com/android/settings/users/UserDetailsSettings.java index 65f55cb514f..47f800731c7 100644 --- a/src/com/android/settings/users/UserDetailsSettings.java +++ b/src/com/android/settings/users/UserDetailsSettings.java @@ -26,6 +26,7 @@ import android.os.UserManager; import android.support.v14.preference.SwitchPreference; import android.support.v7.preference.Preference; +import com.android.internal.logging.MetricsProto; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; @@ -192,6 +193,20 @@ public class UserDetailsSettings extends SettingsPreferenceFragment throw new IllegalArgumentException("Unsupported dialogId " + dialogId); } + @Override + public int getDialogMetricsCategory(int dialogId) { + switch (dialogId) { + case DIALOG_CONFIRM_REMOVE: + return MetricsProto.MetricsEvent.DIALOG_USER_REMOVE; + case DIALOG_CONFIRM_ENABLE_CALLING: + return MetricsProto.MetricsEvent.DIALOG_USER_ENABLE_CALLING; + case DIALOG_CONFIRM_ENABLE_CALLING_AND_SMS: + return MetricsProto.MetricsEvent.DIALOG_USER_ENABLE_CALLING_AND_SMS; + default: + return 0; + } + } + void removeUser() { mUserManager.removeUser(mUserInfo.id); finishFragment(); diff --git a/src/com/android/settings/users/UserSettings.java b/src/com/android/settings/users/UserSettings.java index bc3712e0caf..d070838ab86 100644 --- a/src/com/android/settings/users/UserSettings.java +++ b/src/com/android/settings/users/UserSettings.java @@ -622,6 +622,32 @@ public class UserSettings extends SettingsPreferenceFragment } } + @Override + public int getDialogMetricsCategory(int dialogId) { + switch (dialogId) { + case DIALOG_CONFIRM_REMOVE: + return MetricsEvent.DIALOG_USER_REMOVE; + case DIALOG_USER_CANNOT_MANAGE: + return MetricsEvent.DIALOG_USER_CANNOT_MANAGE; + case DIALOG_ADD_USER: + return MetricsEvent.DIALOG_USER_ADD; + case DIALOG_SETUP_USER: + return MetricsEvent.DIALOG_USER_SETUP; + case DIALOG_SETUP_PROFILE: + return MetricsEvent.DIALOG_USER_SETUP_PROFILE; + case DIALOG_CHOOSE_USER_TYPE: + return MetricsEvent.DIALOG_USER_CHOOSE_TYPE; + case DIALOG_NEED_LOCKSCREEN: + return MetricsEvent.DIALOG_USER_NEED_LOCKSCREEN; + case DIALOG_CONFIRM_EXIT_GUEST: + return MetricsEvent.DIALOG_USER_CONFIRM_EXIT_GUEST; + case DIALOG_USER_PROFILE_EDITOR: + return MetricsEvent.DIALOG_USER_EDIT_PROFILE; + default: + return 0; + } + } + private static boolean emergencyInfoActivityPresent(Context context) { Intent intent = new Intent(ACTION_EDIT_EMERGENCY_INFO).setPackage("com.android.emergency"); List infos = context.getPackageManager().queryIntentActivities(intent, 0); diff --git a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java index ea92b7f2ac4..55f0b636426 100644 --- a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java +++ b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java @@ -25,6 +25,7 @@ import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.util.Log; +import com.android.internal.logging.MetricsProto; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; @@ -151,6 +152,16 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment return super.onCreateDialog(dialogId); } + @Override + public int getDialogMetricsCategory(int dialogId) { + switch (dialogId) { + case WifiSettings.WIFI_DIALOG_ID: + return MetricsProto.MetricsEvent.DIALOG_WIFI_SAVED_AP_EDIT; + default: + return 0; + } + } + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java index 6198bc96086..782ff13896f 100644 --- a/src/com/android/settings/wifi/WifiSettings.java +++ b/src/com/android/settings/wifi/WifiSettings.java @@ -597,6 +597,22 @@ public class WifiSettings extends RestrictedSettingsFragment return super.onCreateDialog(dialogId); } + @Override + public int getDialogMetricsCategory(int dialogId) { + switch (dialogId) { + case WIFI_DIALOG_ID: + return MetricsEvent.DIALOG_WIFI_AP_EDIT; + case WPS_PBC_DIALOG_ID: + return MetricsEvent.DIALOG_WIFI_PBC; + case WPS_PIN_DIALOG_ID: + return MetricsEvent.DIALOG_WIFI_PIN; + case WRITE_NFC_DIALOG_ID: + return MetricsEvent.DIALOG_WIFI_WRITE_NFC; + default: + return 0; + } + } + /** * Shows the latest access points available with supplemental information like * the strength of network and the security for it. diff --git a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java index ddf7dfee418..487090d3873 100644 --- a/src/com/android/settings/wifi/p2p/WifiP2pSettings.java +++ b/src/com/android/settings/wifi/p2p/WifiP2pSettings.java @@ -495,6 +495,21 @@ public class WifiP2pSettings extends SettingsPreferenceFragment return MetricsEvent.WIFI_P2P; } + @Override + public int getDialogMetricsCategory(int dialogId) { + switch (dialogId) { + case DIALOG_DISCONNECT: + return MetricsEvent.DIALOG_WIFI_P2P_DISCONNECT; + case DIALOG_CANCEL_CONNECT: + return MetricsEvent.DIALOG_WIFI_P2P_CANCEL_CONNECT; + case DIALOG_RENAME: + return MetricsEvent.DIALOG_WIFI_P2P_RENAME; + case DIALOG_DELETE_GROUP: + return MetricsEvent.DIALOG_WIFI_P2P_DELETE_GROUP; + } + return 0; + } + @Override public void onSaveInstanceState(Bundle outState) { if (mSelectedWifiPeer != null) { diff --git a/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java b/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java new file mode 100644 index 00000000000..da23d5f2ad5 --- /dev/null +++ b/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 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; + +import android.app.Dialog; +import android.app.Fragment; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import static org.junit.Assert.fail; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SettingsDialogFragmentTest { + + private static final int DIALOG_ID = 15; + + @Mock + private DialogCreatableFragment mDialogCreatable; + private SettingsPreferenceFragment.SettingsDialogFragment mDialogFragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + public void testGetMetrics_shouldGetMetricFromDialogCreatable() { + when(mDialogCreatable.getDialogMetricsCategory(DIALOG_ID)).thenReturn(1); + + mDialogFragment = + new SettingsPreferenceFragment.SettingsDialogFragment(mDialogCreatable, DIALOG_ID); + mDialogFragment.getMetricsCategory(); + + // getDialogMetricsCategory called in constructor, and explicitly in test. + verify(mDialogCreatable, times(2)).getDialogMetricsCategory(DIALOG_ID); + } + + @Test + public void testGetInvalidMetricsValue_shouldCrash() { + when(mDialogCreatable.getDialogMetricsCategory(DIALOG_ID)).thenReturn(-1); + + try { + mDialogFragment = new SettingsPreferenceFragment.SettingsDialogFragment( + mDialogCreatable, DIALOG_ID); + } catch (IllegalStateException e) { + // getDialogMetricsCategory called in constructor + verify(mDialogCreatable).getDialogMetricsCategory(DIALOG_ID); + return; + } + fail("Should fail with IllegalStateException"); + } + + public static class DialogCreatableFragment extends Fragment implements DialogCreatable { + + @Override + public Dialog onCreateDialog(int dialogId) { + return null; + } + + @Override + public int getDialogMetricsCategory(int dialogId) { + return 0; + } + } +} diff --git a/tests/robotests/src/com/android/settings/SummaryPreferenceTest.java b/tests/robotests/src/com/android/settings/SummaryPreferenceTest.java index 8742846b972..e55f069c37b 100644 --- a/tests/robotests/src/com/android/settings/SummaryPreferenceTest.java +++ b/tests/robotests/src/com/android/settings/SummaryPreferenceTest.java @@ -1,3 +1,18 @@ +/* + * Copyright (C) 2016 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; import android.content.Context;