From e72fb487f23b9377e4b258395cd471462be6a3df Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Wed, 1 Nov 2017 12:54:29 -0700 Subject: [PATCH 01/21] Add screen resource for Colors setting. - each preference fragment should have its own preference screen layout in order to show the title correctly. Adding the missing data for ColorModePreferenceFragment. Change-Id: I172429dc957f94351456d4bc829897a578d7dbf9 Fixes: 68763217 Test: make RunSettingsRoboTests (cherry picked from commit 5a66ddbd6f399e5413bc058ce12cb1646e4e3903) --- res/xml/color_mode_settings.xml | 21 ++++++++++++++++ .../display/ColorModePreferenceFragment.java | 5 ++++ .../widget/RadioButtonPickerFragment.java | 3 +++ .../DefaultAppPickerFragmentTest.java | 5 ++++ .../ColorModePreferenceFragmentTest.java | 24 ++++++++++++++++--- .../widget/RadioButtonPickerFragmentTest.java | 5 ++++ 6 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 res/xml/color_mode_settings.xml diff --git a/res/xml/color_mode_settings.xml b/res/xml/color_mode_settings.xml new file mode 100644 index 00000000000..b7f58d2ea08 --- /dev/null +++ b/res/xml/color_mode_settings.xml @@ -0,0 +1,21 @@ + + + + diff --git a/src/com/android/settings/display/ColorModePreferenceFragment.java b/src/com/android/settings/display/ColorModePreferenceFragment.java index 07cf82e7901..9f18fd8423b 100644 --- a/src/com/android/settings/display/ColorModePreferenceFragment.java +++ b/src/com/android/settings/display/ColorModePreferenceFragment.java @@ -44,6 +44,11 @@ public class ColorModePreferenceFragment extends RadioButtonPickerFragment { mController = new NightDisplayController(context); } + @Override + protected int getPreferenceScreenResId() { + return R.xml.color_mode_settings; + } + @Override protected List getCandidates() { Context c = getContext(); diff --git a/src/com/android/settings/widget/RadioButtonPickerFragment.java b/src/com/android/settings/widget/RadioButtonPickerFragment.java index 7489a772c5c..c7689090959 100644 --- a/src/com/android/settings/widget/RadioButtonPickerFragment.java +++ b/src/com/android/settings/widget/RadioButtonPickerFragment.java @@ -82,6 +82,9 @@ public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFr return view; } + @Override + protected abstract int getPreferenceScreenResId(); + @Override public void onRadioButtonClicked(RadioButtonPreference selected) { final String selectedKey = selected.getKey(); diff --git a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java index 3621edd3645..42a62254a0a 100644 --- a/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java +++ b/tests/robotests/src/com/android/settings/applications/defaultapps/DefaultAppPickerFragmentTest.java @@ -114,6 +114,11 @@ public class DefaultAppPickerFragmentTest { return 0; } + @Override + protected int getPreferenceScreenResId() { + return 0; + } + @Override protected List getCandidates() { return new ArrayList<>(); diff --git a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java index 9ee79ffe545..fb9bb9f490b 100644 --- a/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/display/ColorModePreferenceFragmentTest.java @@ -16,11 +16,18 @@ package com.android.settings.display; import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.os.Bundle; + import com.android.internal.app.NightDisplayController; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowSystemProperties; @@ -111,20 +118,31 @@ public class ColorModePreferenceFragmentTest { @Test public void setKey_natural() { mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_NATURAL); - Mockito.verify(mController).setColorMode(NightDisplayController.COLOR_MODE_NATURAL); + verify(mController).setColorMode(NightDisplayController.COLOR_MODE_NATURAL); } @Config(shadows = {SettingsShadowSystemProperties.class}) @Test public void setKey_boosted() { mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_BOOSTED); - Mockito.verify(mController).setColorMode(NightDisplayController.COLOR_MODE_BOOSTED); + verify(mController).setColorMode(NightDisplayController.COLOR_MODE_BOOSTED); } @Config(shadows = {SettingsShadowSystemProperties.class}) @Test public void setKey_saturated() { mFragment.setDefaultKey(ColorModePreferenceFragment.KEY_COLOR_MODE_SATURATED); - Mockito.verify(mController).setColorMode(NightDisplayController.COLOR_MODE_SATURATED); + verify(mController).setColorMode(NightDisplayController.COLOR_MODE_SATURATED); } + + @Test + public void onCreatePreferences_useNewTitle_shouldAddColorModePreferences() { + doNothing().when(mFragment).addPreferencesFromResource(anyInt()); + doNothing().when(mFragment).updateCandidates(); + + mFragment.onCreatePreferences(Bundle.EMPTY, null /* rootKey */); + + verify(mFragment).addPreferencesFromResource(R.xml.color_mode_settings); + } + } diff --git a/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java b/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java index 40d73eb327a..8ca68ae50b7 100644 --- a/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java +++ b/tests/robotests/src/com/android/settings/widget/RadioButtonPickerFragmentTest.java @@ -113,6 +113,11 @@ public class RadioButtonPickerFragmentTest { return 0; } + @Override + protected int getPreferenceScreenResId() { + return 0; + } + @Override protected List getCandidates() { return new ArrayList<>(); From e33bbc6c7ac45f96f1b4a6c310386102f5a1e4a0 Mon Sep 17 00:00:00 2001 From: Matthew Fritze Date: Thu, 9 Nov 2017 09:40:09 -0800 Subject: [PATCH 02/21] Prevent crash in Search from Stack overflow NotificationSettingBase's getPreferenceController call is recursive with no base case which crashes search. Root cause here is that NotificationSettingsBase should not be indexed for seacrh but was probably failing the code inspection test. Added NotificationSettingsBase child classes to grandfather list of classes that should be ignored for search. Change-Id: I04ed242db3a394b88e0d0ac420aaaff6f9301cb5 Fixes: 69096424 Test: robotests (cherry picked from commit f6cf598d0325c3c96927285b22c84f042e95b6fb) --- .../ChannelImportanceSettings.java | 11 ----- .../NotificationSettingsBase.java | 40 +++++++------------ .../search/SearchIndexableResources.java | 9 ----- ...randfather_not_implementing_index_provider | 6 ++- .../grandfather_not_implementing_indexable | 2 +- 5 files changed, 20 insertions(+), 48 deletions(-) diff --git a/src/com/android/settings/notification/ChannelImportanceSettings.java b/src/com/android/settings/notification/ChannelImportanceSettings.java index bffed08079c..27b23b8c2cc 100644 --- a/src/com/android/settings/notification/ChannelImportanceSettings.java +++ b/src/com/android/settings/notification/ChannelImportanceSettings.java @@ -163,15 +163,4 @@ public class ChannelImportanceSettings extends NotificationSettingsBase mChannel.lockFields(USER_LOCKED_IMPORTANCE); mBackend.updateChannel(mAppRow.pkg, mAppRow.uid, mChannel); } - - // This page exists per notification channel; should not be included - // in search - public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getXmlResourcesToIndex( - Context context, boolean enabled) { - return null; - } - }; } diff --git a/src/com/android/settings/notification/NotificationSettingsBase.java b/src/com/android/settings/notification/NotificationSettingsBase.java index e9da5d96f32..9afb61845ee 100644 --- a/src/com/android/settings/notification/NotificationSettingsBase.java +++ b/src/com/android/settings/notification/NotificationSettingsBase.java @@ -208,15 +208,19 @@ abstract public class NotificationSettingsBase extends DashboardFragment { intent, 0 //PackageManager.MATCH_DEFAULT_ONLY ); - if (DEBUG) Log.d(TAG, "Found " + resolveInfos.size() + " preference activities" - + (resolveInfos.size() == 0 ? " ;_;" : "")); + if (DEBUG) { + Log.d(TAG, "Found " + resolveInfos.size() + " preference activities" + + (resolveInfos.size() == 0 ? " ;_;" : "")); + } for (ResolveInfo ri : resolveInfos) { final ActivityInfo activityInfo = ri.activityInfo; final ApplicationInfo appInfo = activityInfo.applicationInfo; if (mAppRow.settingsIntent != null) { - if (DEBUG) Log.v(TAG, "Ignoring duplicate notification preference activity (" - + activityInfo.name + ") for package " - + activityInfo.packageName); + if (DEBUG) { + Log.d(TAG, "Ignoring duplicate notification preference activity (" + + activityInfo.name + ") for package " + + activityInfo.packageName); + } continue; } mAppRow.settingsIntent = intent @@ -280,7 +284,7 @@ abstract public class NotificationSettingsBase extends DashboardFragment { public boolean onPreferenceChange(Preference preference, Object o) { boolean value = (Boolean) o; - int importance = value ? IMPORTANCE_LOW : IMPORTANCE_NONE; + int importance = value ? IMPORTANCE_LOW : IMPORTANCE_NONE; channel.setImportance(importance); channel.lockFields( NotificationChannel.USER_LOCKED_IMPORTANCE); @@ -365,8 +369,10 @@ abstract public class NotificationSettingsBase extends DashboardFragment { public void onReceive(Context context, Intent intent) { String packageName = intent.getData().getSchemeSpecificPart(); if (mPkgInfo == null || TextUtils.equals(mPkgInfo.packageName, packageName)) { - if (DEBUG) Log.d(TAG, "Package (" + packageName + ") removed. Removing" - + "NotificationSettingsBase."); + if (DEBUG) { + Log.d(TAG, "Package (" + packageName + ") removed. Removing" + + "NotificationSettingsBase."); + } onPackageRemoved(); } } @@ -380,24 +386,6 @@ abstract public class NotificationSettingsBase extends DashboardFragment { return left.getId().compareTo(right.getId()); }; - /** - * These screens aren't searchable - they only make sense in the context of an app, so - * surfacing a generic version would be impossible. - */ - public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getXmlResourcesToIndex(Context context, - boolean enabled) { - return new ArrayList<>(); - } - - @Override - public List getPreferenceControllers(Context context) { - return getPreferenceControllers(context); - } - }; - protected class ImportanceListener { protected void onImportanceChanged() { final PreferenceScreen screen = getPreferenceScreen(); diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index 4548342ad57..c5243460eb3 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -64,10 +64,6 @@ import com.android.settings.location.LocationSettings; import com.android.settings.location.ScanningSettings; import com.android.settings.network.NetworkDashboardFragment; import com.android.settings.nfc.PaymentSettings; -import com.android.settings.notification.AppNotificationSettings; -import com.android.settings.notification.ChannelGroupNotificationSettings; -import com.android.settings.notification.ChannelImportanceSettings; -import com.android.settings.notification.ChannelNotificationSettings; import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.SoundSettings; import com.android.settings.notification.ZenModeAutomationSettings; @@ -161,7 +157,6 @@ public final class SearchIndexableResources { addIndex(TtsEnginePreferenceFragment.class); addIndex(MagnificationPreferenceFragment.class); addIndex(AccessibilityShortcutPreferenceFragment.class); - addIndex(ChannelImportanceSettings.class); addIndex(DreamSettings.class); addIndex(SupportDashboardActivity.class); addIndex(AutomaticStorageManagerSettings.class); @@ -171,10 +166,6 @@ public final class SearchIndexableResources { addIndex(LockscreenDashboardFragment.class); addIndex(ZenModeBehaviorSettings.class); addIndex(ZenModeAutomationSettings.class); - addIndex(AppNotificationSettings.class); - addIndex(ChannelNotificationSettings.class); - addIndex(ChannelImportanceSettings.class); - addIndex(ChannelGroupNotificationSettings.class); } private SearchIndexableResources() { diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider index fda5c8a5c70..6704fc3fb0e 100644 --- a/tests/robotests/assets/grandfather_not_implementing_index_provider +++ b/tests/robotests/assets/grandfather_not_implementing_index_provider @@ -7,6 +7,10 @@ com.android.settings.fuelgauge.AdvancedPowerUsageDetail com.android.settings.development.featureflags.FeatureFlagsDashboard com.android.settings.development.qstile.DevelopmentTileConfigFragment com.android.settings.deviceinfo.StorageProfileFragment +com.android.settings.notification.ChannelNotificationSettings +com.android.settings.notification.ChannelImportanceSettings +com.android.settings.notification.ChannelGroupNotificationSettings +com.android.settings.notification.AppNotificationSettings com.android.settings.wifi.details.WifiNetworkDetailsFragment com.android.settings.wifi.p2p.WifiP2pSettings com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionCamera @@ -15,4 +19,4 @@ com.android.settings.enterprise.ApplicationListFragment$AdminGrantedPermissionMi com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages com.android.settings.enterprise.EnterpriseSetDefaultAppsListFragment com.android.settings.wifi.tether.WifiTetherSettings -com.android.settings.wifi.SavedAccessPointsWifiSettings +com.android.settings.wifi.SavedAccessPointsWifiSettings \ No newline at end of file diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable index 7c82e78d162..c2a084c5360 100644 --- a/tests/robotests/assets/grandfather_not_implementing_indexable +++ b/tests/robotests/assets/grandfather_not_implementing_indexable @@ -79,4 +79,4 @@ com.android.settings.IccLockSettings com.android.settings.TetherSettings com.android.settings.ApnEditor com.android.settings.UserCredentialsSettings -com.android.settings.TestingSettings +com.android.settings.TestingSettings \ No newline at end of file From d7f6f40d92ca94a7bbfab7e2b732d88ab1fd7dd8 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Mon, 13 Nov 2017 18:30:11 +0000 Subject: [PATCH 03/21] Revert "Expand all preferences when launch from search." This reverts commit 6589a07d5915d8bcc911ddf36054549a7cc1a219. Bug: 68988454 Fixes: 69242304 Change-Id: Iec29dbe302064a6209fbb0a8e7901c9a0f8744c0 (cherry picked from commit 9ce35ad0231d27292e6df5ebbd078947626dd3df) --- .../settings/SettingsPreferenceFragment.java | 16 ++++--------- .../SettingsPreferenceFragmentTest.java | 24 ++++--------------- 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java index f265f9892f8..a3d26af8eb7 100644 --- a/src/com/android/settings/SettingsPreferenceFragment.java +++ b/src/com/android/settings/SettingsPreferenceFragment.java @@ -150,8 +150,8 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF } // Prepare help url and enable menu if necessary - final Bundle arguments = getArguments(); - final int helpResource; + Bundle arguments = getArguments(); + int helpResource; if (arguments != null && arguments.containsKey(HELP_URI_RESOURCE_KEY)) { helpResource = arguments.getInt(HELP_URI_RESOURCE_KEY); } else { @@ -160,14 +160,6 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF if (helpResource != 0) { mHelpUri = getResources().getString(helpResource); } - - // Check if we should keep the preferences expanded. - if (arguments != null) { - mPreferenceKey = arguments.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY); - if (!TextUtils.isEmpty(mPreferenceKey)) { - getPreferenceScreen().setInitialExpandedChildrenCount(Integer.MAX_VALUE); - } - } } @Override @@ -232,7 +224,9 @@ public abstract class SettingsPreferenceFragment extends InstrumentedPreferenceF public void onResume() { super.onResume(); - if (mPreferenceKey != null) { + final Bundle args = getArguments(); + if (args != null) { + mPreferenceKey = args.getString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY); highlightPreferenceIfNeeded(); } } diff --git a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java index aa92ebb4975..dc4166d7eb3 100644 --- a/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/SettingsPreferenceFragmentTest.java @@ -16,9 +16,9 @@ package com.android.settings; + import android.app.Activity; import android.content.Context; -import android.os.Bundle; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceCategory; import android.support.v7.preference.PreferenceManager; @@ -39,18 +39,18 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; 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 com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settings.testutils.shadow.SettingsShadowResources; @RunWith(SettingsRobolectricTestRunner.class) -@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class SettingsPreferenceFragmentTest { private static final int ITEM_COUNT = 5; + @Mock + private PreferenceManager mPreferenceManager; @Mock private Activity mActivity; @Mock @@ -142,21 +142,6 @@ public class SettingsPreferenceFragmentTest { assertThat(mEmptyView.getVisibility()).isEqualTo(View.GONE); } - @Test - @Config(shadows = SettingsShadowResources.SettingsShadowTheme.class) - public void onCreate_hasExtraFragmentKey_shouldExpandPreferences() { - doReturn(mContext.getTheme()).when(mActivity).getTheme(); - doReturn(mContext.getResources()).when(mFragment).getResources(); - doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen(); - final Bundle bundle = new Bundle(); - bundle.putString(SettingsActivity.EXTRA_FRAGMENT_ARG_KEY, "test_key"); - doReturn(bundle).when(mFragment).getArguments(); - - mFragment.onCreate(null /* icicle */); - - verify(mPreferenceScreen).setInitialExpandedChildrenCount(Integer.MAX_VALUE); - } - public static class TestFragment extends SettingsPreferenceFragment { @Override @@ -165,4 +150,5 @@ public class SettingsPreferenceFragmentTest { } } + } From 2e1009f4a3fae112de4be10f8d036e7a11026d97 Mon Sep 17 00:00:00 2001 From: Tony Mantler Date: Wed, 15 Nov 2017 11:19:40 -0800 Subject: [PATCH 04/21] Copy proguard rules needed for Lifecycle support Bug: 69350851 Test: Manual, sadly Change-Id: Ice2b2697ec269e3ed0d3ca81940948189357cefb (cherry picked from commit bd6fcdbd2b4c0f4eb87fa8d2072ff809d2fbb3b5) --- proguard.flags | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/proguard.flags b/proguard.flags index d644f47887c..7a403a4490c 100644 --- a/proguard.flags +++ b/proguard.flags @@ -39,3 +39,21 @@ public static ** SEARCH_INDEX_DATA_PROVIDER; public static ** SUMMARY_PROVIDER_FACTORY; } + +# Keep classes, annotations and members used by Lifecycle +-keepattributes *Annotation* + +-keepclassmembers enum android.arch.lifecycle.Lifecycle$Event { + ; +} + +-keep class * implements android.arch.lifecycle.LifecycleObserver { +} + +-keep class * implements android.arch.lifecycle.GeneratedAdapter { + (...); +} + +-keepclassmembers class ** { + @android.arch.lifecycle.OnLifecycleEvent *; +} From bbc79a2e1e723a6e78e9643e00b068ddf688a25c Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Mon, 11 Dec 2017 11:18:10 -0800 Subject: [PATCH 05/21] Update package name for PictureAndPictureSettings - the settings have been moved into the appinfo package, but the path has not been updated properly in the android manifest. Change-Id: I3a00a187bd2fdbeb926e2bb8cc1c4ab720ccd72a Fixes: 70491786 Test: manual (cherry picked from commit ebf884384073e96754d6bea5ee6e611f293a65f5) --- AndroidManifest.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 8eaf761d478..6ccb8d1b08d 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2573,7 +2573,7 @@ + android:value="com.android.settings.applications.appinfo.PictureInPictureSettings" /> + android:value="com.android.settings.applications.appinfo.PictureInPictureDetails" /> + android:value="com.android.settings.applications.appinfo.DrawOverlayDetails" /> + android:value="com.android.settings.applications.appinfo.WriteSettingsDetails" /> + android:value="com.android.settings.applications.appinfo.ExternalSourcesDetails" /> Date: Mon, 11 Dec 2017 13:45:40 -0800 Subject: [PATCH 06/21] Update package name for PictureAndPictureSettings - also need to update the reference in the special app access xml page. Change-Id: I1199f70adf18d3f0e21a946848239526d9c8b3c8 Fixes: 70491786 Test: make SettingsUnitTests (cherry picked from commit a8472007a7d195410c030146361122de63a07e6a) --- res/xml/special_access.xml | 2 +- .../SpecialAppAccessSettingsTest.java | 89 +++++++++++++++++++ 2 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 tests/unit/src/com/android/settings/applications/SpecialAppAccessSettingsTest.java diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml index 6adfc933fb4..829bc53c6c1 100644 --- a/res/xml/special_access.xml +++ b/res/xml/special_access.xml @@ -68,7 +68,7 @@ Date: Wed, 20 Dec 2017 16:38:45 -0800 Subject: [PATCH 07/21] Catch NullPointerException in PreIndexDataCollector. Null pointer exception is thrown from ContentProviderNative when we query the non indexable keys. Added a try-catch block to prevent it from crashing. Change-Id: I45c1e34bb81a4739ae2eb5dd19a08781ab7beeb1 Fix: 70900076 Test: manual (cherry picked from commit 559ac8a72a6ee6265199d90baa2f99b308cd0844) --- .../settings/search/indexing/PreIndexDataCollector.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/search/indexing/PreIndexDataCollector.java b/src/com/android/settings/search/indexing/PreIndexDataCollector.java index a4e11317f23..63000b48744 100644 --- a/src/com/android/settings/search/indexing/PreIndexDataCollector.java +++ b/src/com/android/settings/search/indexing/PreIndexDataCollector.java @@ -287,8 +287,14 @@ public class PreIndexDataCollector { String[] projection) { final ContentResolver resolver = packageContext.getContentResolver(); - final Cursor cursor = resolver.query(uri, projection, null, null, null); final List result = new ArrayList<>(); + Cursor cursor; + try { + cursor = resolver.query(uri, projection, null, null, null); + } catch (NullPointerException e) { + Log.e(TAG, "Exception querying the keys!", e); + return result; + } if (cursor == null) { Log.w(TAG, "Cannot add index data for Uri: " + uri.toString()); From 59c2323bb7300845c695a4d1c1629c4c864ad4de Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Thu, 4 Jan 2018 13:05:46 -0800 Subject: [PATCH 08/21] Disable animation when adjusting font size. - The fade-in and fade-out animation for transitioning between different frames in the text preview is very janky. Disable the animation to get a smoother transition while dragging along the seek bar. Change-Id: I201faf8229961ea5fa5fe42efd312290a4af0f30 Fixes: 71569578 Test: visual (cherry picked from commit 121b3579afc02f54862c2feb99a01c88343bde53) --- src/com/android/settings/PreviewSeekBarPreferenceFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/android/settings/PreviewSeekBarPreferenceFragment.java b/src/com/android/settings/PreviewSeekBarPreferenceFragment.java index f5f3017af79..026032d26c6 100644 --- a/src/com/android/settings/PreviewSeekBarPreferenceFragment.java +++ b/src/com/android/settings/PreviewSeekBarPreferenceFragment.java @@ -67,7 +67,7 @@ public abstract class PreviewSeekBarPreferenceFragment extends SettingsPreferenc @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - setPreviewLayer(progress, true); + setPreviewLayer(progress, false); if (!mSeekByTouch) { commit(); } From df27c89f7e82c7c5fa6854185c86e4db9a66f6d7 Mon Sep 17 00:00:00 2001 From: Leif Wilden Date: Mon, 22 Jan 2018 20:22:02 +0000 Subject: [PATCH 09/21] Revert "Migrate to use instrumentation classes from settingslib." This reverts commit 1546cca529bf56430332e15b05ceb6efb37e57bf. Reason for revert: Broke fingerprint setup flow. b/72267201 Change-Id: I8321265ae64732c526325882ddea51080decddf5 (cherry picked from commit cab0ee611d375d70a3803d857e62c745ccd98de2) --- .../android/settings/AirplaneModeEnabler.java | 2 +- .../android/settings/DeviceAdminSettings.java | 16 +- .../android/settings/SettingsActivity.java | 12 +- .../settings/SettingsPreferenceFragment.java | 2 +- src/com/android/settings/Utils.java | 3 +- .../accounts/AccountPreferenceController.java | 2 +- .../applications/UsageAccessDetails.java | 2 +- .../bluetooth/BluetoothDevicePreference.java | 2 +- ...toothDeviceRenamePreferenceController.java | 2 +- .../settings/bluetooth/BluetoothEnabler.java | 2 +- .../BluetoothFilesPreferenceController.java | 2 +- .../settings/core/InstrumentedActivity.java | 8 +- .../settings/core/InstrumentedFragment.java | 22 +- .../core/InstrumentedPreferenceFragment.java | 22 +- .../core/instrumentation/EventLogWriter.java | 110 ++++++++ .../core/instrumentation/Instrumentable.java | 28 ++ .../InstrumentedDialogFragment.java | 11 +- .../core/instrumentation/LogWriter.java | 84 ++++++ .../MetricsFeatureProvider.java | 159 +++++++++++ .../SharedPreferencesLogger.java | 259 ++++++++++++++++++ .../VisibilityLoggerMixin.java | 100 +++++++ .../settings/dashboard/DashboardAdapter.java | 2 +- .../dashboard/DashboardAdapterV2.java | 2 +- .../DashboardFeatureProviderImpl.java | 8 +- .../dashboard/conditional/Condition.java | 2 +- .../conditional/ConditionAdapter.java | 2 +- .../conditional/ConditionAdapterV2.java | 2 +- .../suggestions/SuggestionAdapter.java | 2 +- .../suggestions/SuggestionAdapterV2.java | 2 +- .../SuggestionFeatureProviderImpl.java | 2 +- .../settings/datausage/DataSaverBackend.java | 2 +- .../android/settings/datetime/ZonePicker.java | 21 +- ...aticStorageManagerSwitchBarController.java | 4 +- .../BuildNumberPreferenceController.java | 2 +- ...eManagementSwitchPreferenceController.java | 2 +- .../StorageItemPreferenceController.java | 2 +- ...playNotificationsPreferenceController.java | 2 +- .../display/AmbientDisplaySettings.java | 2 +- .../AutoRotatePreferenceController.java | 2 +- .../display/ThemePreferenceController.java | 2 +- .../AppButtonsPreferenceController.java | 2 +- .../BatteryAppListPreferenceController.java | 2 +- .../settings/fuelgauge/PowerUsageSummary.java | 2 +- .../fuelgauge/PowerUsageSummaryLegacy.java | 2 +- .../fuelgauge/anomaly/AnomalyUtils.java | 2 +- .../anomaly/action/AnomalyAction.java | 2 +- .../batterytip/actions/BatteryTipAction.java | 2 +- .../actions/SmartBatteryAction.java | 2 +- .../inputmethod/UserDictionarySettings.java | 17 +- .../AirplaneModePreferenceController.java | 2 +- .../network/NetworkDashboardFragment.java | 2 +- .../AbstractZenModePreferenceController.java | 2 +- .../notification/ZenRulePreference.java | 4 +- .../settings/overlay/FeatureFactory.java | 2 +- .../settings/overlay/FeatureFactoryImpl.java | 2 +- .../android/settings/widget/SwitchBar.java | 2 +- .../android/settings/wifi/WifiEnabler.java | 2 +- .../WifiMasterSwitchPreferenceController.java | 2 +- .../WifiDetailPreferenceController.java | 2 +- .../settings/SettingsDialogFragmentTest.java | 7 +- .../InstantAppButtonsControllerTest.java | 2 +- .../BluetoothDevicePreferenceTest.java | 2 +- .../bluetooth/BluetoothEnablerTest.java | 2 +- .../android/settings/bluetooth/UtilsTest.java | 2 +- .../InstrumentableFragmentCodeInspector.java | 1 - .../InstrumentedDialogFragmentTest.java | 1 - .../MetricsFeatureProviderTest.java | 66 ++++- .../SharedPreferenceLoggerTest.java | 185 +++++++++++++ .../VisibilityLoggerMixinTest.java | 123 +++++++++ .../DashboardFeatureProviderImplTest.java | 3 +- .../dashboard/DashboardFragmentTest.java | 2 +- .../dashboard/conditional/ConditionTest.java | 2 +- .../settings/datausage/DataUsageListTest.java | 1 - .../settings/datetime/ZonePickerTest.java | 2 +- ...StorageManagerSwitchBarControllerTest.java | 2 +- ...agementSwitchPreferenceControllerTest.java | 2 +- .../StorageItemPreferenceControllerTest.java | 2 +- ...eSummaryDonutPreferenceControllerTest.java | 2 +- ...NotificationsPreferenceControllerTest.java | 2 +- .../FingerprintEnrollEnrollingTest.java | 4 - .../FingerprintEnrollFindSensorTest.java | 4 - .../FingerprintSuggestionActivityTest.java | 4 - .../SetupFingerprintEnrollFindSensorTest.java | 4 - ...etupFingerprintEnrollIntroductionTest.java | 4 - .../fuelgauge/anomaly/AnomalyUtilsTest.java | 2 +- .../localepicker/LocaleListEditorTest.java | 10 - .../testutils/FakeFeatureFactory.java | 2 +- .../shadow/ShadowEventLogWriter.java | 2 +- .../webview/WebViewAppPickerTest.java | 2 +- .../settings/wifi/WifiEnablerTest.java | 2 +- ...iMasterSwitchPreferenceControllerTest.java | 2 +- .../WifiDetailPreferenceControllerTest.java | 2 +- 92 files changed, 1249 insertions(+), 176 deletions(-) create mode 100644 src/com/android/settings/core/instrumentation/EventLogWriter.java create mode 100644 src/com/android/settings/core/instrumentation/Instrumentable.java create mode 100644 src/com/android/settings/core/instrumentation/LogWriter.java create mode 100644 src/com/android/settings/core/instrumentation/MetricsFeatureProvider.java create mode 100644 src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java create mode 100644 src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java create mode 100644 tests/robotests/src/com/android/settings/core/instrumentation/SharedPreferenceLoggerTest.java create mode 100644 tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java diff --git a/src/com/android/settings/AirplaneModeEnabler.java b/src/com/android/settings/AirplaneModeEnabler.java index 5f93589c92d..4fc205d263d 100644 --- a/src/com/android/settings/AirplaneModeEnabler.java +++ b/src/com/android/settings/AirplaneModeEnabler.java @@ -30,8 +30,8 @@ import android.support.v7.preference.Preference; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.telephony.PhoneStateIntentReceiver; import com.android.internal.telephony.TelephonyProperties; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.WirelessUtils; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class AirplaneModeEnabler implements Preference.OnPreferenceChangeListener { diff --git a/src/com/android/settings/DeviceAdminSettings.java b/src/com/android/settings/DeviceAdminSettings.java index bb53018dfd6..9391439267d 100644 --- a/src/com/android/settings/DeviceAdminSettings.java +++ b/src/com/android/settings/DeviceAdminSettings.java @@ -49,9 +49,8 @@ import android.widget.Switch; import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.Instrumentable; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; +import com.android.settings.core.instrumentation.Instrumentable; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import org.xmlpull.v1.XmlPullParserException; @@ -64,7 +63,8 @@ import java.util.List; public class DeviceAdminSettings extends ListFragment implements Instrumentable { static final String TAG = "DeviceAdminSettings"; - private VisibilityLoggerMixin mVisibilityLoggerMixin; + private final VisibilityLoggerMixin mVisibilityLoggerMixin = + new VisibilityLoggerMixin(getMetricsCategory()); private DevicePolicyManager mDPM; private UserManager mUm; @@ -85,6 +85,12 @@ public class DeviceAdminSettings extends ListFragment implements Instrumentable } } + @Override + public void onAttach(Context context) { + super.onAttach(context); + mVisibilityLoggerMixin.onAttach(context); + } + /** * Internal collection of device admin info objects for all profiles associated with the current * user. @@ -115,8 +121,6 @@ public class DeviceAdminSettings extends ListFragment implements Instrumentable @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); - mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(), - FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()); } @Override diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 5cb7c06c21a..d3580d18b86 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -56,13 +56,13 @@ import com.android.settings.Settings.WifiSettingsActivity; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.backup.BackupSettingsActivity; import com.android.settings.core.gateway.SettingsGateway; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.core.instrumentation.SharedPreferencesLogger; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardSummary; import com.android.settings.overlay.FeatureFactory; import com.android.settings.wfd.WifiDisplaySettings; import com.android.settings.widget.SwitchBar; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.core.instrumentation.SharedPreferencesLogger; import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.SettingsDrawerActivity; @@ -92,6 +92,11 @@ public class SettingsActivity extends SettingsDrawerActivity */ public static final String EXTRA_SHOW_FRAGMENT = ":settings:show_fragment"; + /** + * The metrics category constant for logging source when a setting fragment is opened. + */ + public static final String EXTRA_SOURCE_METRICS_CATEGORY = ":settings:source_metrics"; + /** * When starting this activity and using {@link #EXTRA_SHOW_FRAGMENT}, * this extra can also be specified to supply a Bundle of arguments to pass @@ -215,8 +220,7 @@ public class SettingsActivity extends SettingsDrawerActivity @Override public SharedPreferences getSharedPreferences(String name, int mode) { if (name.equals(getPackageName() + "_preferences")) { - return new SharedPreferencesLogger(this, getMetricsTag(), - FeatureFactory.getFactory(this).getMetricsFeatureProvider()); + return new SharedPreferencesLogger(this, getMetricsTag()); } return super.getSharedPreferences(name, mode); } diff --git a/src/com/android/settings/SettingsPreferenceFragment.java b/src/com/android/settings/SettingsPreferenceFragment.java index c5d477aad0b..d9e264bf33d 100644 --- a/src/com/android/settings/SettingsPreferenceFragment.java +++ b/src/com/android/settings/SettingsPreferenceFragment.java @@ -45,6 +45,7 @@ import android.widget.Button; import com.android.settings.applications.LayoutPreference; import com.android.settings.core.InstrumentedPreferenceFragment; +import com.android.settings.core.instrumentation.Instrumentable; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.search.actionbar.SearchMenuController; import com.android.settings.support.actionbar.HelpMenuController; @@ -52,7 +53,6 @@ import com.android.settings.support.actionbar.HelpResourceProvider; import com.android.settings.widget.LoadingViewController; import com.android.settingslib.CustomDialogPreference; import com.android.settingslib.CustomEditTextPreference; -import com.android.settingslib.core.instrumentation.Instrumentable; import com.android.settingslib.widget.FooterPreferenceMixin; import java.util.UUID; diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 1c674b68f15..ad951216781 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -110,7 +110,6 @@ import com.android.internal.widget.LockPatternUtils; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.wrapper.DevicePolicyManagerWrapper; import com.android.settings.wrapper.FingerprintManagerWrapper; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import java.net.InetAddress; import java.util.ArrayList; @@ -577,7 +576,7 @@ public final class Utils extends com.android.settingslib.Utils { intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, titleResId); intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title); intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut); - intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory); + intent.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory); return intent; } diff --git a/src/com/android/settings/accounts/AccountPreferenceController.java b/src/com/android/settings/accounts/AccountPreferenceController.java index 6127ab9bccc..c0bf7d21ef9 100644 --- a/src/com/android/settings/accounts/AccountPreferenceController.java +++ b/src/com/android/settings/accounts/AccountPreferenceController.java @@ -51,12 +51,12 @@ import com.android.settings.SettingsActivity; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.RestrictedPreference; import com.android.settingslib.accounts.AuthenticatorHelper; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; diff --git a/src/com/android/settings/applications/UsageAccessDetails.java b/src/com/android/settings/applications/UsageAccessDetails.java index c172137664b..c10fb55c9ec 100644 --- a/src/com/android/settings/applications/UsageAccessDetails.java +++ b/src/com/android/settings/applications/UsageAccessDetails.java @@ -37,8 +37,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.applications.AppStateUsageBridge.UsageState; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class UsageAccessDetails extends AppInfoWithHeader implements OnPreferenceChangeListener, OnPreferenceClickListener { diff --git a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java index 3fd7ced3e03..a0ce73386a5 100644 --- a/src/com/android/settings/bluetooth/BluetoothDevicePreference.java +++ b/src/com/android/settings/bluetooth/BluetoothDevicePreference.java @@ -33,10 +33,10 @@ import android.widget.ImageView; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.GearPreference; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import static android.os.UserManager.DISALLOW_CONFIG_BLUETOOTH; diff --git a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java index cea0147cecf..a12d1a8ecb2 100644 --- a/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java +++ b/src/com/android/settings/bluetooth/BluetoothDeviceRenamePreferenceController.java @@ -23,9 +23,9 @@ import android.support.v7.preference.Preference; import android.text.TextUtils; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.bluetooth.LocalBluetoothAdapter; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; public class BluetoothDeviceRenamePreferenceController extends diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java index 0f294bd5748..87fa43d2db2 100644 --- a/src/com/android/settings/bluetooth/BluetoothEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java @@ -27,12 +27,12 @@ import android.widget.Toast; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.widget.SwitchWidgetController; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.WirelessUtils; import com.android.settingslib.bluetooth.LocalBluetoothAdapter; import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; /** * BluetoothEnabler is a helper to manage the Bluetooth on/off checkbox diff --git a/src/com/android/settings/bluetooth/BluetoothFilesPreferenceController.java b/src/com/android/settings/bluetooth/BluetoothFilesPreferenceController.java index 1ecfed42515..450c7b2320a 100644 --- a/src/com/android/settings/bluetooth/BluetoothFilesPreferenceController.java +++ b/src/com/android/settings/bluetooth/BluetoothFilesPreferenceController.java @@ -23,9 +23,9 @@ import android.support.v7.preference.Preference; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; /** * Controller that shows received files diff --git a/src/com/android/settings/core/InstrumentedActivity.java b/src/com/android/settings/core/InstrumentedActivity.java index 294de2cb957..9b24756b19e 100644 --- a/src/com/android/settings/core/InstrumentedActivity.java +++ b/src/com/android/settings/core/InstrumentedActivity.java @@ -16,9 +16,8 @@ package com.android.settings.core; -import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.Instrumentable; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; +import com.android.settings.core.instrumentation.Instrumentable; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.core.lifecycle.ObservableActivity; /** @@ -28,8 +27,7 @@ public abstract class InstrumentedActivity extends ObservableActivity implements public InstrumentedActivity() { // Mixin that logs visibility change for activity. - getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory(), - FeatureFactory.getFactory(this).getMetricsFeatureProvider())); + getLifecycle().addObserver(new VisibilityLoggerMixin(getMetricsCategory())); } } diff --git a/src/com/android/settings/core/InstrumentedFragment.java b/src/com/android/settings/core/InstrumentedFragment.java index b1215b9ac4a..45db836efcc 100644 --- a/src/com/android/settings/core/InstrumentedFragment.java +++ b/src/com/android/settings/core/InstrumentedFragment.java @@ -18,28 +18,30 @@ package com.android.settings.core; import android.content.Context; +import com.android.settings.core.instrumentation.Instrumentable; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settings.overlay.FeatureFactory; import com.android.settings.survey.SurveyMixin; -import com.android.settingslib.core.instrumentation.Instrumentable; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.core.lifecycle.ObservableFragment; public abstract class InstrumentedFragment extends ObservableFragment implements Instrumentable { protected MetricsFeatureProvider mMetricsFeatureProvider; - private VisibilityLoggerMixin mVisibilityLoggerMixin; + private final VisibilityLoggerMixin mVisibilityLoggerMixin; + + public InstrumentedFragment() { + // Mixin that logs visibility change for activity. + mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory()); + getLifecycle().addObserver(mVisibilityLoggerMixin); + getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName())); + } @Override public void onAttach(Context context) { - mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); - mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(), - mMetricsFeatureProvider); - // Mixin that logs visibility change for activity. - getLifecycle().addObserver(mVisibilityLoggerMixin); - getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName())); super.onAttach(context); + mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); } @Override diff --git a/src/com/android/settings/core/InstrumentedPreferenceFragment.java b/src/com/android/settings/core/InstrumentedPreferenceFragment.java index 278676c52ea..7e37115bab0 100644 --- a/src/com/android/settings/core/InstrumentedPreferenceFragment.java +++ b/src/com/android/settings/core/InstrumentedPreferenceFragment.java @@ -23,11 +23,11 @@ import android.support.v7.preference.PreferenceScreen; import android.text.TextUtils; import android.util.Log; +import com.android.settings.core.instrumentation.Instrumentable; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settings.overlay.FeatureFactory; import com.android.settings.survey.SurveyMixin; -import com.android.settingslib.core.instrumentation.Instrumentable; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.core.lifecycle.ObservablePreferenceFragment; /** @@ -44,17 +44,19 @@ public abstract class InstrumentedPreferenceFragment extends ObservablePreferenc // metrics placeholder value. Only use this for development. protected final int PLACEHOLDER_METRIC = 10000; - private VisibilityLoggerMixin mVisibilityLoggerMixin; + private final VisibilityLoggerMixin mVisibilityLoggerMixin; + + public InstrumentedPreferenceFragment() { + // Mixin that logs visibility change for activity. + mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory()); + getLifecycle().addObserver(mVisibilityLoggerMixin); + getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName())); + } @Override public void onAttach(Context context) { - mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); - // Mixin that logs visibility change for activity. - mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(), - mMetricsFeatureProvider); - getLifecycle().addObserver(mVisibilityLoggerMixin); - getLifecycle().addObserver(new SurveyMixin(this, getClass().getSimpleName())); super.onAttach(context); + mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); } @Override diff --git a/src/com/android/settings/core/instrumentation/EventLogWriter.java b/src/com/android/settings/core/instrumentation/EventLogWriter.java new file mode 100644 index 00000000000..3196f76b323 --- /dev/null +++ b/src/com/android/settings/core/instrumentation/EventLogWriter.java @@ -0,0 +1,110 @@ +/* + * 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.core.instrumentation; + +import android.content.Context; +import android.metrics.LogMaker; +import android.util.Log; +import android.util.Pair; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto; + +/** + * {@link LogWriter} that writes data to eventlog. + */ +public class EventLogWriter implements LogWriter { + + private final MetricsLogger mMetricsLogger = new MetricsLogger(); + + public void visible(Context context, int source, int category) { + final LogMaker logMaker = new LogMaker(category) + .setType(MetricsProto.MetricsEvent.TYPE_OPEN) + .addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source); + MetricsLogger.action(logMaker); + } + + public void hidden(Context context, int category) { + MetricsLogger.hidden(context, category); + } + + public void action(int category, int value, Pair... taggedData) { + if (taggedData == null || taggedData.length == 0) { + mMetricsLogger.action(category, value); + } else { + final LogMaker logMaker = new LogMaker(category) + .setType(MetricsProto.MetricsEvent.TYPE_ACTION) + .setSubtype(value); + for (Pair pair : taggedData) { + logMaker.addTaggedData(pair.first, pair.second); + } + mMetricsLogger.write(logMaker); + } + } + + public void action(int category, boolean value, Pair... taggedData) { + action(category, value ? 1 : 0, taggedData); + } + + public void action(Context context, int category, Pair... taggedData) { + action(context, category, "", taggedData); + } + + public void actionWithSource(Context context, int source, int category) { + final LogMaker logMaker = new LogMaker(category) + .setType(MetricsProto.MetricsEvent.TYPE_ACTION); + if (source != MetricsProto.MetricsEvent.VIEW_UNKNOWN) { + logMaker.addTaggedData(MetricsProto.MetricsEvent.FIELD_CONTEXT, source); + } + MetricsLogger.action(logMaker); + } + + /** @deprecated use {@link #action(int, int, Pair[])} */ + @Deprecated + public void action(Context context, int category, int value) { + MetricsLogger.action(context, category, value); + } + + /** @deprecated use {@link #action(int, boolean, Pair[])} */ + @Deprecated + public void action(Context context, int category, boolean value) { + MetricsLogger.action(context, category, value); + } + + public void action(Context context, int category, String pkg, + Pair... taggedData) { + if (taggedData == null || taggedData.length == 0) { + MetricsLogger.action(context, category, pkg); + } else { + final LogMaker logMaker = new LogMaker(category) + .setType(MetricsProto.MetricsEvent.TYPE_ACTION) + .setPackageName(pkg); + for (Pair pair : taggedData) { + logMaker.addTaggedData(pair.first, pair.second); + } + MetricsLogger.action(logMaker); + } + } + + public void count(Context context, String name, int value) { + MetricsLogger.count(context, name, value); + } + + public void histogram(Context context, String name, int bucket) { + MetricsLogger.histogram(context, name, bucket); + } +} diff --git a/src/com/android/settings/core/instrumentation/Instrumentable.java b/src/com/android/settings/core/instrumentation/Instrumentable.java new file mode 100644 index 00000000000..f58e140b62a --- /dev/null +++ b/src/com/android/settings/core/instrumentation/Instrumentable.java @@ -0,0 +1,28 @@ +/* + * 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.core.instrumentation; + +public interface Instrumentable { + + int METRICS_CATEGORY_UNKNOWN = 0; + + /** + * Instrumented name for a view as defined in + * {@link com.android.internal.logging.nano.MetricsProto.MetricsEvent}. + */ + int getMetricsCategory(); +} diff --git a/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java b/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java index 0a214f17315..5a9ab56ea99 100644 --- a/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java +++ b/src/com/android/settings/core/instrumentation/InstrumentedDialogFragment.java @@ -19,9 +19,6 @@ import android.content.Context; import com.android.settings.DialogCreatable; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.Instrumentable; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.core.lifecycle.ObservableDialogFragment; public abstract class InstrumentedDialogFragment extends ObservableDialogFragment @@ -41,15 +38,13 @@ public abstract class InstrumentedDialogFragment extends ObservableDialogFragmen public InstrumentedDialogFragment(DialogCreatable dialogCreatable, int dialogId) { mDialogCreatable = dialogCreatable; mDialogId = dialogId; + mLifecycle.addObserver(new VisibilityLoggerMixin(getMetricsCategory())); } + @Override public void onAttach(Context context) { super.onAttach(context); - mMetricsFeatureProvider = FeatureFactory.getFactory(context) - .getMetricsFeatureProvider(); - mLifecycle.addObserver(new VisibilityLoggerMixin(getMetricsCategory(), - mMetricsFeatureProvider)); - mLifecycle.onAttach(context); + mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); } } diff --git a/src/com/android/settings/core/instrumentation/LogWriter.java b/src/com/android/settings/core/instrumentation/LogWriter.java new file mode 100644 index 00000000000..062d46f759f --- /dev/null +++ b/src/com/android/settings/core/instrumentation/LogWriter.java @@ -0,0 +1,84 @@ +/* + * 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.core.instrumentation; + +import android.content.Context; +import android.util.Pair; + +/** + * Generic log writer interface. + */ +public interface LogWriter { + + /** + * Logs a visibility event when view becomes visible. + */ + void visible(Context context, int source, int category); + + /** + * Logs a visibility event when view becomes hidden. + */ + void hidden(Context context, int category); + + /** + * Logs a user action. + */ + void action(int category, int value, Pair... taggedData); + + /** + * Logs a user action. + */ + void action(int category, boolean value, Pair... taggedData); + + /** + * Logs an user action. + */ + void action(Context context, int category, Pair... taggedData); + + /** + * Logs an user action. + */ + void actionWithSource(Context context, int source, int category); + + /** + * Logs an user action. + * @deprecated use {@link #action(int, int, Pair[])} + */ + @Deprecated + void action(Context context, int category, int value); + + /** + * Logs an user action. + * @deprecated use {@link #action(int, boolean, Pair[])} + */ + @Deprecated + void action(Context context, int category, boolean value); + + /** + * Logs an user action. + */ + void action(Context context, int category, String pkg, Pair... taggedData); + + /** + * Logs a count. + */ + void count(Context context, String name, int value); + + /** + * Logs a histogram event. + */ + void histogram(Context context, String name, int bucket); +} diff --git a/src/com/android/settings/core/instrumentation/MetricsFeatureProvider.java b/src/com/android/settings/core/instrumentation/MetricsFeatureProvider.java new file mode 100644 index 00000000000..166cbb84471 --- /dev/null +++ b/src/com/android/settings/core/instrumentation/MetricsFeatureProvider.java @@ -0,0 +1,159 @@ +/* + * 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.core.instrumentation; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.text.TextUtils; +import android.util.Pair; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; + +import java.util.ArrayList; +import java.util.List; + +/** + * FeatureProvider for metrics. + */ +public class MetricsFeatureProvider { + private List mLoggerWriters; + + public MetricsFeatureProvider() { + mLoggerWriters = new ArrayList<>(); + installLogWriters(); + } + + protected void installLogWriters() { + mLoggerWriters.add(new EventLogWriter()); + } + + public void visible(Context context, int source, int category) { + for (LogWriter writer : mLoggerWriters) { + writer.visible(context, source, category); + } + } + + public void hidden(Context context, int category) { + for (LogWriter writer : mLoggerWriters) { + writer.hidden(context, category); + } + } + + public void actionWithSource(Context context, int source, int category) { + for (LogWriter writer : mLoggerWriters) { + writer.actionWithSource(context, source, category); + } + } + + /** + * Logs a user action. Includes the elapsed time since the containing + * fragment has been visible. + */ + public void action(VisibilityLoggerMixin visibilityLogger, int category, int value) { + for (LogWriter writer : mLoggerWriters) { + writer.action(category, value, + sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible())); + } + } + + /** + * Logs a user action. Includes the elapsed time since the containing + * fragment has been visible. + */ + public void action(VisibilityLoggerMixin visibilityLogger, int category, boolean value) { + for (LogWriter writer : mLoggerWriters) { + writer.action(category, value, + sinceVisibleTaggedData(visibilityLogger.elapsedTimeSinceVisible())); + } + } + + public void action(Context context, int category, Pair... taggedData) { + for (LogWriter writer : mLoggerWriters) { + writer.action(context, category, taggedData); + } + } + + /** @deprecated use {@link #action(VisibilityLoggerMixin, int, int)} */ + @Deprecated + public void action(Context context, int category, int value) { + for (LogWriter writer : mLoggerWriters) { + writer.action(context, category, value); + } + } + + /** @deprecated use {@link #action(VisibilityLoggerMixin, int, boolean)} */ + @Deprecated + public void action(Context context, int category, boolean value) { + for (LogWriter writer : mLoggerWriters) { + writer.action(context, category, value); + } + } + + public void action(Context context, int category, String pkg, + Pair... taggedData) { + for (LogWriter writer : mLoggerWriters) { + writer.action(context, category, pkg, taggedData); + } + } + + public void count(Context context, String name, int value) { + for (LogWriter writer : mLoggerWriters) { + writer.count(context, name, value); + } + } + + public void histogram(Context context, String name, int bucket) { + for (LogWriter writer : mLoggerWriters) { + writer.histogram(context, name, bucket); + } + } + + public int getMetricsCategory(Object object) { + if (object == null || !(object instanceof Instrumentable)) { + return MetricsEvent.VIEW_UNKNOWN; + } + return ((Instrumentable) object).getMetricsCategory(); + } + + public void logDashboardStartIntent(Context context, Intent intent, + int sourceMetricsCategory) { + if (intent == null) { + return; + } + final ComponentName cn = intent.getComponent(); + if (cn == null) { + final String action = intent.getAction(); + if (TextUtils.isEmpty(action)) { + // Not loggable + return; + } + action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, action, + Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory)); + return; + } else if (TextUtils.equals(cn.getPackageName(), context.getPackageName())) { + // Going to a Setting internal page, skip click logging in favor of page's own + // visibility logging. + return; + } + action(context, MetricsEvent.ACTION_SETTINGS_TILE_CLICK, cn.flattenToString(), + Pair.create(MetricsEvent.FIELD_CONTEXT, sourceMetricsCategory)); + } + + private Pair sinceVisibleTaggedData(long timestamp) { + return Pair.create(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS, timestamp); + } +} diff --git a/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java b/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java new file mode 100644 index 00000000000..dee40c043ce --- /dev/null +++ b/src/com/android/settings/core/instrumentation/SharedPreferencesLogger.java @@ -0,0 +1,259 @@ +/* + * 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.core.instrumentation; + +import android.annotation.Nullable; +import android.content.ComponentName; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.os.AsyncTask; +import android.support.annotation.VisibleForTesting; +import android.text.TextUtils; +import android.util.Log; +import android.util.Pair; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.overlay.FeatureFactory; + +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; + +public class SharedPreferencesLogger implements SharedPreferences { + + private static final String LOG_TAG = "SharedPreferencesLogger"; + + private final String mTag; + private final Context mContext; + private final MetricsFeatureProvider mMetricsFeature; + private final Set mPreferenceKeySet; + + public SharedPreferencesLogger(Context context, String tag) { + mContext = context; + mTag = tag; + mMetricsFeature = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + mPreferenceKeySet = new ConcurrentSkipListSet<>(); + } + + @Override + public Map getAll() { + return null; + } + + @Override + public String getString(String key, @Nullable String defValue) { + return defValue; + } + + @Override + public Set getStringSet(String key, @Nullable Set defValues) { + return defValues; + } + + @Override + public int getInt(String key, int defValue) { + return defValue; + } + + @Override + public long getLong(String key, long defValue) { + return defValue; + } + + @Override + public float getFloat(String key, float defValue) { + return defValue; + } + + @Override + public boolean getBoolean(String key, boolean defValue) { + return defValue; + } + + @Override + public boolean contains(String key) { + return false; + } + + @Override + public Editor edit() { + return new EditorLogger(); + } + + @Override + public void registerOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) { + } + + @Override + public void unregisterOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) { + } + + private void logValue(String key, Object value) { + logValue(key, value, false /* forceLog */); + } + + private void logValue(String key, Object value, boolean forceLog) { + final String prefKey = buildPrefKey(mTag, key); + if (!forceLog && !mPreferenceKeySet.contains(prefKey)) { + // Pref key doesn't exist in set, this is initial display so we skip metrics but + // keeps track of this key. + mPreferenceKeySet.add(prefKey); + return; + } + // TODO: Remove count logging to save some resource. + mMetricsFeature.count(mContext, buildCountName(prefKey, value), 1); + + final Pair valueData; + if (value instanceof Long) { + final Long longVal = (Long) value; + final int intVal; + if (longVal > Integer.MAX_VALUE) { + intVal = Integer.MAX_VALUE; + } else if (longVal < Integer.MIN_VALUE) { + intVal = Integer.MIN_VALUE; + } else { + intVal = longVal.intValue(); + } + valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, + intVal); + } else if (value instanceof Integer) { + valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, + value); + } else if (value instanceof Boolean) { + valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, + (Boolean) value ? 1 : 0); + } else if (value instanceof Float) { + valueData = Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE, + value); + } else if (value instanceof String) { + Log.d(LOG_TAG, "Tried to log string preference " + prefKey + " = " + value); + valueData = null; + } else { + Log.w(LOG_TAG, "Tried to log unloggable object" + value); + valueData = null; + } + if (valueData != null) { + // Pref key exists in set, log it's change in metrics. + mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE, + Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey), + valueData); + } + } + + @VisibleForTesting + void logPackageName(String key, String value) { + final String prefKey = mTag + "/" + key; + mMetricsFeature.action(mContext, MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE, value, + Pair.create(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, prefKey)); + } + + private void safeLogValue(String key, String value) { + new AsyncPackageCheck().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, key, value); + } + + public static String buildCountName(String prefKey, Object value) { + return prefKey + "|" + value; + } + + public static String buildPrefKey(String tag, String key) { + return tag + "/" + key; + } + + private class AsyncPackageCheck extends AsyncTask { + @Override + protected Void doInBackground(String... params) { + String key = params[0]; + String value = params[1]; + PackageManager pm = mContext.getPackageManager(); + try { + // Check if this might be a component. + ComponentName name = ComponentName.unflattenFromString(value); + if (value != null) { + value = name.getPackageName(); + } + } catch (Exception e) { + } + try { + pm.getPackageInfo(value, PackageManager.MATCH_ANY_USER); + logPackageName(key, value); + } catch (PackageManager.NameNotFoundException e) { + // Clearly not a package, and it's unlikely this preference is in prefSet, so + // lets force log it. + logValue(key, value, true /* forceLog */); + } + return null; + } + } + + public class EditorLogger implements Editor { + @Override + public Editor putString(String key, @Nullable String value) { + safeLogValue(key, value); + return this; + } + + @Override + public Editor putStringSet(String key, @Nullable Set values) { + safeLogValue(key, TextUtils.join(",", values)); + return this; + } + + @Override + public Editor putInt(String key, int value) { + logValue(key, value); + return this; + } + + @Override + public Editor putLong(String key, long value) { + logValue(key, value); + return this; + } + + @Override + public Editor putFloat(String key, float value) { + logValue(key, value); + return this; + } + + @Override + public Editor putBoolean(String key, boolean value) { + logValue(key, value); + return this; + } + + @Override + public Editor remove(String key) { + return this; + } + + @Override + public Editor clear() { + return this; + } + + @Override + public boolean commit() { + return true; + } + + @Override + public void apply() { + } + } +} diff --git a/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java b/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java new file mode 100644 index 00000000000..2fe2a3beb1d --- /dev/null +++ b/src/com/android/settings/core/instrumentation/VisibilityLoggerMixin.java @@ -0,0 +1,100 @@ +/* + * 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.core.instrumentation; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +import android.os.SystemClock; +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.SettingsActivity; +import com.android.settings.overlay.FeatureFactory; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnAttach; +import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.core.lifecycle.events.OnResume; + +import static com.android.settings.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN; + +/** + * Logs visibility change of a fragment. + */ +public class VisibilityLoggerMixin implements LifecycleObserver, OnResume, OnPause, OnAttach { + + private static final String TAG = "VisibilityLoggerMixin"; + + private final int mMetricsCategory; + + private MetricsFeatureProvider mMetricsFeature; + private int mSourceMetricsCategory = MetricsProto.MetricsEvent.VIEW_UNKNOWN; + private long mVisibleTimestamp; + + public VisibilityLoggerMixin(int metricsCategory) { + // MetricsFeature will be set during onAttach. + this(metricsCategory, null /* metricsFeature */); + } + + public VisibilityLoggerMixin(int metricsCategory, MetricsFeatureProvider metricsFeature) { + mMetricsCategory = metricsCategory; + mMetricsFeature = metricsFeature; + } + + @Override + public void onAttach(Context context) { + mMetricsFeature = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); + } + + @Override + public void onResume() { + mVisibleTimestamp = SystemClock.elapsedRealtime(); + if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) { + mMetricsFeature.visible(null /* context */, mSourceMetricsCategory, mMetricsCategory); + } + } + + @Override + public void onPause() { + mVisibleTimestamp = 0; + if (mMetricsFeature != null && mMetricsCategory != METRICS_CATEGORY_UNKNOWN) { + mMetricsFeature.hidden(null /* context */, mMetricsCategory); + } + } + + /** + * Sets source metrics category for this logger. Source is the caller that opened this UI. + */ + public void setSourceMetricsCategory(Activity activity) { + if (mSourceMetricsCategory != MetricsProto.MetricsEvent.VIEW_UNKNOWN || activity == null) { + return; + } + final Intent intent = activity.getIntent(); + if (intent == null) { + return; + } + mSourceMetricsCategory = intent.getIntExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, + MetricsProto.MetricsEvent.VIEW_UNKNOWN); + } + + /** Returns elapsed time since onResume() */ + public long elapsedTimeSinceVisible() { + if (mVisibleTimestamp == 0) { + return 0; + } + return SystemClock.elapsedRealtime() - mVisibleTimestamp; + } +} diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java index 2d35ea78d33..97eef1329d5 100644 --- a/src/com/android/settings/dashboard/DashboardAdapter.java +++ b/src/com/android/settings/dashboard/DashboardAdapter.java @@ -41,6 +41,7 @@ import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.R.id; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardData.SuggestionConditionHeaderData; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.dashboard.conditional.ConditionAdapter; @@ -49,7 +50,6 @@ import com.android.settings.dashboard.suggestions.SuggestionControllerMixin; import com.android.settings.dashboard.suggestions.SuggestionDismissController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.Utils; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; diff --git a/src/com/android/settings/dashboard/DashboardAdapterV2.java b/src/com/android/settings/dashboard/DashboardAdapterV2.java index ad93e4c6065..a422ae43328 100644 --- a/src/com/android/settings/dashboard/DashboardAdapterV2.java +++ b/src/com/android/settings/dashboard/DashboardAdapterV2.java @@ -39,13 +39,13 @@ import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.R.id; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardDataV2.ConditionHeaderData; import com.android.settings.dashboard.conditional.Condition; import com.android.settings.dashboard.conditional.ConditionAdapterV2; import com.android.settings.dashboard.suggestions.SuggestionAdapterV2; import com.android.settings.dashboard.suggestions.SuggestionControllerMixin; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState; diff --git a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java index a14d9e9a76d..a06fee9fbc1 100644 --- a/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/DashboardFeatureProviderImpl.java @@ -41,9 +41,8 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.core.FeatureFlags; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.drawer.CategoryManager; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.ProfileSelectDialog; @@ -160,8 +159,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { pref.setFragment(clsName); } else if (tile.intent != null) { final Intent intent = new Intent(tile.intent); - intent.putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, - sourceMetricsCategory); + intent.putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, sourceMetricsCategory); if (action != null) { intent.setAction(action); } @@ -210,7 +208,7 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { return; } final Intent intent = new Intent(tile.intent) - .putExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, + .putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, MetricsEvent.DASHBOARD_SUMMARY) .putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); diff --git a/src/com/android/settings/dashboard/conditional/Condition.java b/src/com/android/settings/dashboard/conditional/Condition.java index d66440e9e89..05783bde798 100644 --- a/src/com/android/settings/dashboard/conditional/Condition.java +++ b/src/com/android/settings/dashboard/conditional/Condition.java @@ -24,8 +24,8 @@ import android.os.PersistableBundle; import android.support.annotation.VisibleForTesting; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public abstract class Condition { diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapter.java b/src/com/android/settings/dashboard/conditional/ConditionAdapter.java index d84aa7c9eac..eb768e50d0e 100644 --- a/src/com/android/settings/dashboard/conditional/ConditionAdapter.java +++ b/src/com/android/settings/dashboard/conditional/ConditionAdapter.java @@ -27,13 +27,13 @@ import android.widget.Button; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardAdapter; import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder; import com.android.settings.dashboard.DashboardData; import com.android.settings.dashboard.DashboardData.HeaderMode; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.WirelessUtils; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import java.util.List; import java.util.Objects; diff --git a/src/com/android/settings/dashboard/conditional/ConditionAdapterV2.java b/src/com/android/settings/dashboard/conditional/ConditionAdapterV2.java index 8db57f79678..3f3e5c91daf 100644 --- a/src/com/android/settings/dashboard/conditional/ConditionAdapterV2.java +++ b/src/com/android/settings/dashboard/conditional/ConditionAdapterV2.java @@ -27,10 +27,10 @@ import android.widget.Button; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardAdapterV2.DashboardItemHolder; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.WirelessUtils; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import java.util.List; import java.util.Objects; diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java index 2b79a9babfe..fc1102901c0 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java @@ -27,10 +27,10 @@ import android.view.ViewGroup; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardAdapter.DashboardItemHolder; import com.android.settings.dashboard.DashboardAdapter.IconCache; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import java.util.List; import java.util.Objects; diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java b/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java index e04ae936418..afd0e08b64d 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionAdapterV2.java @@ -31,10 +31,10 @@ import android.widget.LinearLayout; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardAdapterV2.DashboardItemHolder; import com.android.settings.dashboard.DashboardAdapterV2.IconCache; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState; diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java index 8cd1675ac2b..fe19b958c2d 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java @@ -36,6 +36,7 @@ import com.android.settings.Settings.DoubleTapPowerSuggestionActivity; import com.android.settings.Settings.DoubleTwistSuggestionActivity; import com.android.settings.Settings.NightDisplaySuggestionActivity; import com.android.settings.Settings.SwipeToNotificationSuggestionActivity; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.fingerprint.FingerprintEnrollSuggestionActivity; import com.android.settings.fingerprint.FingerprintSuggestionActivity; import com.android.settings.gestures.DoubleTapPowerPreferenceController; @@ -48,7 +49,6 @@ import com.android.settings.password.ScreenLockSuggestionActivity; import com.android.settings.support.NewDeviceIntroSuggestionActivity; import com.android.settings.wallpaper.WallpaperSuggestionActivity; import com.android.settings.wifi.WifiCallingSuggestionActivity; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.drawer.Tile; import java.util.List; diff --git a/src/com/android/settings/datausage/DataSaverBackend.java b/src/com/android/settings/datausage/DataSaverBackend.java index b59da9d7ff8..ff568c7c117 100644 --- a/src/com/android/settings/datausage/DataSaverBackend.java +++ b/src/com/android/settings/datausage/DataSaverBackend.java @@ -25,8 +25,8 @@ import android.os.RemoteException; import android.util.SparseIntArray; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.utils.ThreadUtils; import java.util.ArrayList; diff --git a/src/com/android/settings/datetime/ZonePicker.java b/src/com/android/settings/datetime/ZonePicker.java index dc691275e31..57c340c6809 100644 --- a/src/com/android/settings/datetime/ZonePicker.java +++ b/src/com/android/settings/datetime/ZonePicker.java @@ -35,9 +35,8 @@ import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; -import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.Instrumentable; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; +import com.android.settings.core.instrumentation.Instrumentable; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.datetime.ZoneGetter; import java.text.Collator; @@ -58,7 +57,8 @@ public class ZonePicker extends ListFragment implements Instrumentable { private static final int MENU_TIMEZONE = Menu.FIRST+1; private static final int MENU_ALPHABETICAL = Menu.FIRST; - private VisibilityLoggerMixin mVisibilityLoggerMixin; + private final VisibilityLoggerMixin mVisibilityLoggerMixin = + new VisibilityLoggerMixin(getMetricsCategory()); private boolean mSortedByTimezone; @@ -144,6 +144,12 @@ public class ZonePicker extends ListFragment implements Instrumentable { return -1; } + @Override + public void onAttach(Context context) { + super.onAttach(context); + mVisibilityLoggerMixin.onAttach(context); + } + @Override public int getMetricsCategory() { return MetricsProto.MetricsEvent.ZONE_PICKER; @@ -163,13 +169,6 @@ public class ZonePicker extends ListFragment implements Instrumentable { activity.setTitle(R.string.date_time_set_timezone); } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(), - FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()); - } - @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { diff --git a/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarController.java b/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarController.java index a20afa1060a..8ab1a07fb13 100644 --- a/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarController.java +++ b/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarController.java @@ -23,10 +23,10 @@ import android.provider.Settings; import android.support.v7.preference.Preference; import android.widget.Switch; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.Preconditions; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.widget.SwitchBar; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; /** Handles the logic for flipping the storage management toggle on a {@link SwitchBar}. */ public class AutomaticStorageManagerSwitchBarController diff --git a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java index 0f3bfb8ec76..2641f5d941f 100644 --- a/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java +++ b/src/com/android/settings/deviceinfo/BuildNumberPreferenceController.java @@ -34,11 +34,11 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnResume; diff --git a/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceController.java b/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceController.java index 8ab21b36fdb..717d7650b75 100644 --- a/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceController.java @@ -25,12 +25,12 @@ import android.support.annotation.VisibleForTesting; import android.support.v7.preference.PreferenceScreen; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.deletionhelper.ActivationWarningFragment; import com.android.settings.widget.MasterSwitchController; import com.android.settings.widget.MasterSwitchPreference; import com.android.settings.widget.SwitchWidgetController; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnResume; diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index 36232985934..1149b99bce6 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -38,11 +38,11 @@ import com.android.settings.Settings; import com.android.settings.Utils; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.deviceinfo.PrivateVolumeSettings.SystemInfoFragment; import com.android.settings.deviceinfo.StorageItemPreference; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.deviceinfo.StorageMeasurement; import com.android.settingslib.deviceinfo.StorageVolumeProvider; diff --git a/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java b/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java index f3d17d58939..68a21cebf9c 100644 --- a/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java +++ b/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceController.java @@ -27,11 +27,11 @@ import android.support.v7.preference.Preference; import com.android.internal.hardware.AmbientDisplayConfiguration; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.search.DatabaseIndexingUtils; import com.android.settings.search.InlineSwitchPayload; import com.android.settings.search.ResultPayload; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class AmbientDisplayNotificationsPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, diff --git a/src/com/android/settings/display/AmbientDisplaySettings.java b/src/com/android/settings/display/AmbientDisplaySettings.java index 187325c0c7f..24aede05ef6 100644 --- a/src/com/android/settings/display/AmbientDisplaySettings.java +++ b/src/com/android/settings/display/AmbientDisplaySettings.java @@ -23,13 +23,13 @@ import android.provider.SearchIndexableResource; import com.android.internal.hardware.AmbientDisplayConfiguration; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.gestures.DoubleTapScreenPreferenceController; import com.android.settings.gestures.PickupGesturePreferenceController; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.ArrayList; diff --git a/src/com/android/settings/display/AutoRotatePreferenceController.java b/src/com/android/settings/display/AutoRotatePreferenceController.java index 2134b882638..c7f6af175a1 100644 --- a/src/com/android/settings/display/AutoRotatePreferenceController.java +++ b/src/com/android/settings/display/AutoRotatePreferenceController.java @@ -20,9 +20,9 @@ import android.support.v7.preference.TwoStatePreference; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.view.RotationPolicy; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; diff --git a/src/com/android/settings/display/ThemePreferenceController.java b/src/com/android/settings/display/ThemePreferenceController.java index 9c1314ebc5e..d1341dd7435 100644 --- a/src/com/android/settings/display/ThemePreferenceController.java +++ b/src/com/android/settings/display/ThemePreferenceController.java @@ -29,9 +29,9 @@ import android.text.TextUtils; import com.android.settings.R; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import libcore.util.Objects; diff --git a/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java b/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java index a52433b374c..c0347466812 100644 --- a/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java +++ b/src/com/android/settings/fuelgauge/AppButtonsPreferenceController.java @@ -48,6 +48,7 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.widget.ActionButtonPreference; import com.android.settings.wrapper.DevicePolicyManagerWrapper; @@ -55,7 +56,6 @@ import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnDestroy; diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java index 91f35e2533a..5d95dd2ec71 100644 --- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java @@ -49,10 +49,10 @@ import com.android.settings.SettingsActivity; import com.android.settings.core.FeatureFlags; import com.android.settings.core.PreferenceControllerMixin; import com.android.settings.Utils; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.fuelgauge.anomaly.Anomaly; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnDestroy; diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index e0954e57f25..ec54291e3ed 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -47,6 +47,7 @@ import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.LayoutPreference; import com.android.settings.applications.manageapplications.ManageApplications; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.display.AmbientDisplayPreferenceController; import com.android.settings.display.AutoBrightnessPreferenceController; @@ -60,7 +61,6 @@ import com.android.settings.fuelgauge.batterytip.tips.BatteryTip; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.ArrayList; diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacy.java b/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacy.java index 605591dda15..c50d5808629 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacy.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummaryLegacy.java @@ -54,6 +54,7 @@ import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.LayoutPreference; import com.android.settings.applications.manageapplications.ManageApplications; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.display.AmbientDisplayPreferenceController; import com.android.settings.display.AutoBrightnessPreferenceController; @@ -66,7 +67,6 @@ import com.android.settings.fuelgauge.anomaly.AnomalyLoader; import com.android.settings.fuelgauge.anomaly.AnomalySummaryPreferenceController; import com.android.settings.fuelgauge.anomaly.AnomalyUtils; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.AbstractPreferenceController; import java.util.ArrayList; diff --git a/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java b/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java index 3dde95eff5b..39d51dc08af 100644 --- a/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java +++ b/src/com/android/settings/fuelgauge/anomaly/AnomalyUtils.java @@ -24,6 +24,7 @@ import android.util.SparseIntArray; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.os.BatteryStatsHelper; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.fuelgauge.anomaly.action.AnomalyAction; import com.android.settings.fuelgauge.anomaly.action.ForceStopAction; import com.android.settings.fuelgauge.anomaly.action.LocationCheckAction; @@ -32,7 +33,6 @@ import com.android.settings.fuelgauge.anomaly.checker.AnomalyDetector; import com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector; import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector; import com.android.settings.fuelgauge.anomaly.checker.WakeupAlarmAnomalyDetector; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import java.util.ArrayList; import java.util.List; diff --git a/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java b/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java index d7de5a7ac2a..3ee89d1c4a2 100644 --- a/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java +++ b/src/com/android/settings/fuelgauge/anomaly/action/AnomalyAction.java @@ -20,9 +20,9 @@ import android.content.Context; import android.util.Pair; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.fuelgauge.anomaly.Anomaly; import com.android.settings.overlay.FeatureFactory; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; /** * Abstract class for anomaly action, which is triggered if we need to handle the anomaly diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryTipAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryTipAction.java index 1bf08b7b64d..9fa69fd02c0 100644 --- a/src/com/android/settings/fuelgauge/batterytip/actions/BatteryTipAction.java +++ b/src/com/android/settings/fuelgauge/batterytip/actions/BatteryTipAction.java @@ -18,7 +18,7 @@ package com.android.settings.fuelgauge.batterytip.actions; import android.content.Context; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; /** * Abstract class for battery tip action, which is triggered if we need to handle the battery tip diff --git a/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java b/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java index cbd15812e5a..a19471e6d7b 100644 --- a/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java +++ b/src/com/android/settings/fuelgauge/batterytip/actions/SmartBatteryAction.java @@ -22,8 +22,8 @@ import android.support.v14.preference.PreferenceFragment; import com.android.settings.R; import com.android.settings.SettingsActivity; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.fuelgauge.SmartBatterySettings; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; public class SmartBatteryAction extends BatteryTipAction { private SettingsActivity mSettingsActivity; diff --git a/src/com/android/settings/inputmethod/UserDictionarySettings.java b/src/com/android/settings/inputmethod/UserDictionarySettings.java index 3bbc581ac82..9680af10c60 100644 --- a/src/com/android/settings/inputmethod/UserDictionarySettings.java +++ b/src/com/android/settings/inputmethod/UserDictionarySettings.java @@ -42,11 +42,10 @@ import android.widget.SimpleCursorAdapter; import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto; -import com.android.settings.overlay.FeatureFactory; import com.android.settings.R; import com.android.settings.SettingsActivity; -import com.android.settingslib.core.instrumentation.Instrumentable; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; +import com.android.settings.core.instrumentation.Instrumentable; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; public class UserDictionarySettings extends ListFragment implements Instrumentable, LoaderManager.LoaderCallbacks { @@ -60,7 +59,8 @@ public class UserDictionarySettings extends ListFragment implements Instrumentab private static final int OPTIONS_MENU_ADD = Menu.FIRST; private static final int LOADER_ID = 1; - private VisibilityLoggerMixin mVisibilityLoggerMixin; + private final VisibilityLoggerMixin mVisibilityLoggerMixin = + new VisibilityLoggerMixin(getMetricsCategory()); private Cursor mCursor; private String mLocale; @@ -70,13 +70,16 @@ public class UserDictionarySettings extends ListFragment implements Instrumentab return MetricsProto.MetricsEvent.USER_DICTIONARY_SETTINGS; } + @Override + public void onAttach(Context context) { + super.onAttach(context); + mVisibilityLoggerMixin.onAttach(context); + } + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mVisibilityLoggerMixin = new VisibilityLoggerMixin(getMetricsCategory(), - FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider()); - final Intent intent = getActivity().getIntent(); final String localeFromIntent = null == intent ? null : intent.getStringExtra("locale"); diff --git a/src/com/android/settings/network/AirplaneModePreferenceController.java b/src/com/android/settings/network/AirplaneModePreferenceController.java index 0b771791be7..17cf211e9dd 100644 --- a/src/com/android/settings/network/AirplaneModePreferenceController.java +++ b/src/com/android/settings/network/AirplaneModePreferenceController.java @@ -28,10 +28,10 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.internal.telephony.TelephonyProperties; import com.android.settings.AirplaneModeEnabler; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settings.R; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java index 74c191006d4..4b1da310bdd 100644 --- a/src/com/android/settings/network/NetworkDashboardFragment.java +++ b/src/com/android/settings/network/NetworkDashboardFragment.java @@ -31,13 +31,13 @@ import android.view.MenuInflater; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.SummaryLoader; import com.android.settings.network.MobilePlanPreferenceController.MobilePlanPreferenceHost; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.wifi.WifiMasterSwitchPreferenceController; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.ArrayList; diff --git a/src/com/android/settings/notification/AbstractZenModePreferenceController.java b/src/com/android/settings/notification/AbstractZenModePreferenceController.java index 9180791fd55..81ceca19c77 100644 --- a/src/com/android/settings/notification/AbstractZenModePreferenceController.java +++ b/src/com/android/settings/notification/AbstractZenModePreferenceController.java @@ -34,9 +34,9 @@ import android.support.v7.preference.PreferenceScreen; import com.android.internal.annotations.VisibleForTesting; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; diff --git a/src/com/android/settings/notification/ZenRulePreference.java b/src/com/android/settings/notification/ZenRulePreference.java index fee390f5edf..71938732a2b 100644 --- a/src/com/android/settings/notification/ZenRulePreference.java +++ b/src/com/android/settings/notification/ZenRulePreference.java @@ -30,10 +30,10 @@ import android.view.View; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.utils.ManagedServiceSettings; import com.android.settings.utils.ZenServiceListing; import com.android.settingslib.TwoTargetPreference; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import java.util.Map; @@ -145,4 +145,4 @@ public class ZenRulePreference extends TwoTargetPreference { ? mContext.getResources().getString(R.string.switch_off_text) : mContext.getResources().getString(R.string.switch_on_text); } -} +} \ No newline at end of file diff --git a/src/com/android/settings/overlay/FeatureFactory.java b/src/com/android/settings/overlay/FeatureFactory.java index 08057664c1c..dc9df8399f9 100644 --- a/src/com/android/settings/overlay/FeatureFactory.java +++ b/src/com/android/settings/overlay/FeatureFactory.java @@ -24,6 +24,7 @@ import com.android.settings.R; import com.android.settings.applications.ApplicationFeatureProvider; import com.android.settings.bluetooth.BluetoothFeatureProvider; import com.android.settings.connecteddevice.SmsMirroringFeatureProvider; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; import com.android.settings.datausage.DataPlanFeatureProvider; @@ -35,7 +36,6 @@ import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.search.SearchFeatureProvider; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.users.UserFeatureProvider; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; /** * Abstract class for creating feature controllers. Allows OEM implementations to define their own diff --git a/src/com/android/settings/overlay/FeatureFactoryImpl.java b/src/com/android/settings/overlay/FeatureFactoryImpl.java index f817d4bb218..275ebb66865 100644 --- a/src/com/android/settings/overlay/FeatureFactoryImpl.java +++ b/src/com/android/settings/overlay/FeatureFactoryImpl.java @@ -29,6 +29,7 @@ import com.android.settings.bluetooth.BluetoothFeatureProvider; import com.android.settings.bluetooth.BluetoothFeatureProviderImpl; import com.android.settings.connecteddevice.SmsMirroringFeatureProvider; import com.android.settings.connecteddevice.SmsMirroringFeatureProviderImpl; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProviderImpl; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; @@ -54,7 +55,6 @@ import com.android.settings.users.UserFeatureProviderImpl; import com.android.settings.wrapper.ConnectivityManagerWrapper; import com.android.settings.wrapper.DevicePolicyManagerWrapper; import com.android.settings.wrapper.IPackageManagerWrapper; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.wrapper.PackageManagerWrapper; /** diff --git a/src/com/android/settings/widget/SwitchBar.java b/src/com/android/settings/widget/SwitchBar.java index 3be5eca3c2e..749ec0a919b 100644 --- a/src/com/android/settings/widget/SwitchBar.java +++ b/src/com/android/settings/widget/SwitchBar.java @@ -39,9 +39,9 @@ import android.widget.Switch; import android.widget.TextView; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.RestrictedLockUtils; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import java.util.ArrayList; import java.util.List; diff --git a/src/com/android/settings/wifi/WifiEnabler.java b/src/com/android/settings/wifi/WifiEnabler.java index c5e79b2db49..9c431422371 100644 --- a/src/com/android/settings/wifi/WifiEnabler.java +++ b/src/com/android/settings/wifi/WifiEnabler.java @@ -33,9 +33,9 @@ import android.widget.Toast; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.widget.SwitchWidgetController; import com.android.settings.wrapper.ConnectivityManagerWrapper; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.WirelessUtils; diff --git a/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java b/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java index 8843d93775a..de1b030f3dc 100644 --- a/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java +++ b/src/com/android/settings/wifi/WifiMasterSwitchPreferenceController.java @@ -19,12 +19,12 @@ import android.content.Context; import android.support.v7.preference.PreferenceScreen; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.R; import com.android.settings.widget.SummaryUpdater; import com.android.settings.widget.MasterSwitchPreference; import com.android.settings.widget.MasterSwitchController; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java index 13ffd5bee44..70ee20de03d 100644 --- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java +++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java @@ -54,6 +54,7 @@ import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.applications.LayoutPreference; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.widget.ActionButtonPreference; import com.android.settings.widget.EntityHeaderController; import com.android.settings.wifi.WifiDetailPreference; @@ -62,7 +63,6 @@ import com.android.settings.wifi.WifiDialog.WifiDialogListener; import com.android.settings.wifi.WifiUtils; import com.android.settings.wrapper.ConnectivityManagerWrapper; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; diff --git a/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java b/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java index 3a7d094747f..942634a0a71 100644 --- a/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/SettingsDialogFragmentTest.java @@ -17,7 +17,6 @@ package com.android.settings; import android.app.Dialog; import android.app.Fragment; -import android.content.Context; import org.junit.Before; import org.junit.Test; @@ -39,8 +38,6 @@ public class SettingsDialogFragmentTest { private static final int DIALOG_ID = 15; - @Mock - private Context mContext; @Mock private DialogCreatableFragment mDialogCreatable; private SettingsPreferenceFragment.SettingsDialogFragment mDialogFragment; @@ -56,10 +53,9 @@ public class SettingsDialogFragmentTest { mDialogFragment = new SettingsPreferenceFragment.SettingsDialogFragment(mDialogCreatable, DIALOG_ID); - mDialogFragment.onAttach(mContext); mDialogFragment.getMetricsCategory(); - // getDialogMetricsCategory called in onAttach, and explicitly in test. + // getDialogMetricsCategory called in constructor, and explicitly in test. verify(mDialogCreatable, times(2)).getDialogMetricsCategory(DIALOG_ID); } @@ -70,7 +66,6 @@ public class SettingsDialogFragmentTest { try { mDialogFragment = new SettingsPreferenceFragment.SettingsDialogFragment( mDialogCreatable, DIALOG_ID); - mDialogFragment.onAttach(mContext); } catch (IllegalStateException e) { // getDialogMetricsCategory called in constructor verify(mDialogCreatable).getDialogMetricsCategory(DIALOG_ID); diff --git a/tests/robotests/src/com/android/settings/applications/instantapps/InstantAppButtonsControllerTest.java b/tests/robotests/src/com/android/settings/applications/instantapps/InstantAppButtonsControllerTest.java index f85d43aac6a..5c0badcc475 100644 --- a/tests/robotests/src/com/android/settings/applications/instantapps/InstantAppButtonsControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/instantapps/InstantAppButtonsControllerTest.java @@ -42,9 +42,9 @@ import android.widget.Button; import com.android.settings.R; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.wrapper.PackageManagerWrapper; import org.junit.Before; diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java index 71020be315a..e9d37f6a0c2 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothDevicePreferenceTest.java @@ -32,11 +32,11 @@ import android.os.UserManager; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settingslib.bluetooth.CachedBluetoothDevice; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java index 828b5a17335..b973edb674d 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothEnablerTest.java @@ -29,13 +29,13 @@ import android.widget.Switch; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.widget.MasterSwitchController; import com.android.settings.widget.MasterSwitchPreference; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.bluetooth.LocalBluetoothAdapter; import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.BeforeClass; diff --git a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java index c3b22b3a98c..8666ce3c13c 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/UtilsTest.java @@ -26,11 +26,11 @@ import android.content.Context; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settingslib.bluetooth.LocalBluetoothManager; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentableFragmentCodeInspector.java b/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentableFragmentCodeInspector.java index 867b5df7336..4455549db12 100644 --- a/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentableFragmentCodeInspector.java +++ b/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentableFragmentCodeInspector.java @@ -20,7 +20,6 @@ import android.app.Fragment; import android.util.ArraySet; import com.android.settings.core.codeinspection.CodeInspector; -import com.android.settingslib.core.instrumentation.Instrumentable; import java.util.ArrayList; import java.util.List; diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentedDialogFragmentTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentedDialogFragmentTest.java index 8ad2d696846..9e37896fa62 100644 --- a/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentedDialogFragmentTest.java +++ b/tests/robotests/src/com/android/settings/core/instrumentation/InstrumentedDialogFragmentTest.java @@ -21,7 +21,6 @@ import android.os.Bundle; import com.android.settings.TestConfig; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/MetricsFeatureProviderTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/MetricsFeatureProviderTest.java index 2950c072ad6..da48f15c4c4 100644 --- a/tests/robotests/src/com/android/settings/core/instrumentation/MetricsFeatureProviderTest.java +++ b/tests/robotests/src/com/android/settings/core/instrumentation/MetricsFeatureProviderTest.java @@ -31,9 +31,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.TestConfig; import com.android.settings.overlay.FeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settingslib.core.instrumentation.LogWriter; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import org.junit.Before; import org.junit.Test; @@ -61,6 +58,7 @@ public class MetricsFeatureProviderTest { @Mock private VisibilityLoggerMixin mockVisibilityLogger; private Context mContext; + private MetricsFeatureProvider mProvider; @Captor private ArgumentCaptor mPairCaptor; @@ -69,6 +67,12 @@ public class MetricsFeatureProviderTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; + mProvider = new MetricsFeatureProvider(); + List writers = new ArrayList<>(); + writers.add(mockLogWriter); + ReflectionHelpers.setField(mProvider, "mLoggerWriters", writers); + + when(mockVisibilityLogger.elapsedTimeSinceVisible()).thenReturn(ELAPSED_TIME); } @Test @@ -80,4 +84,60 @@ public class MetricsFeatureProviderTest { assertThat(feature1 == feature2).isTrue(); } + + @Test + public void logDashboardStartIntent_intentEmpty_shouldNotLog() { + mProvider.logDashboardStartIntent(mContext, null /* intent */, + MetricsEvent.SETTINGS_GESTURES); + + verifyNoMoreInteractions(mockLogWriter); + } + + @Test + public void logDashboardStartIntent_intentHasNoComponent_shouldLog() { + final Intent intent = new Intent(Intent.ACTION_ASSIST); + + mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES); + + verify(mockLogWriter).action( + eq(mContext), + eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK), + anyString(), + eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES))); + } + + @Test + public void logDashboardStartIntent_intentIsExternal_shouldLog() { + final Intent intent = new Intent().setComponent(new ComponentName("pkg", "cls")); + + mProvider.logDashboardStartIntent(mContext, intent, MetricsEvent.SETTINGS_GESTURES); + + verify(mockLogWriter).action( + eq(mContext), + eq(MetricsEvent.ACTION_SETTINGS_TILE_CLICK), + anyString(), + eq(Pair.create(MetricsEvent.FIELD_CONTEXT, MetricsEvent.SETTINGS_GESTURES))); + } + + @Test + public void action_BooleanLogsElapsedTime() { + mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_BOOLEAN); + verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_BOOLEAN), mPairCaptor.capture()); + + Pair value = mPairCaptor.getValue(); + assertThat(value.first instanceof Integer).isTrue(); + assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS); + assertThat(value.second).isEqualTo(ELAPSED_TIME); + } + + @Test + public void action_IntegerLogsElapsedTime() { + mProvider.action(mockVisibilityLogger, CATEGORY, SUBTYPE_INTEGER); + verify(mockLogWriter).action(eq(CATEGORY), eq(SUBTYPE_INTEGER), mPairCaptor.capture()); + + Pair value = mPairCaptor.getValue(); + assertThat(value.first instanceof Integer).isTrue(); + assertThat((int) value.first).isEqualTo(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS); + assertThat(value.second).isEqualTo(ELAPSED_TIME); + } } diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/SharedPreferenceLoggerTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/SharedPreferenceLoggerTest.java new file mode 100644 index 00000000000..c80e3a89d8d --- /dev/null +++ b/tests/robotests/src/com/android/settings/core/instrumentation/SharedPreferenceLoggerTest.java @@ -0,0 +1,185 @@ +/* + * 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.core.instrumentation; + +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Pair; + +import com.android.settings.TestConfig; +import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import com.google.common.truth.Platform; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Answers; +import org.mockito.ArgumentMatcher; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SharedPreferenceLoggerTest { + + private static final String TEST_TAG = "tag"; + private static final String TEST_KEY = "key"; + + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Context mContext; + + private ArgumentMatcher> mNamePairMatcher; + private FakeFeatureFactory mFactory; + private MetricsFeatureProvider mMetricsFeature; + private SharedPreferencesLogger mSharedPrefLogger; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + mFactory = FakeFeatureFactory.setupForTest(); + mMetricsFeature = mFactory.metricsFeatureProvider; + + mSharedPrefLogger = new SharedPreferencesLogger(mContext, TEST_TAG); + mNamePairMatcher = pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, String.class); + } + + @Test + public void putInt_shouldNotLogInitialPut() { + final SharedPreferences.Editor editor = mSharedPrefLogger.edit(); + editor.putInt(TEST_KEY, 1); + editor.putInt(TEST_KEY, 1); + editor.putInt(TEST_KEY, 1); + editor.putInt(TEST_KEY, 2); + editor.putInt(TEST_KEY, 2); + editor.putInt(TEST_KEY, 2); + editor.putInt(TEST_KEY, 2); + + verify(mMetricsFeature, times(6)).action(any(Context.class), anyInt(), + argThat(mNamePairMatcher), + argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class))); + } + + @Test + public void putBoolean_shouldNotLogInitialPut() { + final SharedPreferences.Editor editor = mSharedPrefLogger.edit(); + editor.putBoolean(TEST_KEY, true); + editor.putBoolean(TEST_KEY, true); + editor.putBoolean(TEST_KEY, false); + editor.putBoolean(TEST_KEY, false); + editor.putBoolean(TEST_KEY, false); + + + verify(mMetricsFeature).action(any(Context.class), anyInt(), + argThat(mNamePairMatcher), + argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, true))); + verify(mMetricsFeature, times(3)).action(any(Context.class), anyInt(), + argThat(mNamePairMatcher), + argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, false))); + } + + @Test + public void putLong_shouldNotLogInitialPut() { + final SharedPreferences.Editor editor = mSharedPrefLogger.edit(); + editor.putLong(TEST_KEY, 1); + editor.putLong(TEST_KEY, 1); + editor.putLong(TEST_KEY, 1); + editor.putLong(TEST_KEY, 1); + editor.putLong(TEST_KEY, 2); + + verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(), + argThat(mNamePairMatcher), + argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class))); + } + + @Test + public void putLong_biggerThanIntMax_shouldLogIntMax() { + final SharedPreferences.Editor editor = mSharedPrefLogger.edit(); + final long veryBigNumber = 500L + Integer.MAX_VALUE; + editor.putLong(TEST_KEY, 1); + editor.putLong(TEST_KEY, veryBigNumber); + + verify(mMetricsFeature).action(any(Context.class), anyInt(), + argThat(mNamePairMatcher), + argThat(pairMatches( + FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MAX_VALUE))); + } + + @Test + public void putLong_smallerThanIntMin_shouldLogIntMin() { + final SharedPreferences.Editor editor = mSharedPrefLogger.edit(); + final long veryNegativeNumber = -500L + Integer.MIN_VALUE; + editor.putLong(TEST_KEY, 1); + editor.putLong(TEST_KEY, veryNegativeNumber); + + verify(mMetricsFeature).action(any(Context.class), anyInt(), + argThat(mNamePairMatcher), + argThat(pairMatches( + FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MIN_VALUE))); + } + + @Test + public void putFloat_shouldNotLogInitialPut() { + final SharedPreferences.Editor editor = mSharedPrefLogger.edit(); + editor.putFloat(TEST_KEY, 1); + editor.putFloat(TEST_KEY, 1); + editor.putFloat(TEST_KEY, 1); + editor.putFloat(TEST_KEY, 1); + editor.putFloat(TEST_KEY, 2); + + verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(), + argThat(mNamePairMatcher), + argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE, Float.class))); + } + + @Test + public void logPackage_shouldUseLogPackageApi() { + mSharedPrefLogger.logPackageName("key", "com.android.settings"); + verify(mMetricsFeature).action(any(Context.class), + eq(ACTION_SETTINGS_PREFERENCE_CHANGE), + eq("com.android.settings"), + any(Pair.class)); + } + + private ArgumentMatcher> pairMatches(int tag, Class clazz) { + return pair -> pair.first == tag && Platform.isInstanceOfType(pair.second, clazz); + } + + private ArgumentMatcher> pairMatches(int tag, boolean bool) { + return pair -> pair.first == tag + && Platform.isInstanceOfType(pair.second, Integer.class) + && pair.second.equals((bool ? 1 : 0)); + } + + private ArgumentMatcher> pairMatches(int tag, int val) { + return pair -> pair.first == tag + && Platform.isInstanceOfType(pair.second, Integer.class) + && pair.second.equals(val); + } +} diff --git a/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java b/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java new file mode 100644 index 00000000000..1a47a66f25e --- /dev/null +++ b/tests/robotests/src/com/android/settings/core/instrumentation/VisibilityLoggerMixinTest.java @@ -0,0 +1,123 @@ +/* + * 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.core.instrumentation; + +import static com.android.settings.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN; + +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.SettingsActivity; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.TestConfig; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class VisibilityLoggerMixinTest { + + @Mock + private MetricsFeatureProvider mMetricsFeature; + + private VisibilityLoggerMixin mMixin; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC, mMetricsFeature); + } + + @Test + public void shouldLogVisibleOnResume() { + mMixin.onResume(); + + verify(mMetricsFeature, times(1)) + .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.VIEW_UNKNOWN), + eq(TestInstrumentable.TEST_METRIC)); + } + + @Test + public void shouldLogVisibleWithSource() { + final Intent sourceIntent = new Intent() + .putExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, + MetricsProto.MetricsEvent.SETTINGS_GESTURES); + final Activity activity = mock(Activity.class); + when(activity.getIntent()).thenReturn(sourceIntent); + mMixin.setSourceMetricsCategory(activity); + mMixin.onResume(); + + verify(mMetricsFeature, times(1)) + .visible(nullable(Context.class), eq(MetricsProto.MetricsEvent.SETTINGS_GESTURES), + eq(TestInstrumentable.TEST_METRIC)); + } + + @Test + public void shouldLogHideOnPause() { + mMixin.onPause(); + + verify(mMetricsFeature, times(1)) + .hidden(nullable(Context.class), eq(TestInstrumentable.TEST_METRIC)); + } + + @Test + public void shouldNotLogIfMetricsFeatureIsNull() { + mMixin = new VisibilityLoggerMixin(TestInstrumentable.TEST_METRIC); + mMixin.onResume(); + mMixin.onPause(); + + verify(mMetricsFeature, never()) + .hidden(nullable(Context.class), anyInt()); + } + + @Test + public void shouldNotLogIfMetricsCategoryIsUnknown() { + mMixin = new VisibilityLoggerMixin(METRICS_CATEGORY_UNKNOWN, mMetricsFeature); + + mMixin.onResume(); + mMixin.onPause(); + + verify(mMetricsFeature, never()) + .hidden(nullable(Context.class), anyInt()); + } + + private final class TestInstrumentable implements Instrumentable { + + public static final int TEST_METRIC = 12345; + + @Override + public int getMetricsCategory() { + return TEST_METRIC; + } + } +} diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java index afa914cf93f..741f2bc084c 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java @@ -51,7 +51,6 @@ import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowThreadUtils; import com.android.settings.testutils.shadow.ShadowTileUtils; import com.android.settings.testutils.shadow.ShadowUserManager; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.drawer.CategoryKey; import com.android.settingslib.drawer.CategoryManager; import com.android.settingslib.drawer.DashboardCategory; @@ -373,7 +372,7 @@ public class DashboardFeatureProviderImplTest { final Intent launchIntent = shadowActivity.getNextStartedActivityForResult().intent; assertThat(launchIntent.getAction()) .isEqualTo("TestAction"); - assertThat(launchIntent.getIntExtra(VisibilityLoggerMixin.EXTRA_SOURCE_METRICS_CATEGORY, 0)) + assertThat(launchIntent.getIntExtra(SettingsActivity.EXTRA_SOURCE_METRICS_CATEGORY, 0)) .isEqualTo(MetricsProto.MetricsEvent.SETTINGS_GESTURES); } diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java index 40e590a665c..6c663ab6cef 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java @@ -33,10 +33,10 @@ import android.support.v7.preference.PreferenceScreen; import com.android.settings.TestConfig; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import com.android.settingslib.drawer.DashboardCategory; import com.android.settingslib.drawer.Tile; import com.android.settingslib.drawer.TileUtils; diff --git a/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java b/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java index 1a3fa5e7092..d077e6fcd77 100644 --- a/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/conditional/ConditionTest.java @@ -22,7 +22,7 @@ import android.graphics.drawable.Icon; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java index 8b3c7708230..9ab88d3a805 100644 --- a/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java +++ b/tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java @@ -60,7 +60,6 @@ public class DataUsageListTest { @Test public void resumePause_shouldListenUnlistenDataStateChange() { - mDataUsageList.onAttach(mContext); mDataUsageList.onResume(); verify(mListener).setListener(true, 0, mContext); diff --git a/tests/robotests/src/com/android/settings/datetime/ZonePickerTest.java b/tests/robotests/src/com/android/settings/datetime/ZonePickerTest.java index 9f6d0ef984a..92807e9fcf3 100644 --- a/tests/robotests/src/com/android/settings/datetime/ZonePickerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/ZonePickerTest.java @@ -28,8 +28,8 @@ import android.view.ViewGroup; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.VisibilityLoggerMixin; import com.android.settings.testutils.shadow.ShadowZoneGetter; -import com.android.settingslib.core.instrumentation.VisibilityLoggerMixin; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarControllerTest.java index ab32fa28705..66ccc6ec3dd 100644 --- a/tests/robotests/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarControllerTest.java +++ b/tests/robotests/src/com/android/settings/deletionhelper/AutomaticStorageManagerSwitchBarControllerTest.java @@ -31,11 +31,11 @@ import android.support.v7.preference.Preference; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowSystemProperties; import com.android.settings.widget.SwitchBar; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceControllerTest.java index 9c566113149..90ce3953ee3 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/AutomaticStorageManagementSwitchPreferenceControllerTest.java @@ -37,13 +37,13 @@ import android.support.v7.preference.PreferenceScreen; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.RoSystemProperties; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.deletionhelper.ActivationWarningFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowSystemProperties; import com.android.settings.widget.MasterSwitchPreference; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.After; import org.junit.Before; diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java index 2da756f5a1d..1a3139d509c 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java @@ -50,13 +50,13 @@ import com.android.settings.SettingsActivity; import com.android.settings.SubSettings; import com.android.settings.TestConfig; import com.android.settings.applications.manageapplications.ManageApplications; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.deviceinfo.PrivateVolumeSettings; import com.android.settings.deviceinfo.StorageItemPreference; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settingslib.applications.StorageStatsSource; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.deviceinfo.StorageVolumeProvider; import org.junit.After; diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceControllerTest.java index e251be0db6b..6ad37ce2cec 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageSummaryDonutPreferenceControllerTest.java @@ -38,10 +38,10 @@ import android.widget.LinearLayout; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.deviceinfo.StorageVolumeProvider; import org.junit.After; diff --git a/tests/robotests/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceControllerTest.java index c003f176613..e1ce6945c13 100644 --- a/tests/robotests/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AmbientDisplayNotificationsPreferenceControllerTest.java @@ -32,11 +32,11 @@ import android.support.v14.preference.SwitchPreference; import com.android.internal.hardware.AmbientDisplayConfiguration; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.search.InlinePayload; import com.android.settings.search.InlineSwitchPayload; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowSecureSettings; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollEnrollingTest.java b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollEnrollingTest.java index 5418ead24d4..c590fd34dc1 100644 --- a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollEnrollingTest.java +++ b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollEnrollingTest.java @@ -36,7 +36,6 @@ import android.widget.TextView; import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.password.ChooseLockSettingsHelper; -import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.testutils.shadow.ShadowVibrator; @@ -70,15 +69,12 @@ public class FingerprintEnrollEnrollingTest { private FingerprintEnrollEnrolling mActivity; - private FakeFeatureFactory mFactory; - @Before public void setUp() { MockitoAnnotations.initMocks(this); ShadowUtils.setFingerprintManager(mFingerprintManager); ShadowVibrator.addToServiceMap(); - mFactory = FakeFeatureFactory.setupForTest(); mActivity = Robolectric.buildActivity( FingerprintEnrollEnrolling.class, new Intent() diff --git a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java index be53aa57487..d495b74e903 100644 --- a/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java +++ b/tests/robotests/src/com/android/settings/fingerprint/FingerprintEnrollFindSensorTest.java @@ -33,7 +33,6 @@ import android.widget.Button; import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.password.ChooseLockSettingsHelper; -import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowEventLogWriter; @@ -70,13 +69,10 @@ public class FingerprintEnrollFindSensorTest { private FingerprintEnrollFindSensor mActivity; - private FakeFeatureFactory mFactory; - @Before public void setUp() { MockitoAnnotations.initMocks(this); ShadowUtils.setFingerprintManager(mFingerprintManager); - mFactory = FakeFeatureFactory.setupForTest(); mActivity = Robolectric.buildActivity( FingerprintEnrollFindSensor.class, diff --git a/tests/robotests/src/com/android/settings/fingerprint/FingerprintSuggestionActivityTest.java b/tests/robotests/src/com/android/settings/fingerprint/FingerprintSuggestionActivityTest.java index f52f437414b..0254bcb997b 100644 --- a/tests/robotests/src/com/android/settings/fingerprint/FingerprintSuggestionActivityTest.java +++ b/tests/robotests/src/com/android/settings/fingerprint/FingerprintSuggestionActivityTest.java @@ -30,7 +30,6 @@ import android.widget.Button; import com.android.settings.R; import com.android.settings.TestConfig; -import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowLockPatternUtils; @@ -64,12 +63,9 @@ public class FingerprintSuggestionActivityTest { private ActivityController mController; - private FakeFeatureFactory mFactory; - @Before public void setUp() { MockitoAnnotations.initMocks(this); - mFactory = FakeFeatureFactory.setupForTest(); final Intent intent = new Intent(); mController = Robolectric.buildActivity(FingerprintSuggestionActivity.class, intent); diff --git a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java index c786608386a..c3899e9b01d 100644 --- a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java +++ b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollFindSensorTest.java @@ -27,7 +27,6 @@ import android.widget.Button; import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.password.ChooseLockSettingsHelper; -import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowEventLogWriter; @@ -62,13 +61,10 @@ public class SetupFingerprintEnrollFindSensorTest { private SetupFingerprintEnrollFindSensor mActivity; - private FakeFeatureFactory mFactory; - @Before public void setUp() { MockitoAnnotations.initMocks(this); ShadowUtils.setFingerprintManager(mFingerprintManager); - mFactory = FakeFeatureFactory.setupForTest(); } private void createActivity(Intent intent) { diff --git a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java index f5b0c8a9ad0..2d98bf44511 100644 --- a/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java +++ b/tests/robotests/src/com/android/settings/fingerprint/SetupFingerprintEnrollIntroductionTest.java @@ -35,7 +35,6 @@ import com.android.settings.fingerprint.SetupFingerprintEnrollIntroductionTest import com.android.settings.password.SetupChooseLockGeneric.SetupChooseLockGenericFragment; import com.android.settings.password.SetupSkipDialog; import com.android.settings.password.StorageManagerWrapper; -import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowEventLogWriter; import com.android.settings.testutils.shadow.ShadowFingerprintManager; @@ -73,7 +72,6 @@ public class SetupFingerprintEnrollIntroductionTest { @Mock private UserInfo mUserInfo; - private FakeFeatureFactory mFactory; private ActivityController mController; @@ -85,8 +83,6 @@ public class SetupFingerprintEnrollIntroductionTest { .setSystemFeature(PackageManager.FEATURE_FINGERPRINT, true); ShadowFingerprintManager.addToServiceMap(); - mFactory = FakeFeatureFactory.setupForTest(); - final Intent intent = new Intent(); mController = Robolectric.buildActivity(SetupFingerprintEnrollIntroduction.class, intent); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java index 3e33823b82c..38391c9350b 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyUtilsTest.java @@ -24,6 +24,7 @@ import android.os.Build; import android.util.Pair; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.fuelgauge.anomaly.action.StopAndBackgroundCheckAction; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; @@ -31,7 +32,6 @@ import com.android.settings.fuelgauge.anomaly.action.ForceStopAction; import com.android.settings.fuelgauge.anomaly.checker.WakeLockAnomalyDetector; import com.android.settings.testutils.shadow.ShadowKeyValueListParserWrapperImpl; import com.android.settings.fuelgauge.anomaly.checker.WakeupAlarmAnomalyDetector; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java index 737c16d5001..1ee52ca463c 100644 --- a/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java +++ b/tests/robotests/src/com/android/settings/localepicker/LocaleListEditorTest.java @@ -20,7 +20,6 @@ import android.content.Context; import android.view.View; import android.widget.TextView; import com.android.settings.TestConfig; -import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment; @@ -28,7 +27,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; @@ -41,11 +39,6 @@ public class LocaleListEditorTest { private LocaleListEditor mLocaleListEditor; - @Mock - private Context mContext; - - private FakeFeatureFactory mFactory; - @Before public void setUp() { mLocaleListEditor = new LocaleListEditor(); @@ -55,13 +48,11 @@ public class LocaleListEditorTest { RuntimeEnvironment.application.getSystemService(Context.RESTRICTIONS_SERVICE)); ReflectionHelpers.setField(mLocaleListEditor, "mUserManager", RuntimeEnvironment.application.getSystemService(Context.USER_SERVICE)); - mFactory = FakeFeatureFactory.setupForTest(); } @Test public void testDisallowConfigLocale_unrestrict() { ReflectionHelpers.setField(mLocaleListEditor, "mIsUiRestricted", true); - mLocaleListEditor.onAttach(mContext); mLocaleListEditor.onResume(); Assert.assertEquals(View.GONE, mLocaleListEditor.getEmptyTextView().getVisibility()); } @@ -69,7 +60,6 @@ public class LocaleListEditorTest { @Test public void testDisallowConfigLocale_restrict() { ReflectionHelpers.setField(mLocaleListEditor, "mIsUiRestricted", false); - mLocaleListEditor.onAttach(mContext); mLocaleListEditor.onResume(); Assert.assertEquals(View.VISIBLE, mLocaleListEditor.getEmptyTextView().getVisibility()); } diff --git a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java index 3325332703b..752ca1e21dc 100644 --- a/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java +++ b/tests/robotests/src/com/android/settings/testutils/FakeFeatureFactory.java @@ -24,6 +24,7 @@ import android.content.Context; import com.android.settings.applications.ApplicationFeatureProvider; import com.android.settings.bluetooth.BluetoothFeatureProvider; import com.android.settings.connecteddevice.SmsMirroringFeatureProvider; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.dashboard.DashboardFeatureProvider; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; import com.android.settings.datausage.DataPlanFeatureProvider; @@ -38,7 +39,6 @@ import com.android.settings.search.SearchFeatureProvider; import com.android.settings.security.SecurityFeatureProvider; import com.android.settings.slices.SlicesFeatureProvider; import com.android.settings.users.UserFeatureProvider; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.mockito.Answers; diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowEventLogWriter.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowEventLogWriter.java index 9caf09f3e8d..dcced4e40d0 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowEventLogWriter.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowEventLogWriter.java @@ -19,7 +19,7 @@ package com.android.settings.testutils.shadow; import android.content.Context; -import com.android.settingslib.core.instrumentation.EventLogWriter; +import com.android.settings.core.instrumentation.EventLogWriter; import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; diff --git a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java index 59a08ae8801..e44be0e8781 100644 --- a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java +++ b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java @@ -44,10 +44,10 @@ import android.os.UserManager; import com.android.settings.TestConfig; import com.android.settings.applications.defaultapps.DefaultAppInfo; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.widget.RadioButtonPreference; import com.android.settings.wrapper.UserPackageWrapper; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.wrapper.PackageManagerWrapper; import org.junit.Before; diff --git a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java index 84549a62388..63f89e62c5c 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiEnablerTest.java @@ -22,9 +22,9 @@ import android.net.wifi.WifiManager; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.widget.SwitchWidgetController; import com.android.settings.wrapper.ConnectivityManagerWrapper; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java index 82569c74054..1708e364e0f 100644 --- a/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/WifiMasterSwitchPreferenceControllerTest.java @@ -30,10 +30,10 @@ import android.support.v7.preference.Preference.OnPreferenceChangeListener; import android.support.v7.preference.PreferenceScreen; import com.android.settings.TestConfig; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.widget.MasterSwitchPreference; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import org.junit.Before; import org.junit.Test; diff --git a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java index ca2cac09257..4f774357612 100644 --- a/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/wifi/details/WifiDetailPreferenceControllerTest.java @@ -65,6 +65,7 @@ import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.TestConfig; import com.android.settings.applications.LayoutPreference; +import com.android.settings.core.instrumentation.MetricsFeatureProvider; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.shadow.ShadowBidiFormatter; import com.android.settings.testutils.shadow.ShadowDevicePolicyManagerWrapper; @@ -75,7 +76,6 @@ import com.android.settings.widget.ActionButtonPreferenceTest; import com.android.settings.widget.EntityHeaderController; import com.android.settings.wifi.WifiDetailPreference; import com.android.settings.wrapper.ConnectivityManagerWrapper; -import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.wifi.AccessPoint; From e2ad4149abd8e08e389d22b5bbff4560400ca5ec Mon Sep 17 00:00:00 2001 From: Carlos Valdivia Date: Tue, 23 Jan 2018 09:12:59 -0800 Subject: [PATCH 10/21] AF/FR Fix onActivityResult condition. Chase list bug. Accidentally bailed on true effectively. Manual tested by going to Settings > System > Erase All Data And then hitting then successfully wiping and reseting. Test: make RunSettingsRoboTests -j40 Bug: 72324059 Change-Id: Ib2a155820811f0ec62a45c1312475c24646ede76 (cherry picked from commit 5dd6ed470eb8b3c59c88f605e96789da2f147cc4) --- src/com/android/settings/MasterClear.java | 11 ++++++++--- .../src/com/android/settings/MasterClearTest.java | 7 +++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java index 3cc722bbffa..b24bd62d248 100644 --- a/src/com/android/settings/MasterClear.java +++ b/src/com/android/settings/MasterClear.java @@ -75,8 +75,8 @@ import java.util.List; public class MasterClear extends InstrumentedPreferenceFragment { private static final String TAG = "MasterClear"; - private static final int KEYGUARD_REQUEST = 55; - private static final int CREDENTIAL_CONFIRM_REQUEST = 56; + @VisibleForTesting static final int KEYGUARD_REQUEST = 55; + @VisibleForTesting static final int CREDENTIAL_CONFIRM_REQUEST = 56; static final String ERASE_EXTERNAL_EXTRA = "erase_sd"; static final String ERASE_ESIMS_EXTRA = "erase_esim"; @@ -113,11 +113,16 @@ public class MasterClear extends InstrumentedPreferenceFragment { request, res.getText(R.string.master_clear_title)); } + @VisibleForTesting + boolean isValidRequestCode(int requestCode) { + return !((requestCode != KEYGUARD_REQUEST) && (requestCode != CREDENTIAL_CONFIRM_REQUEST)); + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode != KEYGUARD_REQUEST || requestCode != CREDENTIAL_CONFIRM_REQUEST) { + if (!isValidRequestCode(requestCode)) { return; } diff --git a/tests/robotests/src/com/android/settings/MasterClearTest.java b/tests/robotests/src/com/android/settings/MasterClearTest.java index 361bc8f319d..c23e88facbe 100644 --- a/tests/robotests/src/com/android/settings/MasterClearTest.java +++ b/tests/robotests/src/com/android/settings/MasterClearTest.java @@ -167,6 +167,13 @@ public class MasterClearTest { assertThat(mMasterClear.tryShowAccountConfirmation()).isFalse(); } + @Test + public void testIsValidRequestCode() { + assertThat(mMasterClear.isValidRequestCode(MasterClear.KEYGUARD_REQUEST)).isTrue(); + assertThat(mMasterClear.isValidRequestCode(MasterClear.CREDENTIAL_CONFIRM_REQUEST)).isTrue(); + assertThat(mMasterClear.isValidRequestCode(0)).isFalse(); + } + private void initScrollView(int height, int scrollY, int childBottom) { when(mScrollView.getHeight()).thenReturn(height); when(mScrollView.getScrollY()).thenReturn(scrollY); From 7dfdd888d611671c498a714f47277dbbd028a65e Mon Sep 17 00:00:00 2001 From: Carlos Valdivia Date: Tue, 23 Jan 2018 09:12:59 -0800 Subject: [PATCH 11/21] AF/FR Fix onActivityResult condition. Chase list bug. Accidentally bailed on true effectively. Manual tested by going to Settings > System > Erase All Data And then hitting then successfully wiping and reseting. Test: make RunSettingsRoboTests -j40 Bug: 72324059 Change-Id: Ib2a155820811f0ec62a45c1312475c24646ede76 (cherry picked from commit 5dd6ed470eb8b3c59c88f605e96789da2f147cc4) --- src/com/android/settings/MasterClear.java | 9 +++++++-- .../src/com/android/settings/MasterClearTest.java | 7 +++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/MasterClear.java b/src/com/android/settings/MasterClear.java index 0e337f68bf0..b7fb69404cd 100644 --- a/src/com/android/settings/MasterClear.java +++ b/src/com/android/settings/MasterClear.java @@ -75,7 +75,7 @@ import java.util.List; public class MasterClear extends InstrumentedPreferenceFragment { private static final String TAG = "MasterClear"; - private static final int KEYGUARD_REQUEST = 55; + @VisibleForTesting static final int KEYGUARD_REQUEST = 55; @VisibleForTesting static final int CREDENTIAL_CONFIRM_REQUEST = 56; private static final String KEY_SHOW_ESIM_RESET_CHECKBOX @@ -118,11 +118,16 @@ public class MasterClear extends InstrumentedPreferenceFragment { request, res.getText(R.string.master_clear_title)); } + @VisibleForTesting + boolean isValidRequestCode(int requestCode) { + return !((requestCode != KEYGUARD_REQUEST) && (requestCode != CREDENTIAL_CONFIRM_REQUEST)); + } + @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); - if (requestCode != KEYGUARD_REQUEST || requestCode != CREDENTIAL_CONFIRM_REQUEST) { + if (!isValidRequestCode(requestCode)) { return; } diff --git a/tests/robotests/src/com/android/settings/MasterClearTest.java b/tests/robotests/src/com/android/settings/MasterClearTest.java index ac753c109f2..9bf3310c6b8 100644 --- a/tests/robotests/src/com/android/settings/MasterClearTest.java +++ b/tests/robotests/src/com/android/settings/MasterClearTest.java @@ -270,6 +270,13 @@ public class MasterClearTest { assertThat(mMasterClear.tryShowAccountConfirmation()).isTrue(); } + @Test + public void testIsValidRequestCode() { + assertThat(mMasterClear.isValidRequestCode(MasterClear.KEYGUARD_REQUEST)).isTrue(); + assertThat(mMasterClear.isValidRequestCode(MasterClear.CREDENTIAL_CONFIRM_REQUEST)).isTrue(); + assertThat(mMasterClear.isValidRequestCode(0)).isFalse(); + } + private void initScrollView(int height, int scrollY, int childBottom) { when(mScrollView.getHeight()).thenReturn(height); when(mScrollView.getScrollY()).thenReturn(scrollY); From f98425c87454509f05790b008a1e54775150f2e3 Mon Sep 17 00:00:00 2001 From: Salvador Martinez Date: Wed, 24 Jan 2018 10:24:04 -0800 Subject: [PATCH 12/21] Fix null pointer from PowerUsageFeatureProvider Some locations did not check if the returned value was null before doing operations on them and could crash. This CL changes those spots to take that into account. Test: b/72463854 will add in follow up to unblock dogfood Bug: 72350595 Change-Id: I0ace5c0ab4a8aa9fd5b09d41d6f986143246f059 (cherry picked from commit 250a79830cd065602b99ec3d611da694ee294ea8) --- .../settings/fuelgauge/BatteryInfo.java | 24 ++++++++++--------- .../fuelgauge/DebugEstimatesLoader.java | 3 +++ 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/fuelgauge/BatteryInfo.java b/src/com/android/settings/fuelgauge/BatteryInfo.java index c4c795b29b1..63841307ed8 100644 --- a/src/com/android/settings/fuelgauge/BatteryInfo.java +++ b/src/com/android/settings/fuelgauge/BatteryInfo.java @@ -171,18 +171,20 @@ public class BatteryInfo { if (discharging && provider != null && provider.isEnhancedBatteryPredictionEnabled(context)) { Estimate estimate = provider.getEnhancedBatteryPrediction(context); - BatteryUtils.logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime); - return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, - elapsedRealtimeUs, shortString, - BatteryUtils.convertMsToUs(estimate.estimateMillis), - estimate.isBasedOnUsage); - } else { - long prediction = discharging - ? stats.computeBatteryTimeRemaining(elapsedRealtimeUs) : 0; - BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime); - return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, - elapsedRealtimeUs, shortString, prediction, false); + if(estimate != null) { + BatteryUtils + .logRuntime(LOG_TAG, "time for enhanced BatteryInfo", startTime); + return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, + elapsedRealtimeUs, shortString, + BatteryUtils.convertMsToUs(estimate.estimateMillis), + estimate.isBasedOnUsage); + } } + long prediction = discharging + ? stats.computeBatteryTimeRemaining(elapsedRealtimeUs) : 0; + BatteryUtils.logRuntime(LOG_TAG, "time for regular BatteryInfo", startTime); + return BatteryInfo.getBatteryInfo(context, batteryBroadcast, stats, + elapsedRealtimeUs, shortString, prediction, false); } @Override diff --git a/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java b/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java index a080e2b7300..e58ccd339a0 100644 --- a/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java +++ b/src/com/android/settings/fuelgauge/DebugEstimatesLoader.java @@ -55,6 +55,9 @@ public class DebugEstimatesLoader extends AsyncLoader> { stats, elapsedRealtimeUs, false); Estimate estimate = powerUsageFeatureProvider.getEnhancedBatteryPrediction(context); + if (estimate == null) { + estimate = new Estimate(0, false); + } BatteryInfo newInfo = BatteryInfo.getBatteryInfo(getContext(), batteryBroadcast, stats, elapsedRealtimeUs, false, BatteryUtils.convertMsToUs(estimate.estimateMillis), From 94cf4c39eaf78dfa73373a1504d5a7f2dc634ef4 Mon Sep 17 00:00:00 2001 From: Antony Sargent Date: Wed, 24 Jan 2018 16:14:16 -0800 Subject: [PATCH 13/21] Prevent crash in recent app list In some situations if you have recently used an app and then uninstalled it, the display of recent apps in Settings->Apps & notifications would crash. This is due to a bug in recent CL that fixed b/71591298. Test: make -j64 RunSettingsRoboTests Change-Id: Id04b073b2617eeff0e188b10d3743496a9f70d5e Fixes: 72340364 (cherry picked from commit e04101be07b2225ee51f474d8f254d892fc4c6bc) --- .../RecentAppsPreferenceController.java | 2 +- ...centNotifyingAppsPreferenceController.java | 2 +- .../RecentAppsPreferenceControllerTest.java | 27 +++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/applications/RecentAppsPreferenceController.java b/src/com/android/settings/applications/RecentAppsPreferenceController.java index 20c5581ae8e..38590817ae7 100644 --- a/src/com/android/settings/applications/RecentAppsPreferenceController.java +++ b/src/com/android/settings/applications/RecentAppsPreferenceController.java @@ -325,7 +325,7 @@ public class RecentAppsPreferenceController extends AbstractPreferenceController // Not visible on launcher -> likely not a user visible app, skip if non-instant. final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry(pkgName, mUserId); - if (!AppUtils.isInstant(appEntry.info)) { + if (appEntry == null || appEntry.info == null || !AppUtils.isInstant(appEntry.info)) { Log.d(TAG, "Not a user visible or instant app, skipping " + pkgName); return false; } diff --git a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java index ef34a9b65e6..dbffc550d5e 100644 --- a/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java +++ b/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java @@ -283,7 +283,7 @@ public class RecentNotifyingAppsPreferenceController extends AbstractPreferenceC // Not visible on launcher -> likely not a user visible app, skip if non-instant. final ApplicationsState.AppEntry appEntry = mApplicationsState.getEntry(pkgName, mUserId); - if (!AppUtils.isInstant(appEntry.info)) { + if (appEntry == null || appEntry.info == null || !AppUtils.isInstant(appEntry.info)) { Log.d(TAG, "Not a user visible or instant app, skipping " + pkgName); return false; } diff --git a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java index bd57211a231..ed97fe774b6 100644 --- a/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/RecentAppsPreferenceControllerTest.java @@ -247,6 +247,33 @@ public class RecentAppsPreferenceControllerTest { assertThat(prefs.get(0).getKey()).isEqualTo(stat2.mPackageName); } + @Test + public void display_showRecentsWithNullAppEntryOrInfo() { + final List stats = new ArrayList<>(); + final UsageStats stat1 = new UsageStats(); + final UsageStats stat2 = new UsageStats(); + stat1.mLastTimeUsed = System.currentTimeMillis(); + stat1.mPackageName = "pkg.class"; + stats.add(stat1); + + stat2.mLastTimeUsed = System.currentTimeMillis(); + stat2.mPackageName = "pkg.class2"; + stats.add(stat2); + + // app1 has AppEntry with null info, app2 has null AppEntry. + mAppEntry.info = null; + when(mAppState.getEntry(stat1.mPackageName, UserHandle.myUserId())) + .thenReturn(mAppEntry); + when(mAppState.getEntry(stat2.mPackageName, UserHandle.myUserId())) + .thenReturn(null); + + when(mUsageStatsManager.queryUsageStats(anyInt(), anyLong(), anyLong())) + .thenReturn(stats); + + // We should not crash here. + mController.displayPreference(mScreen); + } + @Test public void display_hasRecentButNoneDisplayable_showAppInfo() { final List stats = new ArrayList<>(); From 78d21f602a4e3ebf6889b88c819e7c000c4ee6a0 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Tue, 27 Feb 2018 20:12:57 +0000 Subject: [PATCH 14/21] Revert "Update to match now slice APIs" This reverts commit 2d96005aba3a509fc801f9a05d61786d8ad78218. Reason for revert: prebuilt revert Bug: 73903252 Bug: 73876473 Bug: 73875529 Bug: 73866916 Change-Id: I5d47a7c5ddebc16c1c508f5bb48ace809cbaf273 (cherry picked from commit 80c806abd60f8d8381f6654fd2f708f5d915f0bf) --- src/com/android/settings/slices/SettingsSliceProvider.java | 6 ++---- src/com/android/settings/slices/SliceBuilderUtils.java | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/com/android/settings/slices/SettingsSliceProvider.java b/src/com/android/settings/slices/SettingsSliceProvider.java index d8ba991a145..433bdf368bd 100644 --- a/src/com/android/settings/slices/SettingsSliceProvider.java +++ b/src/com/android/settings/slices/SettingsSliceProvider.java @@ -35,7 +35,6 @@ import java.util.WeakHashMap; import androidx.app.slice.Slice; import androidx.app.slice.SliceProvider; -import androidx.app.slice.builders.SliceAction; import androidx.app.slice.builders.ListBuilder; /** @@ -174,9 +173,8 @@ public class SettingsSliceProvider extends SliceProvider { .setTitle(getContext().getString(R.string.wifi_settings)) .setTitleItem(Icon.createWithResource(getContext(), R.drawable.wifi_signal)) .setSubtitle(state) - .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED), - null, finalWifiEnabled)) - .setPrimaryAction(new SliceAction(getIntent(Intent.ACTION_MAIN), null, null))) + .addToggle(getBroadcastIntent(ACTION_WIFI_CHANGED), finalWifiEnabled) + .setContentIntent(getIntent(Intent.ACTION_MAIN))) .build(); } diff --git a/src/com/android/settings/slices/SliceBuilderUtils.java b/src/com/android/settings/slices/SliceBuilderUtils.java index 3df24edbeb1..a01ea1bd0ed 100644 --- a/src/com/android/settings/slices/SliceBuilderUtils.java +++ b/src/com/android/settings/slices/SliceBuilderUtils.java @@ -34,7 +34,6 @@ import com.android.settings.search.DatabaseIndexingUtils; import com.android.settingslib.core.AbstractPreferenceController; import androidx.app.slice.Slice; -import androidx.app.slice.builders.SliceAction; import androidx.app.slice.builders.ListBuilder; import androidx.app.slice.builders.ListBuilder.RowBuilder; @@ -64,7 +63,7 @@ public class SliceBuilderUtils { .setTitle(sliceData.getTitle()) .setTitleItem(icon) .setSubtitle(subtitleText) - .setPrimaryAction(new SliceAction(contentIntent, null, null)); + .setContentIntent(contentIntent); // TODO (b/71640747) Respect setting availability. @@ -101,7 +100,7 @@ public class SliceBuilderUtils { String key) { PendingIntent actionIntent = getActionIntent(context, SettingsSliceProvider.ACTION_TOGGLE_CHANGED, key); - builder.addEndItem(new SliceAction(actionIntent, null, isChecked)); + builder.addToggle(actionIntent, isChecked); } private static PendingIntent getActionIntent(Context context, String action, String key) { From 5ae1758d47dc706a8c1c66829df416ec3e236df7 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Mon, 5 Mar 2018 16:13:33 +0000 Subject: [PATCH 15/21] Fix SettingsRoboTests build error with OpenJDK 9 - CL http://ag/3671365 broke git_pi-release/marlin-userdebug-jdk9 when building "m checkbuild". It shouldn't break the image build Test: m SettingsRoboTests ROBOTEST_FILTER=com.android.settings.datetime.timezone EXPERIMENTAL_USE_OPENJDK9=true USE_R8=true Change-Id: I161c0350cff55bd13ba4a6c63df4e4e9bc4b1a5f (cherry picked from commit e10875210adef2949aa4f9b56c40fb6d81b0f222) --- .../timezone/model/TimeZoneDataTest.java | 6 +-- .../src/libcore/util/CountryTimeZones.java | 45 ------------------- .../src/libcore/util/CountryZonesFinder.java | 38 ---------------- 3 files changed, 3 insertions(+), 86 deletions(-) delete mode 100644 tests/robotests/src/libcore/util/CountryTimeZones.java delete mode 100644 tests/robotests/src/libcore/util/CountryZonesFinder.java diff --git a/tests/robotests/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java b/tests/robotests/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java index e6073a8ecb4..4a624b70f6c 100644 --- a/tests/robotests/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java +++ b/tests/robotests/src/com/android/settings/datetime/timezone/model/TimeZoneDataTest.java @@ -73,13 +73,13 @@ public class TimeZoneDataTest { CountryTimeZones US = mock(CountryTimeZones.class); when(US.getCountryIso()).thenReturn("us"); when(US.getTimeZoneMappings()).thenReturn(Arrays.asList( - new CountryTimeZones.TimeZoneMapping("Unknown/Secret_City", true), - new CountryTimeZones.TimeZoneMapping("Unknown/Secret_City2", false) + TimeZoneMapping.createForTests("Unknown/Secret_City", true), + TimeZoneMapping.createForTests("Unknown/Secret_City2", false) )); CountryTimeZones GB = mock(CountryTimeZones.class); when(GB.getCountryIso()).thenReturn("gb"); when(GB.getTimeZoneMappings()).thenReturn(Collections.singletonList( - new TimeZoneMapping("Unknown/Secret_City", true) + TimeZoneMapping.createForTests("Unknown/Secret_City", true) )); when(mCountryZonesFinder.lookupCountryTimeZonesForZoneId("Unknown/Secret_City")) .thenReturn(Arrays.asList(US, GB)); diff --git a/tests/robotests/src/libcore/util/CountryTimeZones.java b/tests/robotests/src/libcore/util/CountryTimeZones.java deleted file mode 100644 index 2087848609d..00000000000 --- a/tests/robotests/src/libcore/util/CountryTimeZones.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 libcore.util; - -import java.util.List; - -/** - * Empty implementation of CountryTimeZones for Robolectric test. - */ -public class CountryTimeZones { - public CountryTimeZones() { - } - - public final static class TimeZoneMapping { - public final String timeZoneId; - public final boolean showInPicker; - - public TimeZoneMapping(String timeZoneId, boolean showInPicker) { - this.timeZoneId = timeZoneId; - this.showInPicker = showInPicker; - } - } - - public List getTimeZoneMappings() { - return null; - } - - public String getCountryIso() { - return null; - } -} diff --git a/tests/robotests/src/libcore/util/CountryZonesFinder.java b/tests/robotests/src/libcore/util/CountryZonesFinder.java deleted file mode 100644 index 51149ecb915..00000000000 --- a/tests/robotests/src/libcore/util/CountryZonesFinder.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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 libcore.util; - -import java.util.List; - -/** - * Empty implementation of CountryZonesFinder for Robolectric test. - */ -public class CountryZonesFinder { - public CountryZonesFinder(List countryTimeZonesList) {} - - public List lookupAllCountryIsoCodes() { - return null; - } - - public List lookupCountryTimeZonesForZoneId(String zoneId) { - return null; - } - - public CountryTimeZones lookupCountryTimeZones(String countryIso) { - return null; - } -} From cd7e9e6e6cc7868b76cd813fb37cfd9251ff1059 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Thu, 29 Mar 2018 20:20:08 +0000 Subject: [PATCH 16/21] Revert "Support AOD in the Universal Settings API" This reverts commit 537c2cfc2c21ffee691b11864a26bd84f043916a. Fixes: 77278897 Change-Id: I7a5ff34bf79b87f6a7be50c2e8f421bfc4a22195 (cherry picked from commit f75edca09fd5b576a0b733dc1b699f4fd8f05752) --- res/xml/ambient_display_settings.xml | 3 +- ...ntDisplayAlwaysOnPreferenceController.java | 58 ++++++---- .../display/AmbientDisplaySettings.java | 30 ++---- ...splayAlwaysOnPreferenceControllerTest.java | 102 ++++++++++-------- .../display/AmbientDisplaySettingsTest.java | 69 ------------ 5 files changed, 100 insertions(+), 162 deletions(-) delete mode 100644 tests/robotests/src/com/android/settings/display/AmbientDisplaySettingsTest.java diff --git a/res/xml/ambient_display_settings.xml b/res/xml/ambient_display_settings.xml index 037421cd213..306ead5d50f 100644 --- a/res/xml/ambient_display_settings.xml +++ b/res/xml/ambient_display_settings.xml @@ -29,8 +29,7 @@ + android:summary="@string/doze_always_on_summary" /> buildPreferenceControllers(Context context, Lifecycle lifecycle, AmbientDisplayConfiguration config, - MetricsFeatureProvider metricsFeatureProvider) { + MetricsFeatureProvider metricsFeatureProvider, + AmbientDisplayAlwaysOnPreferenceController.OnPreferenceChangedCallback aodCallback) { final List controllers = new ArrayList<>(); controllers.add(new AmbientDisplayNotificationsPreferenceController(context, config, metricsFeatureProvider)); + controllers.add(new AmbientDisplayAlwaysOnPreferenceController(context, config, + aodCallback)); controllers.add(new DoubleTapScreenPreferenceController(context, lifecycle, config, MY_USER_ID, KEY_AMBIENT_DISPLAY_DOUBLE_TAP)); controllers.add(new PickupGesturePreferenceController(context, lifecycle, config, @@ -64,14 +64,6 @@ public class AmbientDisplaySettings extends DashboardFragment { return controllers; } - @Override - public void onAttach(Context context) { - super.onAttach(context); - final AmbientDisplayAlwaysOnPreferenceController controller = use( - AmbientDisplayAlwaysOnPreferenceController.class); - controller.setConfig(getConfig(context)); - controller.setCallback(this::updatePreferenceStates); - } @Override protected String getLogTag() { @@ -86,7 +78,8 @@ public class AmbientDisplaySettings extends DashboardFragment { @Override protected List createPreferenceControllers(Context context) { return buildPreferenceControllers(context, getLifecycle(), - getConfig(context), mMetricsFeatureProvider); + new AmbientDisplayConfiguration(context), mMetricsFeatureProvider, + this::updatePreferenceStates); } @Override @@ -111,14 +104,7 @@ public class AmbientDisplaySettings extends DashboardFragment { public List createPreferenceControllers( Context context) { return buildPreferenceControllers(context, null, - new AmbientDisplayConfiguration(context), null); + new AmbientDisplayConfiguration(context), null, null); } }; - - private AmbientDisplayConfiguration getConfig(Context context) { - if (mConfig != null) { - mConfig = new AmbientDisplayConfiguration(context); - } - return mConfig; - } } diff --git a/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java index e1c4b70477a..d06ea2ac50c 100644 --- a/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/AmbientDisplayAlwaysOnPreferenceControllerTest.java @@ -17,14 +17,17 @@ package com.android.settings.display; import static com.google.common.truth.Truth.assertThat; - -import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.Context; import android.provider.Settings; +import android.support.v14.preference.SwitchPreference; import com.android.internal.hardware.AmbientDisplayConfiguration; import com.android.settings.search.InlinePayload; @@ -46,6 +49,8 @@ public class AmbientDisplayAlwaysOnPreferenceControllerTest { @Mock private AmbientDisplayConfiguration mConfig; + @Mock + private SwitchPreference mSwitchPreference; private Context mContext; @@ -59,90 +64,95 @@ public class AmbientDisplayAlwaysOnPreferenceControllerTest { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; mContentResolver = mContext.getContentResolver(); - mController = new AmbientDisplayAlwaysOnPreferenceController(mContext, "key"); - mController.setConfig(mConfig); - mController.setCallback(() -> mCallbackInvoked = true); + mController = new AmbientDisplayAlwaysOnPreferenceController(mContext, mConfig, + () -> { + mCallbackInvoked = true; + }); } @Test - public void getAvailabilityStatus_available() { - when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(true); - - assertThat(mController.getAvailabilityStatus()).isEqualTo( - AmbientDisplayAlwaysOnPreferenceController.AVAILABLE); - } - - @Test - public void getAvailabilityStatus_disabled_unsupported() { - when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false); - - assertThat(mController.getAvailabilityStatus()).isEqualTo( - AmbientDisplayAlwaysOnPreferenceController.DISABLED_UNSUPPORTED); - } - - @Test - public void isChecked_enabled() { + public void updateState_enabled() { when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(true); - assertThat(mController.isChecked()).isTrue(); + mController.updateState(mSwitchPreference); + + verify(mSwitchPreference).setChecked(true); } @Test - public void isChecked_disabled() { + public void updateState_disabled() { when(mConfig.alwaysOnEnabled(anyInt())).thenReturn(false); - assertThat(mController.isChecked()).isFalse(); - } + mController.updateState(mSwitchPreference); - @Test - public void setChecked_enabled() { - mController.setChecked(true); - - assertThat(Settings.Secure.getInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, -1)) - .isEqualTo(1); - } - - @Test - public void setChecked_disabled() { - mController.setChecked(false); - - assertThat(Settings.Secure.getInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, -1)) - .isEqualTo(0); + verify(mSwitchPreference).setChecked(false); } @Test public void onPreferenceChange_callback() { assertThat(mCallbackInvoked).isFalse(); - mController.setChecked(true); + mController.onPreferenceChange(mSwitchPreference, true); assertThat(mCallbackInvoked).isTrue(); } @Test - public void testPreferenceController_ProperResultPayloadType() { - when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false); + public void onPreferenceChange_enable() { + mController.onPreferenceChange(mSwitchPreference, true); + + assertThat(Settings.Secure.getInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, -1)) + .isEqualTo(1); + } + + @Test + public void onPreferenceChange_disable() { + mController.onPreferenceChange(mSwitchPreference, false); + + assertThat(Settings.Secure.getInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, -1)) + .isEqualTo(0); + } + + @Test + public void isAvailable_available() { mController = spy(mController); + doReturn(true).when(mController).alwaysOnAvailableForUser(any()); + + assertThat(mController.isAvailable()).isTrue(); + } + + @Test + public void isAvailable_unavailable() { + mController = spy(mController); + doReturn(false).when(mController).alwaysOnAvailableForUser(any()); + + assertThat(mController.isAvailable()).isFalse(); + } + + @Test + public void testPreferenceController_ProperResultPayloadType() { + mController = spy(mController); + doReturn(false).when(mController).alwaysOnAvailableForUser(any()); assertThat(mController.getResultPayload()).isInstanceOf(InlineSwitchPayload.class); } @Test public void testSetValue_updatesCorrectly() { - when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false); mController = spy(mController); + doReturn(false).when(mController).alwaysOnAvailableForUser(any()); final int newValue = 1; Settings.Secure.putInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, 0 /* value */); ((InlinePayload) mController.getResultPayload()).setValue(mContext, newValue); final int updatedValue = Settings.Secure. - getInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, 1 /* default */); + getInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, 1 /* default */); assertThat(updatedValue).isEqualTo(newValue); } @Test public void testGetValue_correctValueReturned() { - when(mConfig.alwaysOnAvailableForUser(anyInt())).thenReturn(false); mController = spy(mController); + doReturn(false).when(mController).alwaysOnAvailableForUser(any()); final int currentValue = 1; Settings.Secure.putInt(mContentResolver, Settings.Secure.DOZE_ALWAYS_ON, currentValue); diff --git a/tests/robotests/src/com/android/settings/display/AmbientDisplaySettingsTest.java b/tests/robotests/src/com/android/settings/display/AmbientDisplaySettingsTest.java deleted file mode 100644 index bab5d410e4d..00000000000 --- a/tests/robotests/src/com/android/settings/display/AmbientDisplaySettingsTest.java +++ /dev/null @@ -1,69 +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.display; - -import static org.mockito.Mockito.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; - -import android.content.Context; - -import com.android.settings.testutils.SettingsRobolectricTestRunner; -import com.android.settingslib.core.AbstractPreferenceController; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; - -@RunWith(SettingsRobolectricTestRunner.class) -public class AmbientDisplaySettingsTest { - - private TestFragment mTestFragment; - - private Context mContext; - - @Before - public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - mTestFragment = spy(new TestFragment()); - } - - @Test - public void onAttach_shouldSetConfigAndCallback() { - final AmbientDisplayAlwaysOnPreferenceController controller = mock( - AmbientDisplayAlwaysOnPreferenceController.class); - doReturn(controller).when(mTestFragment).use( - AmbientDisplayAlwaysOnPreferenceController.class); - - mTestFragment.onAttach(mContext); - - verify(controller).setConfig(any()); - verify(controller).setCallback(any()); - } - - public static class TestFragment extends AmbientDisplaySettings { - @Override - protected T use(Class clazz) { - return super.use(clazz); - } - } -} \ No newline at end of file From b83242c635daa1567f5e26b5a581803b379f4076 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Wed, 23 May 2018 16:10:11 -0400 Subject: [PATCH 17/21] Follow SliceManager API changes Test: make Bug: 78898947 Change-Id: I5a46ccafe36ad2e0fdac745606d9907f07a86d0c (cherry picked from commit 20495a8c367fd793fe8f852694630a919b92184a) --- .../settings/search/DeviceIndexUpdateJobService.java | 12 ++++++------ .../search/DeviceIndexUpdateJobServiceTest.java | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/com/android/settings/search/DeviceIndexUpdateJobService.java b/src/com/android/settings/search/DeviceIndexUpdateJobService.java index 97b0a61ca6b..3eb904119bc 100644 --- a/src/com/android/settings/search/DeviceIndexUpdateJobService.java +++ b/src/com/android/settings/search/DeviceIndexUpdateJobService.java @@ -38,8 +38,8 @@ import java.util.concurrent.CountDownLatch; import androidx.slice.Slice; import androidx.slice.SliceItem; -import androidx.slice.SliceManager; -import androidx.slice.SliceManager.SliceCallback; +import androidx.slice.SliceViewManager; +import androidx.slice.SliceViewManager.SliceCallback; import androidx.slice.SliceMetadata; import androidx.slice.core.SliceQuery; import androidx.slice.widget.ListContent; @@ -80,7 +80,7 @@ public class DeviceIndexUpdateJobService extends JobService { } final DeviceIndexFeatureProvider indexProvider = FeatureFactory.getFactory(this) .getDeviceIndexFeatureProvider(); - final SliceManager manager = getSliceManager(); + final SliceViewManager manager = getSliceViewManager(); final Uri baseUri = new Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(SettingsSliceProvider.SLICE_AUTHORITY) @@ -124,8 +124,8 @@ public class DeviceIndexUpdateJobService extends JobService { jobFinished(params, false); } - protected SliceManager getSliceManager() { - return SliceManager.getInstance(this); + protected SliceViewManager getSliceViewManager() { + return SliceViewManager.getInstance(this); } protected SliceMetadata getMetadata(Slice loadedSlice) { @@ -158,7 +158,7 @@ public class DeviceIndexUpdateJobService extends JobService { return null; } - protected Slice bindSliceSynchronous(SliceManager manager, Uri slice) { + protected Slice bindSliceSynchronous(SliceViewManager manager, Uri slice) { final Slice[] returnSlice = new Slice[1]; CountDownLatch latch = new CountDownLatch(1); SliceCallback callback = new SliceCallback() { diff --git a/tests/robotests/src/com/android/settings/search/DeviceIndexUpdateJobServiceTest.java b/tests/robotests/src/com/android/settings/search/DeviceIndexUpdateJobServiceTest.java index b5de9737db2..1c02b99323d 100644 --- a/tests/robotests/src/com/android/settings/search/DeviceIndexUpdateJobServiceTest.java +++ b/tests/robotests/src/com/android/settings/search/DeviceIndexUpdateJobServiceTest.java @@ -45,7 +45,7 @@ import java.util.ArrayList; import java.util.List; import androidx.slice.Slice; -import androidx.slice.SliceManager; +import androidx.slice.SliceViewManager; import androidx.slice.SliceMetadata; @RunWith(SettingsRobolectricTestRunner.class) @@ -57,17 +57,17 @@ public class DeviceIndexUpdateJobServiceTest { private Activity mActivity; private DeviceIndexUpdateJobService mJob; - private SliceManager mSliceManager; + private SliceViewManager mSliceManager; @Before public void setup() { FakeFeatureFactory.setupForTest(); mActivity = spy(Robolectric.buildActivity(Activity.class).create().visible().get()); mJob = spy(new DeviceIndexUpdateJobService()); - mSliceManager = mock(SliceManager.class); + mSliceManager = mock(SliceViewManager.class); doReturn(mActivity.getPackageName()).when(mJob).getPackageName(); - doReturn(mSliceManager).when(mJob).getSliceManager(); + doReturn(mSliceManager).when(mJob).getSliceViewManager(); doNothing().when(mJob).jobFinished(null, false); } @@ -144,4 +144,4 @@ public class DeviceIndexUpdateJobServiceTest { when(mSliceManager.getSliceDescendants(BASE_URI)).thenReturn(mUris); } -} \ No newline at end of file +} From 23059f5e5aa1a973b4dcc2bcadc6432d3db931f2 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Wed, 30 May 2018 09:50:52 -0700 Subject: [PATCH 18/21] Skip device index job if caller is not Settings app. Change-Id: I96184f111e83477b46ddf321ec74917bab330048 Fixes: 80437512 Fixes: 109713077 Test: robotests (cherry picked from commit 74ba1a51d74a4fb7fc2ccd62fd38087974c20020) (cherry picked from commit 9ecf3e0c1110e6900f63a600e483f8925e366b4c) --- .../search/DeviceIndexFeatureProvider.java | 30 +++++++++-- .../DeviceIndexFeatureProviderTest.java | 50 +++++++++++++------ 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/com/android/settings/search/DeviceIndexFeatureProvider.java b/src/com/android/settings/search/DeviceIndexFeatureProvider.java index c4d3abfcaa8..e6b3e937b85 100644 --- a/src/com/android/settings/search/DeviceIndexFeatureProvider.java +++ b/src/com/android/settings/search/DeviceIndexFeatureProvider.java @@ -21,7 +21,10 @@ import android.app.job.JobInfo; import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; import android.net.Uri; +import android.os.Binder; import android.os.Build; import android.provider.Settings; import android.text.TextUtils; @@ -36,7 +39,6 @@ import java.util.Locale; public interface DeviceIndexFeatureProvider { - String TAG = "DeviceIndex"; String INDEX_VERSION = "settings:index_version"; @@ -57,7 +59,7 @@ public interface DeviceIndexFeatureProvider { default void updateIndex(Context context, boolean force) { if (!isIndexingEnabled()) { - Log.w(TAG, "Skipping: device index is not enabled"); + Log.i(TAG, "Skipping: device index is not enabled"); return; } @@ -66,7 +68,29 @@ public interface DeviceIndexFeatureProvider { return; } + final ComponentName jobComponent = new ComponentName(context.getPackageName(), + DeviceIndexUpdateJobService.class.getName()); + + try { + final int callerUid = Binder.getCallingUid(); + final ServiceInfo si = context.getPackageManager().getServiceInfo(jobComponent, + PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE); + if (si == null) { + Log.w(TAG, "Skipping: No such service " + jobComponent); + return; + } + if (si.applicationInfo.uid != callerUid) { + Log.w(TAG, "Skipping: Uid cannot schedule DeviceIndexUpdate: " + callerUid); + return; + } + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Skipping: error finding DeviceIndexUpdateJobService from packageManager"); + return; + } + if (!force && skipIndex(context)) { + Log.i(TAG, "Skipping: already indexed."); // No need to update. return; } @@ -74,8 +98,6 @@ public interface DeviceIndexFeatureProvider { // Prevent scheduling multiple jobs setIndexState(context); - final ComponentName jobComponent = new ComponentName(context.getPackageName(), - DeviceIndexUpdateJobService.class.getName()); final int jobId = context.getResources().getInteger(R.integer.device_index_update); // Schedule a job so that we know it'll be able to complete, but try to run as // soon as possible. diff --git a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java index ebba3f310ce..b49ef1d0683 100644 --- a/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java +++ b/tests/robotests/src/com/android/settings/search/DeviceIndexFeatureProviderTest.java @@ -15,7 +15,6 @@ package com.android.settings.search; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -23,27 +22,42 @@ import static org.mockito.Mockito.when; import android.app.Activity; import android.app.job.JobScheduler; +import android.os.Binder; import android.provider.Settings; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.Robolectric; +import org.robolectric.shadows.ShadowBinder; @RunWith(SettingsRobolectricTestRunner.class) public class DeviceIndexFeatureProviderTest { + @Mock + private JobScheduler mJobScheduler; private DeviceIndexFeatureProvider mProvider; private Activity mActivity; @Before public void setUp() { + MockitoAnnotations.initMocks(this); + ShadowBinder.reset(); FakeFeatureFactory.setupForTest(); mActivity = spy(Robolectric.buildActivity(Activity.class).create().visible().get()); mProvider = spy(new DeviceIndexFeatureProviderImpl()); + when(mActivity.getSystemService(JobScheduler.class)).thenReturn(mJobScheduler); + } + + @After + public void tearDown() { + ShadowBinder.reset(); } @Test @@ -51,7 +65,7 @@ public class DeviceIndexFeatureProviderTest { when(mProvider.isIndexingEnabled()).thenReturn(false); mProvider.updateIndex(mActivity, false); - verify(mProvider, never()).index(any(), any(), any(), any(), any()); + verify(mJobScheduler, never()).schedule(any()); } @Test @@ -62,19 +76,17 @@ public class DeviceIndexFeatureProviderTest { mProvider.updateIndex(mActivity, false); - verify(mProvider, never()).index(any(), any(), any(), any(), any()); + verify(mJobScheduler, never()).schedule(any()); } @Test public void updateIndex_enabled_provisioned_shouldIndex() { Settings.Global.putInt(mActivity.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 1); - JobScheduler jobScheduler = mock(JobScheduler.class); when(mProvider.isIndexingEnabled()).thenReturn(true); - when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); mProvider.updateIndex(mActivity, false); - verify(jobScheduler).schedule(any()); + verify(mJobScheduler).schedule(any()); } @Test @@ -87,12 +99,22 @@ public class DeviceIndexFeatureProviderTest { Settings.Global.putString(mActivity.getContentResolver(), DeviceIndexFeatureProvider.LANGUAGE.toString(), DeviceIndexFeatureProvider.INDEX_LANGUAGE); - JobScheduler jobScheduler = mock(JobScheduler.class); when(mProvider.isIndexingEnabled()).thenReturn(true); - when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); mProvider.updateIndex(mActivity, false); - verify(jobScheduler).schedule(any()); + verify(mJobScheduler).schedule(any()); + } + + @Test + public void updateIndex_enabled_provisioned_differentUid_shouldNotIndex() { + Settings.Global.putInt(mActivity.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 1); + when(mProvider.isIndexingEnabled()).thenReturn(true); + + ShadowBinder.setCallingUid(Binder.getCallingUid() + 2000); + + mProvider.updateIndex(mActivity, false); + verify(mJobScheduler, never()).schedule(any()); } @Test @@ -102,12 +124,11 @@ public class DeviceIndexFeatureProviderTest { DeviceIndexFeatureProvider.setIndexState(mActivity); Settings.Global.putString(mActivity.getContentResolver(), DeviceIndexFeatureProvider.INDEX_LANGUAGE, "new language"); - JobScheduler jobScheduler = mock(JobScheduler.class); + when(mProvider.isIndexingEnabled()).thenReturn(true); - when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); mProvider.updateIndex(mActivity, false); - verify(jobScheduler).schedule(any()); + verify(mJobScheduler).schedule(any()); } @Test @@ -120,11 +141,8 @@ public class DeviceIndexFeatureProviderTest { // Same build and same language DeviceIndexFeatureProvider.setIndexState(mActivity); - final JobScheduler jobScheduler = mock(JobScheduler.class); - when(mActivity.getSystemService(JobScheduler.class)).thenReturn(jobScheduler); - mProvider.updateIndex(mActivity, false); - verify(jobScheduler, never()).schedule(any()); + verify(mJobScheduler, never()).schedule(any()); } } From 1582ec3db7b2e827a134aaa148f079de36696c9a Mon Sep 17 00:00:00 2001 From: Lei Yu Date: Thu, 28 Jun 2018 14:08:42 -0700 Subject: [PATCH 19/21] Unrestrict app if it been set as device admin app Bug: 110337989 Test: RunSettingsRoboTests Change-Id: I8229bee97d970f8b16351193cfd99ca05ff041bf Merged-In: I8229bee97d970f8b16351193cfd99ca05ff041bf (cherry picked from commit f87897b84cf09da3d25ea0222fce876fdf62f302) --- src/com/android/settings/DeviceAdminAdd.java | 13 +++++++ .../android/settings/DeviceAdminAddTest.java | 37 +++++++++++++++++++ 2 files changed, 50 insertions(+) diff --git a/src/com/android/settings/DeviceAdminAdd.java b/src/com/android/settings/DeviceAdminAdd.java index 0ad882df9a2..72f4aa32cad 100644 --- a/src/com/android/settings/DeviceAdminAdd.java +++ b/src/com/android/settings/DeviceAdminAdd.java @@ -59,6 +59,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.overlay.FeatureFactory; import com.android.settings.users.UserDialogs; import com.android.settingslib.RestrictedLockUtils; @@ -425,6 +426,9 @@ public class DeviceAdminAdd extends Activity { mDPM.setActiveAdmin(mDeviceAdmin.getComponent(), mRefreshing); EventLog.writeEvent(EventLogTags.EXP_DET_DEVICE_ADMIN_ACTIVATED_BY_USER, mDeviceAdmin.getActivityInfo().applicationInfo.uid); + + unrestrictAppIfPossible(BatteryUtils.getInstance(this)); + setResult(Activity.RESULT_OK); } catch (RuntimeException e) { // Something bad happened... could be that it was @@ -446,6 +450,15 @@ public class DeviceAdminAdd extends Activity { finish(); } + void unrestrictAppIfPossible(BatteryUtils batteryUtils) { + // Unrestrict admin app if it is already been restricted + final String packageName = mDeviceAdmin.getComponent().getPackageName(); + final int uid = batteryUtils.getPackageUid(packageName); + if (batteryUtils.isForceAppStandbyEnabled(uid, packageName)) { + batteryUtils.setForceAppStandby(uid, packageName, AppOpsManager.MODE_ALLOWED); + } + } + void continueRemoveAction(CharSequence msg) { if (!mWaitingForRemoveMsg) { return; diff --git a/tests/robotests/src/com/android/settings/DeviceAdminAddTest.java b/tests/robotests/src/com/android/settings/DeviceAdminAddTest.java index 1a4ce89fbcd..1602f15263a 100644 --- a/tests/robotests/src/com/android/settings/DeviceAdminAddTest.java +++ b/tests/robotests/src/com/android/settings/DeviceAdminAddTest.java @@ -18,23 +18,37 @@ package com.android.settings; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.AppOpsManager; +import android.app.admin.DeviceAdminInfo; import android.content.Context; import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; 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; import org.robolectric.Robolectric; @RunWith(SettingsRobolectricTestRunner.class) public class DeviceAdminAddTest { + private static final int UID = 12345; + private static final String PACKAGE_NAME = "com.android.test.device.admin"; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private DeviceAdminInfo mDeviceAdmin; + @Mock + private BatteryUtils mBatteryUtils; private FakeFeatureFactory mFeatureFactory; private DeviceAdminAdd mDeviceAdminAdd; @@ -44,6 +58,10 @@ public class DeviceAdminAddTest { mFeatureFactory = FakeFeatureFactory.setupForTest(); mDeviceAdminAdd = Robolectric.buildActivity(DeviceAdminAdd.class).get(); + + doReturn(UID).when(mBatteryUtils).getPackageUid(PACKAGE_NAME); + when(mDeviceAdmin.getComponent().getPackageName()).thenReturn(PACKAGE_NAME); + mDeviceAdminAdd.mDeviceAdmin = mDeviceAdmin; } @Test @@ -56,4 +74,23 @@ public class DeviceAdminAddTest { verify(mFeatureFactory.metricsFeatureProvider).action(any(Context.class), eq(MetricsProto.MetricsEvent.APP_SPECIAL_PERMISSION_ADMIN_DENY), eq("app")); } + + @Test + public void unrestrictAppIfPossible_appRestricted_unrestrictApp() { + doReturn(true).when(mBatteryUtils).isForceAppStandbyEnabled(UID, PACKAGE_NAME); + + mDeviceAdminAdd.unrestrictAppIfPossible(mBatteryUtils); + + verify(mBatteryUtils).setForceAppStandby(UID, PACKAGE_NAME, AppOpsManager.MODE_ALLOWED); + } + + @Test + public void unrestrictAppIfPossible_appUnrestricted_doNothing() { + doReturn(false).when(mBatteryUtils).isForceAppStandbyEnabled(UID, PACKAGE_NAME); + + mDeviceAdminAdd.unrestrictAppIfPossible(mBatteryUtils); + + verify(mBatteryUtils, never()).setForceAppStandby(UID, PACKAGE_NAME, + AppOpsManager.MODE_ALLOWED); + } } From 0844fb92d8151773c58f808232182e4116708ca2 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Tue, 3 Jul 2018 20:31:42 +0100 Subject: [PATCH 20/21] Use primary user's LOCK_SCREEN_SHOW_NOTIFICATIONS. Only primary user can set LOCK_SCREEN_SHOW_NOTIFICATIONS, profile can only set notifications to be redacted. When the user changes notification settings for a work app, this class is invoked from the profile, meaning it attempts to read LOCK_SCREEN_SHOW_NOTIFICATIONS for the profile, which is not there. As a result the function always returs 0 for work apps. Bug: 111112011 Test: atest packages/apps/Settings/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java Change-Id: Ifb50209ea8ea8fb6639f00ca8b7cf8a4295890ad (cherry picked from commit f14de789f4cc7d145e6011e5a5562876e25c3f31) --- .../VisibilityPreferenceController.java | 6 +++-- .../VisibilityPreferenceControllerTest.java | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/notification/VisibilityPreferenceController.java b/src/com/android/settings/notification/VisibilityPreferenceController.java index dac90ef7be7..8dc802ccdd0 100644 --- a/src/com/android/settings/notification/VisibilityPreferenceController.java +++ b/src/com/android/settings/notification/VisibilityPreferenceController.java @@ -147,8 +147,10 @@ public class VisibilityPreferenceController extends NotificationPreferenceContro } private boolean getLockscreenNotificationsEnabled() { - return Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0) != 0; + final UserInfo parentUser = mUm.getProfileParent(UserHandle.myUserId()); + final int primaryUserId = parentUser != null ? parentUser.id : UserHandle.myUserId(); + return Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, primaryUserId) != 0; } private boolean getLockscreenAllowPrivateNotifications() { diff --git a/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java index e37c852277f..fbc251206dc 100644 --- a/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/notification/VisibilityPreferenceControllerTest.java @@ -208,6 +208,31 @@ public class VisibilityPreferenceControllerTest { .contains(String.valueOf(VISIBILITY_PRIVATE))); } + @Test + public void testUpdateState_noLockScreenNotificationsGloballyInProfile() { + final int primaryUserId = 2; + final UserInfo primaryUserInfo = new UserInfo(primaryUserId, "user 2", 0); + when(mUm.getProfileParent(anyInt())).thenReturn(primaryUserInfo); + + Settings.Secure.putIntForUser(mContext.getContentResolver(), + Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, primaryUserId); + + NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); + NotificationChannel channel = mock(NotificationChannel.class); + mController.onResume(appRow, channel, null, null); + + RestrictedListPreference pref = mock(RestrictedListPreference.class); + mController.updateState(pref); + + ArgumentCaptor argumentCaptor = + ArgumentCaptor.forClass(CharSequence[].class); + verify(pref, times(1)).setEntryValues(argumentCaptor.capture()); + assertFalse(toStringList(argumentCaptor.getValue()) + .contains(String.valueOf(VISIBILITY_NO_OVERRIDE))); + assertFalse(toStringList(argumentCaptor.getValue()) + .contains(String.valueOf(VISIBILITY_PRIVATE))); + } + @Test public void testUpdateState_noPrivateLockScreenNotificationsGlobally() { Settings.Secure.putInt(mContext.getContentResolver(), From af4c772b3083de944c7d71a24aadd703bd1aa79f Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Tue, 31 Jul 2018 14:04:44 -0700 Subject: [PATCH 21/21] Disable changing lock when device is not provisioned. When the device is not yet provisioned and settings is launched: - disable the entry point for changing device lock - remove the search panel from settings home page - remove the search menu Bug: 110034419 Test: make RunSettingsRoboTests Change-Id: Ieb7eb0e8699229ec0824ccc19d7b958ac44965a2 Merged-In: Ieb7eb0e8699229ec0824ccc19d7b958ac44965a2 (cherry picked from commit 770f4abf9de2bb7d74497cc4b5f6795023229ef2) --- .../android/settings/SettingsActivity.java | 5 +- .../settings/password/ChooseLockGeneric.java | 9 +++ .../password/SetupChooseLockGeneric.java | 5 ++ .../actionbar/SearchMenuController.java | 4 ++ .../settings/SettingsActivityTest.java | 40 ++++++++++++ .../password/ChooseLockGenericTest.java | 65 +++++++++++++++++++ .../actionbar/SearchMenuControllerTest.java | 24 ++++++- 7 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java index 971ae040661..29cd77ade61 100644 --- a/src/com/android/settings/SettingsActivity.java +++ b/src/com/android/settings/SettingsActivity.java @@ -291,8 +291,10 @@ public class SettingsActivity extends SettingsDrawerActivity launchSettingFragment(initialFragmentName, isSubSettings, intent); } + final boolean deviceProvisioned = Utils.isDeviceProvisioned(this); if (mIsShowingDashboard) { - findViewById(R.id.search_bar).setVisibility(View.VISIBLE); + findViewById(R.id.search_bar).setVisibility( + deviceProvisioned ? View.VISIBLE : View.INVISIBLE); findViewById(R.id.action_bar).setVisibility(View.GONE); final Toolbar toolbar = findViewById(R.id.search_action_bar); FeatureFactory.getFactory(this).getSearchFeatureProvider() @@ -311,7 +313,6 @@ public class SettingsActivity extends SettingsDrawerActivity ActionBar actionBar = getActionBar(); if (actionBar != null) { - boolean deviceProvisioned = Utils.isDeviceProvisioned(this); actionBar.setDisplayHomeAsUpEnabled(deviceProvisioned); actionBar.setHomeButtonEnabled(deviceProvisioned); actionBar.setDisplayShowTitleEnabled(!mIsShowingDashboard); diff --git a/src/com/android/settings/password/ChooseLockGeneric.java b/src/com/android/settings/password/ChooseLockGeneric.java index 62978b3089b..1a8afd02cc1 100644 --- a/src/com/android/settings/password/ChooseLockGeneric.java +++ b/src/com/android/settings/password/ChooseLockGeneric.java @@ -164,6 +164,11 @@ public class ChooseLockGeneric extends SettingsActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + final Activity activity = getActivity(); + if (!Utils.isDeviceProvisioned(activity) && !canRunBeforeDeviceProvisioned()) { + activity.finish(); + return; + } String chooseLockAction = getActivity().getIntent().getAction(); mFingerprintManager = Utils.getFingerprintManagerOrNull(getActivity()); @@ -249,6 +254,10 @@ public class ChooseLockGeneric extends SettingsActivity { addHeaderView(); } + protected boolean canRunBeforeDeviceProvisioned() { + return false; + } + protected void addHeaderView() { if (mForFingerprint) { setHeaderView(R.layout.choose_lock_generic_fingerprint_header); diff --git a/src/com/android/settings/password/SetupChooseLockGeneric.java b/src/com/android/settings/password/SetupChooseLockGeneric.java index 179bd797cb7..885f9dfb420 100644 --- a/src/com/android/settings/password/SetupChooseLockGeneric.java +++ b/src/com/android/settings/password/SetupChooseLockGeneric.java @@ -129,6 +129,11 @@ public class SetupChooseLockGeneric extends ChooseLockGeneric { return layout.onCreateRecyclerView(inflater, parent, savedInstanceState); } + @Override + protected boolean canRunBeforeDeviceProvisioned() { + return true; + } + /*** * Disables preferences that are less secure than required quality and shows only secure * screen lock options here. diff --git a/src/com/android/settings/search/actionbar/SearchMenuController.java b/src/com/android/settings/search/actionbar/SearchMenuController.java index 1729ccdb39a..131f7884fc7 100644 --- a/src/com/android/settings/search/actionbar/SearchMenuController.java +++ b/src/com/android/settings/search/actionbar/SearchMenuController.java @@ -25,6 +25,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.SearchFeatureProvider; import com.android.settingslib.core.lifecycle.LifecycleObserver; @@ -52,6 +53,9 @@ public class SearchMenuController implements LifecycleObserver, OnCreateOptionsM @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + if (!Utils.isDeviceProvisioned(mHost.getContext())) { + return; + } if (menu == null) { return; } diff --git a/tests/robotests/src/com/android/settings/SettingsActivityTest.java b/tests/robotests/src/com/android/settings/SettingsActivityTest.java index 2096629a63d..54b01eab76a 100644 --- a/tests/robotests/src/com/android/settings/SettingsActivityTest.java +++ b/tests/robotests/src/com/android/settings/SettingsActivityTest.java @@ -16,6 +16,7 @@ package com.android.settings; +import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.doReturn; @@ -27,17 +28,25 @@ import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.app.FragmentManager; import android.app.FragmentTransaction; +import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; +import android.os.Bundle; +import android.provider.Settings.Global; +import android.view.View; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.SettingsShadowResources; +import com.android.settings.testutils.shadow.SettingsShadowResourcesImpl; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) public class SettingsActivityTest { @@ -49,15 +58,46 @@ public class SettingsActivityTest { @Mock private Bitmap mBitmap; private SettingsActivity mActivity; + private Context mContext; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; mActivity = spy(new SettingsActivity()); doReturn(mBitmap).when(mActivity).getBitmapFromXmlResource(anyInt()); } + @Test + @Config(shadows = { + SettingsShadowResourcesImpl.class, + SettingsShadowResources.SettingsShadowTheme.class, + }) + public void onCreate_deviceNotProvisioned_shouldDisableSearch() { + Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 0); + final Intent intent = new Intent(mContext, Settings.class); + final SettingsActivity activity = + Robolectric.buildActivity(SettingsActivity.class, intent).create(Bundle.EMPTY).get(); + + assertThat(activity.findViewById(R.id.search_bar).getVisibility()) + .isEqualTo(View.INVISIBLE); + } + + @Test + @Config(shadows = { + SettingsShadowResourcesImpl.class, + SettingsShadowResources.SettingsShadowTheme.class, + }) + public void onCreate_deviceProvisioned_shouldEnableSearch() { + Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 1); + final Intent intent = new Intent(mContext, Settings.class); + final SettingsActivity activity = + Robolectric.buildActivity(SettingsActivity.class, intent).create(Bundle.EMPTY).get(); + + assertThat(activity.findViewById(R.id.search_bar).getVisibility()).isEqualTo(View.VISIBLE); + } + @Test public void launchSettingFragment_nullExtraShowFragment_shouldNotCrash() { when(mActivity.getFragmentManager()).thenReturn(mFragmentManager); diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java new file mode 100644 index 00000000000..7a14896a8bb --- /dev/null +++ b/tests/robotests/src/com/android/settings/password/ChooseLockGenericTest.java @@ -0,0 +1,65 @@ +/* + * 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.password; + +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.app.Activity; +import android.content.Context; +import android.os.Bundle; +import android.provider.Settings.Global; + +import com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settings.testutils.shadow.SettingsShadowResources; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +public class ChooseLockGenericTest { + + @After + public void tearDown() { + Global.putInt(RuntimeEnvironment.application.getContentResolver(), + Global.DEVICE_PROVISIONED, 1); + } + + @Test + @Config(shadows = SettingsShadowResources.SettingsShadowTheme.class) + public void onCreate_deviceNotProvisioned_shouldFinishActivity() { + final Context context = RuntimeEnvironment.application; + Global.putInt(context.getContentResolver(), Global.DEVICE_PROVISIONED, 0); + final Activity activity = mock(Activity.class); + when(activity.getContentResolver()).thenReturn(context.getContentResolver()); + when(activity.getTheme()).thenReturn(context.getTheme()); + + final ChooseLockGenericFragment fragment = spy(new ChooseLockGenericFragment()); + when(fragment.getActivity()).thenReturn(activity); + when(fragment.getArguments()).thenReturn(Bundle.EMPTY); + + fragment.onCreate(Bundle.EMPTY); + verify(activity).finish(); + } + +} diff --git a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java index 7ff4accb178..9900df292bc 100644 --- a/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java +++ b/tests/robotests/src/com/android/settings/search/actionbar/SearchMenuControllerTest.java @@ -17,11 +17,14 @@ package com.android.settings.search.actionbar; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; +import android.content.Context; import android.os.Bundle; +import android.provider.Settings.Global; import android.view.Menu; import android.view.MenuItem; @@ -35,6 +38,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; @RunWith(SettingsRobolectricTestRunner.class) public class SearchMenuControllerTest { @@ -43,12 +47,16 @@ public class SearchMenuControllerTest { private Menu mMenu; private TestPreferenceFragment mPreferenceHost; private ObservableFragment mHost; + private Context mContext; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mHost = new ObservableFragment(); + mContext = RuntimeEnvironment.application; + mHost = spy(new ObservableFragment()); + when(mHost.getContext()).thenReturn(mContext); mPreferenceHost = new TestPreferenceFragment(); + Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 1); when(mMenu.add(Menu.NONE, Menu.NONE, 0 /* order */, R.string.search_menu)) .thenReturn(mock(MenuItem.class)); @@ -81,9 +89,23 @@ public class SearchMenuControllerTest { verifyZeroInteractions(mMenu); } + @Test + public void init_deviceNotProvisioned_shouldNotAddMenu() { + Global.putInt(mContext.getContentResolver(), Global.DEVICE_PROVISIONED, 0); + SearchMenuController.init(mHost); + mHost.getLifecycle().onCreateOptionsMenu(mMenu, null /* inflater */); + + verifyZeroInteractions(mMenu); + } + private static class TestPreferenceFragment extends ObservablePreferenceFragment { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { } + + @Override + public Context getContext() { + return RuntimeEnvironment.application; + } } }