From c069669ddfd0d550066e06b915444c03a10a89b6 Mon Sep 17 00:00:00 2001 From: Eric Schwarzenbach Date: Wed, 20 Sep 2017 16:34:23 -0700 Subject: [PATCH 1/6] Fix "Add Network" button on SavedAccessPoints page. The old onSubmit was a no-op. It now correctly pipes onSubmit to WifiManager#save() with the new WifiConfiguration. On successful save, it displays the new network in the list, and on failure, it displays a toast indicating that the save action failed. Adds a test for the WifiDialog behaviors on this page. Bug: 66177765 Test: make RunSettingsRoboTests, manual - tested with Wifi enabled and disabled, and with networks that were visible and not. Change-Id: I27446aa49bc9efaf1ea1d6c6158928b62ce01ba2 Merged-In: I27446aa49bc9efaf1ea1d6c6158928b62ce01ba2 --- .../wifi/SavedAccessPointsWifiSettings.java | 20 ++++- .../SavedAccessPointsWifiSettingsTest.java | 88 +++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 tests/robotests/src/com/android/settings/wifi/SavedAccessPointsWifiSettingsTest.java diff --git a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java index 1a95525fe24..5cb367995c6 100644 --- a/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java +++ b/src/com/android/settings/wifi/SavedAccessPointsWifiSettings.java @@ -17,6 +17,7 @@ package com.android.settings.wifi; import android.annotation.Nullable; +import android.app.Activity; import android.app.Dialog; import android.content.Context; import android.content.res.Resources; @@ -28,6 +29,7 @@ import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.util.Log; +import android.widget.Toast; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; @@ -78,6 +80,22 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment } }; + private final WifiManager.ActionListener mSaveListener = new WifiManager.ActionListener() { + @Override + public void onSuccess() { + initPreferences(); + } + @Override + public void onFailure(int reason) { + Activity activity = getActivity(); + if (activity != null) { + Toast.makeText(activity, + R.string.wifi_failed_save_message, + Toast.LENGTH_SHORT).show(); + } + } + }; + private WifiDialog mDialog; private WifiManager mWifiManager; private AccessPoint mDlgAccessPoint; @@ -251,7 +269,7 @@ public class SavedAccessPointsWifiSettings extends SettingsPreferenceFragment @Override public void onSubmit(WifiDialog dialog) { - // Ignored + mWifiManager.save(dialog.getController().getConfig(), mSaveListener); } @Override diff --git a/tests/robotests/src/com/android/settings/wifi/SavedAccessPointsWifiSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/SavedAccessPointsWifiSettingsTest.java new file mode 100644 index 00000000000..8a72d25fe95 --- /dev/null +++ b/tests/robotests/src/com/android/settings/wifi/SavedAccessPointsWifiSettingsTest.java @@ -0,0 +1,88 @@ +/* + * 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.wifi; + +import android.app.Activity; +import android.content.Context; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.net.wifi.WifiManager.ActionListener; + +import com.android.settings.TestConfig; +import com.android.settingslib.wifi.AccessPoint; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +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 com.android.settings.testutils.SettingsRobolectricTestRunner; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SavedAccessPointsWifiSettingsTest { + + @Mock private Activity mActivity; + @Mock private WifiManager mockWifiManager; + @Mock private WifiDialog mockWifiDialog; + @Mock private WifiConfigController mockConfigController; + @Mock private WifiConfiguration mockWifiConfiguration; + @Mock private AccessPoint mockAccessPoint; + + private Context mContext; + + private SavedAccessPointsWifiSettings mFragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mFragment = new SavedAccessPointsWifiSettings(); + when(mockWifiDialog.getController()).thenReturn(mockConfigController); + when(mockConfigController.getConfig()).thenReturn(mockWifiConfiguration); + + ReflectionHelpers.setField(mFragment, "mWifiManager", mockWifiManager); + } + + @Test + public void onSubmit_shouldInvokeSaveApi() { + mFragment.onSubmit(mockWifiDialog); + verify(mockWifiManager).save(eq(mockWifiConfiguration), any(ActionListener.class)); + } + + @Test + public void onForget_shouldInvokeForgetApi() { + ReflectionHelpers.setField(mFragment, "mSelectedAccessPoint", mockAccessPoint); + when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfiguration); + + mFragment.onForget(mockWifiDialog); + + verify(mockWifiManager).forget(eq(mockWifiConfiguration.networkId), any(ActionListener.class)); + } +} From de603ea469c98668db1d424f56d88a22ce6b65d3 Mon Sep 17 00:00:00 2001 From: Doris Ling Date: Wed, 4 Oct 2017 16:59:28 -0700 Subject: [PATCH 2/6] Add space around the data usage warning spinner. Use a custom item layout for the data usage warning unit selection spinner to make the touch target bigger. Change-Id: I2d73dc3ab4c99cea8f8c791c8c1346240456d6aa Fixes: 66414539 Test: visual --- res/layout/data_usage_spinner_item.xml | 29 +++++++++++++++++++ .../datausage/BillingCycleSettings.java | 2 +- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 res/layout/data_usage_spinner_item.xml diff --git a/res/layout/data_usage_spinner_item.xml b/res/layout/data_usage_spinner_item.xml new file mode 100644 index 00000000000..1706edfc508 --- /dev/null +++ b/res/layout/data_usage_spinner_item.xml @@ -0,0 +1,29 @@ + + + + + \ No newline at end of file diff --git a/src/com/android/settings/datausage/BillingCycleSettings.java b/src/com/android/settings/datausage/BillingCycleSettings.java index d00749d837e..fb8119c60e4 100644 --- a/src/com/android/settings/datausage/BillingCycleSettings.java +++ b/src/com/android/settings/datausage/BillingCycleSettings.java @@ -264,7 +264,7 @@ public class BillingCycleSettings extends DataUsageBase implements formatter.getUnitDisplayName(MeasureUnit.GIGABYTE) }; final ArrayAdapter adapter = new ArrayAdapter( - getContext(), android.R.layout.simple_spinner_item, unitNames); + getContext(), R.layout.data_usage_spinner_item, unitNames); type.setAdapter(adapter); if (bytes > 1.5f * GB_IN_BYTES) { From 33b8f3e6f8736998e2b3b856dcb26de74961fda9 Mon Sep 17 00:00:00 2001 From: jeffreyhuang Date: Thu, 5 Oct 2017 17:05:56 -0700 Subject: [PATCH 3/6] Introduce SelectUsbConfigPreferenceController - Create new SelectUsbConfigController - Create controller inside the DashboardFragment - Port logic from DevelopmentSettings into the controller Bug: 34203528 Test: make RunSettingsRoboTests -j40 Change-Id: I8d6b4eb2e8a90adb7f8bdf4aeec0f5929e8165b2 --- .../DevelopmentSettingsDashboardFragment.java | 2 +- .../SelectUsbConfigPreferenceController.java | 139 +++++++++++++++ ...lectUsbConfigPreferenceControllerTest.java | 162 ++++++++++++++++++ 3 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/development/SelectUsbConfigPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/development/SelectUsbConfigPreferenceControllerTest.java diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index 2d9c5f37935..a6e035d5d1f 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -280,7 +280,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new WifiRoamScansPreferenceController(context)); controllers.add(new MobileDataAlwaysOnPreferenceController(context)); controllers.add(new TetheringHardwareAccelPreferenceController(context)); - // select usb configuration + controllers.add(new SelectUsbConfigPreferenceController(context, lifecycle)); controllers.add(new BluetoothDeviceNoNamePreferenceController(context)); controllers.add(new BluetoothAbsoluteVolumePreferenceController(context)); controllers.add(new BluetoothInbandRingingPreferenceController(context)); diff --git a/src/com/android/settings/development/SelectUsbConfigPreferenceController.java b/src/com/android/settings/development/SelectUsbConfigPreferenceController.java new file mode 100644 index 00000000000..41fe6a3967e --- /dev/null +++ b/src/com/android/settings/development/SelectUsbConfigPreferenceController.java @@ -0,0 +1,139 @@ +/* + * 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.development; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.usb.UsbManager; +import android.os.Bundle; +import android.support.annotation.VisibleForTesting; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.text.TextUtils; + +import com.android.settings.R; +import com.android.settingslib.core.lifecycle.Lifecycle; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnCreate; +import com.android.settingslib.core.lifecycle.events.OnDestroy; + +public class SelectUsbConfigPreferenceController extends + DeveloperOptionsPreferenceController implements + Preference.OnPreferenceChangeListener, LifecycleObserver, OnCreate, OnDestroy { + + private static final String USB_CONFIGURATION_KEY = "select_usb_configuration"; + + private final String[] mListValues; + private final String[] mListSummaries; + private final UsbManager mUsbManager; + private BroadcastReceiver mUsbReceiver; + private ListPreference mPreference; + + public SelectUsbConfigPreferenceController(Context context, Lifecycle lifecycle) { + super(context); + + mListValues = context.getResources().getStringArray(R.array.usb_configuration_values); + mListSummaries = context.getResources().getStringArray(R.array.usb_configuration_titles); + mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE); + mUsbReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mPreference != null) { + updateUsbConfigurationValues(); + } + } + }; + if (lifecycle != null) { + lifecycle.addObserver(this); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + IntentFilter filter = new IntentFilter(); + filter.addAction(UsbManager.ACTION_USB_STATE); + mContext.registerReceiver(mUsbReceiver, filter); + } + + @Override + public String getPreferenceKey() { + return USB_CONFIGURATION_KEY; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + + mPreference = (ListPreference) screen.findPreference(getPreferenceKey()); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + writeUsbConfigurationOption(newValue.toString()); + updateUsbConfigurationValues(); + return true; + } + + @Override + public void updateState(Preference preference) { + updateUsbConfigurationValues(); + } + + @Override + public void onDestroy() { + mContext.unregisterReceiver(mUsbReceiver); + } + + @Override + protected void onDeveloperOptionsSwitchEnabled() { + mPreference.setEnabled(true); + } + + @Override + protected void onDeveloperOptionsSwitchDisabled() { + mPreference.setEnabled(false); + } + + @VisibleForTesting + void setCurrentFunction(String newValue, boolean usbDataUnlocked) { + mUsbManager.setCurrentFunction(newValue, usbDataUnlocked); + } + + private void updateUsbConfigurationValues() { + int index = 0; + for (int i = 0; i < mListValues.length; i++) { + if (mUsbManager.isFunctionEnabled(mListValues[i])) { + index = i; + break; + } + } + mPreference.setValue(mListValues[index]); + mPreference.setSummary(mListSummaries[index]); + } + + private void writeUsbConfigurationOption(String newValue) { + if (TextUtils.equals(newValue, "none")) { + setCurrentFunction(newValue, false); + } else { + setCurrentFunction(newValue, true); + } + } + +} diff --git a/tests/robotests/src/com/android/settings/development/SelectUsbConfigPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/SelectUsbConfigPreferenceControllerTest.java new file mode 100644 index 00000000000..8b96af0f7e9 --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/SelectUsbConfigPreferenceControllerTest.java @@ -0,0 +1,162 @@ +/* + * 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.development; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +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.Context; +import android.hardware.usb.UsbManager; +import android.support.v7.preference.ListPreference; +import android.support.v7.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.TestConfig; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class SelectUsbConfigPreferenceControllerTest { + + @Mock + private ListPreference mPreference; + @Mock + private PreferenceScreen mScreen; + @Mock + private UsbManager mUsbManager; + + private Context mContext; + private Lifecycle mLifecycle; + private SelectUsbConfigPreferenceController mController; + + /** + * Array Values Key + * + * 0: Charging + * 1: MTP + * 2: PTP + * 3: RNDIS + * 4: Audio Source + * 5: MIDI + */ + private String[] mValues; + private String[] mSummaries; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mLifecycle = new Lifecycle(); + mContext = spy(RuntimeEnvironment.application); + doReturn(mUsbManager).when(mContext).getSystemService(Context.USB_SERVICE); + mValues = mContext.getResources().getStringArray(R.array.usb_configuration_values); + mSummaries = mContext.getResources().getStringArray(R.array.usb_configuration_titles); + mController = spy(new SelectUsbConfigPreferenceController(mContext, mLifecycle)); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + mController.displayPreference(mScreen); + + } + + @Test + public void onPreferenceChange_setCharging_shouldEnableCharging() { + when(mUsbManager.isFunctionEnabled(mValues[0])).thenReturn(true); + doNothing().when(mController).setCurrentFunction(anyString(), anyBoolean()); + mController.onPreferenceChange(mPreference, mValues[0]); + + verify(mController).setCurrentFunction(mValues[0], false /* usb data unlock */); + } + + @Test + public void onPreferenceChange_setMtp_shouldEnableMtp() { + when(mUsbManager.isFunctionEnabled(mValues[1])).thenReturn(true); + doNothing().when(mController).setCurrentFunction(anyString(), anyBoolean()); + mController.onPreferenceChange(mPreference, mValues[1]); + + verify(mController).setCurrentFunction(mValues[1], true /* usb data unlock */); + } + + @Test + public void updateState_chargingEnabled_shouldSetPreferenceToCharging() { + when(mUsbManager.isFunctionEnabled(mValues[0])).thenReturn(true); + + mController.updateState(mPreference); + + verify(mPreference).setValue(mValues[0]); + verify(mPreference).setSummary(mSummaries[0]); + } + + @Test + public void updateState_RndisEnabled_shouldEnableRndis() { + when(mUsbManager.isFunctionEnabled(mValues[3])).thenReturn(true); + + mController.updateState(mPreference); + + verify(mPreference).setValue(mValues[3]); + verify(mPreference).setSummary(mSummaries[3]); + } + + @Test + public void updateState_noValueSet_shouldEnableChargingAsDefault() { + mController.updateState(mPreference); + + verify(mPreference).setValue(mValues[0]); + verify(mPreference).setSummary(mSummaries[0]); + } + + @Test + public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() { + mController.onDeveloperOptionsSwitchDisabled(); + + verify(mPreference).setEnabled(false); + } + + @Test + public void onDeveloperOptionsSwitchEnabled_shouldEnablePreference() { + mController.onDeveloperOptionsSwitchEnabled(); + + verify(mPreference).setEnabled(true); + } + + @Test + public void onCreate_shouldRegisterReceiver() { + mLifecycle.onCreate(null /* bundle */); + + verify(mContext).registerReceiver(any(), any()); + } + + @Test + public void onDestroy_shouldUnregisterReceiver() { + doNothing().when(mContext).unregisterReceiver(any()); + mLifecycle.onDestroy(); + + verify(mContext).unregisterReceiver(any()); + } +} From 13ce22080776c708f603e4439023942298f8e1d3 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Thu, 5 Oct 2017 17:50:14 -0700 Subject: [PATCH 4/6] Log cleanup: remove unnecessary logging for suggestions - Remove show_suggestion logging in DashboardAdapater. Showing suggestion is logged inside SuggestionAdapter during onBind. - Remove hide_suggestion logging. It's not used by anyone. - Move SuggestionLogHelper into SuggestionFeatureProvider Bug: 65065268 Test: robotests Change-Id: I1e7929d739b79527d2ae01c25177676f6be6ddff --- .../settings/dashboard/DashboardAdapter.java | 64 +--- .../settings/dashboard/DashboardSummary.java | 3 - .../suggestions/SuggestionAdapter.java | 10 +- .../SuggestionFeatureProvider.java | 9 + .../SuggestionFeatureProviderImpl.java | 11 +- .../suggestions/SuggestionLogHelper.java | 29 -- .../dashboard/DashboardAdapterTest.java | 293 +----------------- .../suggestions/SuggestionAdapterTest.java | 23 +- .../SuggestionFeatureProviderImplTest.java | 16 + .../suggestions/SuggestionLogHelperTest.java | 47 --- 10 files changed, 63 insertions(+), 442 deletions(-) delete mode 100644 src/com/android/settings/dashboard/suggestions/SuggestionLogHelper.java delete mode 100644 tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionLogHelperTest.java diff --git a/src/com/android/settings/dashboard/DashboardAdapter.java b/src/com/android/settings/dashboard/DashboardAdapter.java index 9c61873cb99..d4397dc1c13 100644 --- a/src/com/android/settings/dashboard/DashboardAdapter.java +++ b/src/com/android/settings/dashboard/DashboardAdapter.java @@ -31,7 +31,6 @@ import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; -import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -47,11 +46,9 @@ import com.android.settings.dashboard.DashboardData.SuggestionConditionHeaderDat import com.android.settings.dashboard.conditional.Condition; import com.android.settings.dashboard.conditional.ConditionAdapter; import com.android.settings.dashboard.suggestions.SuggestionAdapter; -import com.android.settings.dashboard.suggestions.SuggestionController; import com.android.settings.dashboard.suggestions.SuggestionControllerMixin; import com.android.settings.dashboard.suggestions.SuggestionDismissController; import com.android.settings.dashboard.suggestions.SuggestionFeatureProvider; -import com.android.settings.dashboard.suggestions.SuggestionLogHelper; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.Utils; import com.android.settingslib.drawer.DashboardCategory; @@ -164,24 +161,6 @@ public class DashboardAdapter extends RecyclerView.Adapter shownSuggestions = null; - final int mode = mDashboardData.getSuggestionConditionMode(); - if (mode == DashboardData.HEADER_MODE_DEFAULT) { - shownSuggestions = suggestions.subList(0, - Math.min(suggestions.size(), DashboardData.DEFAULT_SUGGESTION_COUNT)); - } else if (mode != DashboardData.HEADER_MODE_COLLAPSED) { - shownSuggestions = suggestions; - } - if (shownSuggestions != null) { - for (Tile suggestion : shownSuggestions) { - final String identifier = mSuggestionFeatureProvider.getSuggestionIdentifier( - mContext, suggestion); - mMetricsFeatureProvider.action( - mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, identifier, - getSuggestionTaggedData()); - mSuggestionsShownLogged.add(identifier); - } - } } public void setSuggestionsV2(List data) { @@ -191,7 +170,6 @@ public class DashboardAdapter extends RecyclerView.Adapter suggestions = mDashboardData.getSuggestions(); - if (suggestions == null) { - return; - } - for (Tile suggestion : suggestions) { - final String suggestionId = mSuggestionFeatureProvider.getSuggestionIdentifier( - mContext, suggestion); - if (!mSuggestionsShownLogged.contains(suggestionId)) { - mMetricsFeatureProvider.action( - mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, suggestionId, - getSuggestionTaggedData()); - mSuggestionsShownLogged.add(suggestionId); - } - } - } - @VisibleForTesting void onBindSuggestionConditionHeader(final SuggestionAndConditionHeaderHolder holder, SuggestionConditionHeaderData data) { @@ -460,9 +405,7 @@ public class DashboardAdapter extends RecyclerView.Adapter { - if (moreSuggestions) { - logSuggestions(); - } else if (hasConditions) { + if (hasConditions) { mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_SETTINGS_CONDITION_EXPAND, true); } @@ -587,11 +530,6 @@ public class DashboardAdapter extends RecyclerView.Adapter[] getSuggestionTaggedData() { - return SuggestionLogHelper.getSuggestionTaggedData( - mSuggestionFeatureProvider.isSmartSuggestionEnabled(mContext)); - } - public static class IconCache { private final Context mContext; private final ArrayMap mMap = new ArrayMap<>(); diff --git a/src/com/android/settings/dashboard/DashboardSummary.java b/src/com/android/settings/dashboard/DashboardSummary.java index 4810c7227b3..30a2fce8d7e 100644 --- a/src/com/android/settings/dashboard/DashboardSummary.java +++ b/src/com/android/settings/dashboard/DashboardSummary.java @@ -152,9 +152,6 @@ public class DashboardSummary extends InstrumentedFragment mMetricsFeatureProvider.hidden(getContext(), c.getMetricsConstant()); } } - if (!getActivity().isChangingConfigurations()) { - mAdapter.onPause(); - } } @Override diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java index 2a9463fe929..8502fa7f2cf 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionAdapter.java @@ -21,7 +21,6 @@ import android.service.settings.suggestions.Suggestion; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.util.Log; -import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -131,7 +130,7 @@ public class SuggestionAdapter extends RecyclerView.Adapter if (!mSuggestionsShownLogged.contains(suggestionId)) { mMetricsFeatureProvider.action( mContext, MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, suggestionId, - getSuggestionTaggedData()); + mSuggestionFeatureProvider.getLoggingTaggedData(mContext)); mSuggestionsShownLogged.add(suggestionId); } if (suggestion.remoteViews != null) { @@ -165,7 +164,7 @@ public class SuggestionAdapter extends RecyclerView.Adapter clickHandler.setOnClickListener(v -> { mMetricsFeatureProvider.action(mContext, MetricsEvent.ACTION_SETTINGS_SUGGESTION, suggestionId, - getSuggestionTaggedData()); + mSuggestionFeatureProvider.getLoggingTaggedData(mContext)); ((SettingsActivity) mContext).startSuggestion(suggestion.intent); }); } @@ -237,11 +236,6 @@ public class SuggestionAdapter extends RecyclerView.Adapter notifyDataSetChanged(); } - private Pair[] getSuggestionTaggedData() { - return SuggestionLogHelper.getSuggestionTaggedData( - mSuggestionFeatureProvider.isSmartSuggestionEnabled(mContext)); - } - public void removeSuggestion(Suggestion suggestion) { mSuggestionsV2.remove(suggestion); notifyDataSetChanged(); diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java index 0f8bccc660d..f9114011a0e 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProvider.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.service.settings.suggestions.Suggestion; import android.support.annotation.NonNull; +import android.util.Pair; import com.android.settingslib.drawer.Tile; import com.android.settingslib.suggestions.SuggestionParser; @@ -93,6 +94,14 @@ public interface SuggestionFeatureProvider { /** * Returns an identifier for the suggestion + * + * @deprecated in favor or {@link Suggestion#getId()} */ + @Deprecated String getSuggestionIdentifier(Context context, Tile suggestion); + + /** + * Returns common tagged data for suggestion logging. + */ + Pair[] getLoggingTaggedData(Context context); } diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java index 02a9223fec6..783987dc8b0 100644 --- a/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java +++ b/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImpl.java @@ -170,8 +170,7 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider if (parser == null || suggestion == null || context == null) { return; } - final Pair[] taggedData = - SuggestionLogHelper.getSuggestionTaggedData(isSmartSuggestionEnabled(context)); + final Pair[] taggedData = getLoggingTaggedData(context); mMetricsFeatureProvider.action( context, MetricsEvent.ACTION_SETTINGS_DISMISS_SUGGESTION, @@ -213,6 +212,14 @@ public class SuggestionFeatureProviderImpl implements SuggestionFeatureProvider return packageName; } + @Override + public Pair[] getLoggingTaggedData(Context context) { + final boolean isSmartSuggestionEnabled = isSmartSuggestionEnabled(context); + return new Pair[]{Pair.create( + MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, + isSmartSuggestionEnabled ? 1 : 0)}; + } + @VisibleForTesting boolean hasUsedNightDisplay(Context context) { final ContentResolver cr = context.getContentResolver(); diff --git a/src/com/android/settings/dashboard/suggestions/SuggestionLogHelper.java b/src/com/android/settings/dashboard/suggestions/SuggestionLogHelper.java deleted file mode 100644 index 339392fa780..00000000000 --- a/src/com/android/settings/dashboard/suggestions/SuggestionLogHelper.java +++ /dev/null @@ -1,29 +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.dashboard.suggestions; - -import android.util.Pair; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; - -public class SuggestionLogHelper { - - public static Pair[] getSuggestionTaggedData(boolean enabled) { - return new Pair[]{ - Pair.create( - MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, enabled ? 1 : 0)}; - } -} diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java index 595a9c6f739..14da5d6cd79 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardAdapterTest.java @@ -24,7 +24,6 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -39,12 +38,10 @@ import android.os.Bundle; import android.service.settings.suggestions.Suggestion; import android.support.v7.widget.RecyclerView; import android.util.DisplayMetrics; -import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.widget.RelativeLayout; -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.TestConfig; @@ -61,8 +58,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; @@ -88,12 +83,6 @@ public class DashboardAdapterTest { private Condition mCondition; @Mock private Resources mResources; - @Captor - private ArgumentCaptor mActionCategoryCaptor = ArgumentCaptor.forClass(Integer.class); - @Captor - private ArgumentCaptor mActionPackageCaptor = ArgumentCaptor.forClass(String.class); - @Captor - private ArgumentCaptor mTaggedDataCaptor = ArgumentCaptor.forClass(Pair.class); private FakeFeatureFactory mFactory; private DashboardAdapter mDashboardAdapter; private DashboardAdapter.SuggestionAndConditionHeaderHolder mSuggestionHolder; @@ -110,7 +99,7 @@ public class DashboardAdapterTest { .getSuggestionIdentifier(any(Context.class), any(Tile.class))) .thenAnswer(invocation -> { final Object[] args = invocation.getArguments(); - return ((Tile)args[1]).intent.getComponent().getPackageName(); + return ((Tile) args[1]).intent.getComponent().getPackageName(); }); when(mContext.getResources()).thenReturn(mResources); @@ -125,282 +114,6 @@ public class DashboardAdapterTest { when(mView.getTag()).thenReturn(mCondition); } - @Test - public void testSuggestionsLogs_NotExpanded() { - setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); - - verify(mFactory.metricsFeatureProvider, times(2)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly("pkg1", "pkg2"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_NotExpandedAndPaused() { - setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); - - mDashboardAdapter.onPause(); - - verify(mFactory.metricsFeatureProvider, times(4)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly( - "pkg1", "pkg2", "pkg1", "pkg2"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_Expanded() { - setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); - - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - - verify(mFactory.metricsFeatureProvider, times(3)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly( - "pkg1", "pkg2", "pkg3"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_ExpandedAndPaused() { - setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); - - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - mDashboardAdapter.onPause(); - - verify(mFactory.metricsFeatureProvider, times(6)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly( - "pkg1", "pkg2", "pkg3", "pkg1", "pkg2", "pkg3"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_ExpandedAfterPause() { - setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); - - mDashboardAdapter.onPause(); - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - - verify(mFactory.metricsFeatureProvider, times(7)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly( - "pkg1", "pkg2", "pkg1", "pkg2", "pkg1", "pkg2", "pkg3"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_ExpandedAfterPauseAndPausedAgain() { - setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3")); - - mDashboardAdapter.onPause(); - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - mDashboardAdapter.onPause(); - - verify(mFactory.metricsFeatureProvider, times(10)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly( - "pkg1", "pkg2", "pkg1", "pkg2", "pkg1", "pkg2", "pkg3", "pkg1", "pkg2", "pkg3"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_ExpandedWithLessThanDefaultShown() { - setupSuggestions(makeSuggestions("pkg1")); - - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - - verify(mFactory.metricsFeatureProvider, times(1)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly("pkg1"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_ExpandedWithLessThanDefaultShownAndPaused() { - setupSuggestions(makeSuggestions("pkg1")); - - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - mDashboardAdapter.onPause(); - - verify(mFactory.metricsFeatureProvider, times(2)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly("pkg1", "pkg1"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_ExpandedWithLessThanDefaultShownAfterPause() { - setupSuggestions(makeSuggestions("pkg1")); - - mDashboardAdapter.onPause(); - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - - verify(mFactory.metricsFeatureProvider, times(3)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly("pkg1", "pkg1", "pkg1"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_ExpandedWithLessThanDefaultShownAfterPauseAndPausedAgain() { - setupSuggestions(makeSuggestions("pkg1")); - mDashboardAdapter.onPause(); - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - mDashboardAdapter.onPause(); - - verify(mFactory.metricsFeatureProvider, times(4)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly( - "pkg1", "pkg1", "pkg1", "pkg1"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testSuggestionsLogs_SmartSuggestionEnabled() { - when(mFactory.suggestionsFeatureProvider - .isSmartSuggestionEnabled(any(Context.class))).thenReturn(true); - setupSuggestions(makeSuggestions("pkg1")); - - mDashboardAdapter.onBindSuggestionConditionHeader(mSuggestionHolder, mSuggestionHeaderData); - mSuggestionHolder.itemView.callOnClick(); - mDashboardAdapter.onPause(); - - verify(mFactory.metricsFeatureProvider, times(2)).action( - any(Context.class), mActionCategoryCaptor.capture(), - mActionPackageCaptor.capture(), - mTaggedDataCaptor.capture()); - assertThat(mActionCategoryCaptor.getAllValues()).containsExactly( - MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, - MetricsEvent.ACTION_HIDE_SETTINGS_SUGGESTION); - assertThat(mActionPackageCaptor.getAllValues()).containsExactly("pkg1", "pkg1"); - assertThat(mTaggedDataCaptor.getAllValues()).containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 1), - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 1)); - } - @Test public void testSuggestionsLogs_nullSuggestionsList_shouldNotCrash() { setupSuggestions(makeSuggestions("pkg1", "pkg2", "pkg3", "pkg4", "pkg5")); @@ -618,6 +331,10 @@ public class DashboardAdapterTest { verify(data).setAdapter(any(ConditionAdapter.class)); } + /** + * @deprecated in favor of {@link #makeSuggestionsV2(String...)} + */ + @Deprecated private List makeSuggestions(String... pkgNames) { final List suggestions = new ArrayList<>(); for (String pkgName : pkgNames) { diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java index d43a1692abf..825b388f018 100644 --- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionAdapterTest.java @@ -39,6 +39,7 @@ import android.widget.LinearLayout; import android.widget.RemoteViews; import android.widget.TextView; +import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.TestConfig; @@ -66,7 +67,7 @@ public class SuggestionAdapterTest { @Mock(answer = Answers.RETURNS_DEEP_STUBS) private SettingsActivity mActivity; - + private FakeFeatureFactory mFeatureFactory; private Context mContext; private SuggestionAdapter mSuggestionAdapter; private DashboardAdapter.DashboardItemHolder mSuggestionHolder; @@ -79,7 +80,7 @@ public class SuggestionAdapterTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - FakeFeatureFactory.setupForTest(mActivity); + mFeatureFactory = FakeFeatureFactory.setupForTest(mActivity); final Tile suggestion1 = new Tile(); final Tile suggestion2 = new Tile(); @@ -171,6 +172,24 @@ public class SuggestionAdapterTest { verify(view).setOnClickListener(any(View.OnClickListener.class)); } + @Test + public void onBindViewHolder_shouldLog() { + final View view = spy(LayoutInflater.from(mContext).inflate( + R.layout.suggestion_tile, new LinearLayout(mContext), true)); + mSuggestionHolder = new DashboardAdapter.DashboardItemHolder(view); + mSuggestionAdapter = new SuggestionAdapter(mContext, null /* suggestionV1*/, + mOneSuggestionV2, new ArrayList<>()); + + // Bind twice + mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0); + mSuggestionAdapter.onBindViewHolder(mSuggestionHolder, 0); + + // Log once + verify(mFeatureFactory.metricsFeatureProvider).action( + mContext, MetricsProto.MetricsEvent.ACTION_SHOW_SETTINGS_SUGGESTION, + mOneSuggestionV2.get(0).getId()); + } + @Test public void onBindViewHolder_shouldInflateRemoteView() { List packages = makeSuggestions("pkg1"); diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java index 69b76fa8a31..5e567144a2e 100644 --- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionFeatureProviderImplTest.java @@ -22,6 +22,7 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; @@ -313,4 +314,19 @@ public class SuggestionFeatureProviderImplTest { new ComponentName(mContext, NightDisplaySuggestionActivity.class); assertThat(mProvider.isSuggestionComplete(mContext, componentName)).isFalse(); } + + @Test + public void testGetSmartSuggestionEnabledTaggedData_disabled() { + assertThat(mProvider.getLoggingTaggedData(mContext)).asList().containsExactly( + Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); + } + + @Test + public void testGetSmartSuggestionEnabledTaggedData_enabled() { + final SuggestionFeatureProvider provider = spy(mProvider); + when(provider.isSmartSuggestionEnabled(any(Context.class))).thenReturn(true); + + assertThat(provider.getLoggingTaggedData(mContext)).asList().containsExactly( + Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 1)); + } } diff --git a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionLogHelperTest.java b/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionLogHelperTest.java deleted file mode 100644 index 01d253f7fb3..00000000000 --- a/tests/robotests/src/com/android/settings/dashboard/suggestions/SuggestionLogHelperTest.java +++ /dev/null @@ -1,47 +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.dashboard.suggestions; - -import static com.google.common.truth.Truth.assertThat; - -import android.util.Pair; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.TestConfig; -import com.android.settings.testutils.SettingsRobolectricTestRunner; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.annotation.Config; - -@RunWith(SettingsRobolectricTestRunner.class) -@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) -public class SuggestionLogHelperTest { - - @Test - public void testGetSmartSuggestionEnabledTaggedData_disabled() { - assertThat(SuggestionLogHelper.getSuggestionTaggedData(false)).asList().containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 0)); - } - - @Test - public void testGetSmartSuggestionEnabledTaggedData_enabled() { - assertThat(SuggestionLogHelper.getSuggestionTaggedData(true)).asList().containsExactly( - Pair.create(MetricsEvent.FIELD_SETTINGS_SMART_SUGGESTIONS_ENABLED, 1)); - } -} - From 4f4f91ee2899eb836523135e8638f733135613e1 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Fri, 6 Oct 2017 11:39:44 -0700 Subject: [PATCH 5/6] Fix a grammar issue in string Change-Id: I7ecaefc69d57d07061c6f01359ea6680b64633c3 Fixes: 67415408 Test: visual --- res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 8f6cc9c40dc..6869fdc23fb 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7996,7 +7996,7 @@ App modify system settings permission - Allow modify system settings + Allow modifying system settings This permission allows an app to modify system settings. From e063427d0b9c8e1269984100dbfb9b741ba0b61b Mon Sep 17 00:00:00 2001 From: Andrew Sapperstein Date: Thu, 5 Oct 2017 18:19:32 -0700 Subject: [PATCH 6/6] Update wakeup anomaly to exclude blacklisted wakeups. Also disables all anomalies out of the box. Provides the ability to ignore certain wakeups if blacklisted in AnomalyDetectionPolicy. Compares each wakeup to the blacklist and if it exists, does not include it in the count used to compare against the threshold. Change-Id: I4ef548bd0952be5f0d4e36df5698f287839d0704 Fixes: 67000019 Test: robotests --- .../anomaly/AnomalyDetectionPolicy.java | 40 +++++++++++++--- .../checker/WakeupAlarmAnomalyDetector.java | 17 +++++-- .../wrapper/KeyValueListParserWrapper.java | 12 ++++- .../anomaly/AnomalyDetectionPolicyTest.java | 46 ++++++++++++++----- .../WakeupAlarmAnomalyDetectorTest.java | 26 ++++++++++- 5 files changed, 117 insertions(+), 24 deletions(-) diff --git a/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicy.java b/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicy.java index 382c6921dbf..3791d89c8de 100644 --- a/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicy.java +++ b/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicy.java @@ -17,6 +17,7 @@ package com.android.settings.fuelgauge.anomaly; import android.content.Context; +import android.net.Uri; import android.provider.Settings; import android.support.annotation.VisibleForTesting; import android.text.format.DateUtils; @@ -25,6 +26,10 @@ import android.util.Log; import com.android.settings.wrapper.KeyValueListParserWrapper; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + /** * Class to store the policy for anomaly detection, which comes from * {@link android.provider.Settings.Global} @@ -45,6 +50,8 @@ public class AnomalyDetectionPolicy { @VisibleForTesting static final String KEY_WAKEUP_ALARM_THRESHOLD = "wakeup_alarm_threshold"; @VisibleForTesting + static final String KEY_WAKEUP_BLACKLISTED_TAGS = "wakeup_blacklisted_tags"; + @VisibleForTesting static final String KEY_BLUETOOTH_SCAN_THRESHOLD = "bluetooth_scan_threshold"; /** @@ -95,6 +102,14 @@ public class AnomalyDetectionPolicy { */ public final long wakeupAlarmThreshold; + /** + * Array of blacklisted wakeups, by tag. + * + * @see Settings.Global#ANOMALY_DETECTION_CONSTANTS + * @see #KEY_WAKEUP_BLACKLISTED_TAGS + */ + public final Set wakeupBlacklistedTags; + /** * Threshold for bluetooth unoptimized scanning time in milli seconds * @@ -121,15 +136,18 @@ public class AnomalyDetectionPolicy { Log.e(TAG, "Bad anomaly detection constants"); } - anomalyDetectionEnabled = mParserWrapper.getBoolean(KEY_ANOMALY_DETECTION_ENABLED, true); - wakeLockDetectionEnabled = mParserWrapper.getBoolean(KEY_WAKELOCK_DETECTION_ENABLED, true); - wakeupAlarmDetectionEnabled = mParserWrapper.getBoolean(KEY_WAKEUP_ALARM_DETECTION_ENABLED, - false); + anomalyDetectionEnabled = + mParserWrapper.getBoolean(KEY_ANOMALY_DETECTION_ENABLED, false); + wakeLockDetectionEnabled = + mParserWrapper.getBoolean(KEY_WAKELOCK_DETECTION_ENABLED,false); + wakeupAlarmDetectionEnabled = + mParserWrapper.getBoolean(KEY_WAKEUP_ALARM_DETECTION_ENABLED,false); bluetoothScanDetectionEnabled = mParserWrapper.getBoolean( - KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, true); + KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, false); wakeLockThreshold = mParserWrapper.getLong(KEY_WAKELOCK_THRESHOLD, DateUtils.HOUR_IN_MILLIS); - wakeupAlarmThreshold = mParserWrapper.getLong(KEY_WAKEUP_ALARM_THRESHOLD, 60); + wakeupAlarmThreshold = mParserWrapper.getLong(KEY_WAKEUP_ALARM_THRESHOLD, 10); + wakeupBlacklistedTags = parseStringSet(KEY_WAKEUP_BLACKLISTED_TAGS, null); bluetoothScanThreshold = mParserWrapper.getLong(KEY_BLUETOOTH_SCAN_THRESHOLD, 30 * DateUtils.MINUTE_IN_MILLIS); } @@ -150,4 +168,14 @@ public class AnomalyDetectionPolicy { return false; // Disabled when no this type } } + + private Set parseStringSet(final String key, final Set defaultSet) { + final String value = mParserWrapper.getString(key, null); + if (value != null) { + return Arrays.stream(value.split(":")) + .map(String::trim).map(Uri::decode).collect(Collectors.toSet()); + } else { + return defaultSet; + } + } } diff --git a/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java b/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java index 8823a177092..46f31ab3a8e 100644 --- a/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java +++ b/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetector.java @@ -21,6 +21,8 @@ import android.os.BatteryStats; import android.support.annotation.VisibleForTesting; import android.text.format.DateUtils; import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.Log; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; @@ -29,10 +31,12 @@ import com.android.settings.fuelgauge.BatteryUtils; import com.android.settings.fuelgauge.anomaly.Anomaly; import com.android.settings.fuelgauge.anomaly.AnomalyDetectionPolicy; import com.android.settings.fuelgauge.anomaly.AnomalyUtils; -import com.android.settings.fuelgauge.anomaly.action.AnomalyAction; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; /** * Check whether apps has too many wakeup alarms @@ -42,6 +46,7 @@ public class WakeupAlarmAnomalyDetector implements AnomalyDetector { @VisibleForTesting BatteryUtils mBatteryUtils; private long mWakeupAlarmThreshold; + private Set mWakeupBlacklistedTags; private Context mContext; private AnomalyUtils mAnomalyUtils; @@ -56,6 +61,7 @@ public class WakeupAlarmAnomalyDetector implements AnomalyDetector { mBatteryUtils = BatteryUtils.getInstance(context); mAnomalyUtils = anomalyUtils; mWakeupAlarmThreshold = policy.wakeupAlarmThreshold; + mWakeupBlacklistedTags = policy.wakeupBlacklistedTags; } @Override @@ -123,11 +129,14 @@ public class WakeupAlarmAnomalyDetector implements AnomalyDetector { final BatteryStats.Uid.Pkg ps = packageStats.valueAt(ipkg); final ArrayMap alarms = ps.getWakeupAlarmStats(); - for (int iwa = alarms.size() - 1; iwa >= 0; iwa--) { - int count = alarms.valueAt(iwa).getCountLocked(BatteryStats.STATS_SINCE_CHARGED); + for (Map.Entry alarm : alarms.entrySet()) { + if (mWakeupBlacklistedTags != null + && mWakeupBlacklistedTags.contains(alarm.getKey())) { + continue; + } + int count = alarm.getValue().getCountLocked(BatteryStats.STATS_SINCE_CHARGED); wakeups += count; } - } return wakeups; diff --git a/src/com/android/settings/wrapper/KeyValueListParserWrapper.java b/src/com/android/settings/wrapper/KeyValueListParserWrapper.java index 16dc50eecdc..3fab5711db0 100644 --- a/src/com/android/settings/wrapper/KeyValueListParserWrapper.java +++ b/src/com/android/settings/wrapper/KeyValueListParserWrapper.java @@ -56,12 +56,22 @@ public class KeyValueListParserWrapper { * Get the value for key as a boolean. * @param key The key to lookup. * @param defaultValue The value to return if the key was not found. - * @return the string value associated with the key. + * @return the boolean value associated with the key. */ public boolean getBoolean(String key, boolean defaultValue) { return mParser.getBoolean(key, defaultValue); } + /** + * Get the value for key as a string. + * @param key The key to lookup. + * @param defaultValue The value to return if the key was not found. + * @return the string value associated with the key. + */ + public String getString(String key, String defaultValue) { + return mParser.getString(key, defaultValue); + } + /** * Get the value for key as a long. * @param key The key to lookup. diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicyTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicyTest.java index 9bbc9bd7be6..46db6b37f92 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicyTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/AnomalyDetectionPolicyTest.java @@ -41,11 +41,13 @@ import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class AnomalyDetectionPolicyTest { - private static final String ANOMALY_DETECTION_CONSTANTS_VALUE = "anomaly_detection_enabled=true" + private static final String ANOMALY_DETECTION_CONSTANTS_VALUE = + "anomaly_detection_enabled=true" + ",wakelock_enabled=false" + ",wakelock_threshold=3000" + ",wakeup_alarm_enabled=true" + ",wakeup_alarm_threshold=100" + + ",wakeup_blacklisted_tags=tag1:tag2:with%2Ccomma:with%3Acolon" + ",bluetooth_scan_enabled=true" + ",bluetooth_scan_threshold=2000"; private Context mContext; @@ -59,7 +61,7 @@ public class AnomalyDetectionPolicyTest { } @Test - public void testInit_containsDataFromSettings() { + public void testInit_usesConfigValues() { AnomalyDetectionPolicy anomalyDetectionPolicy = createAnomalyPolicyWithConfig(); assertThat(anomalyDetectionPolicy.anomalyDetectionEnabled).isTrue(); @@ -67,12 +69,14 @@ public class AnomalyDetectionPolicyTest { assertThat(anomalyDetectionPolicy.wakeLockThreshold).isEqualTo(3000); assertThat(anomalyDetectionPolicy.wakeupAlarmDetectionEnabled).isTrue(); assertThat(anomalyDetectionPolicy.wakeupAlarmThreshold).isEqualTo(100); + assertThat(anomalyDetectionPolicy.wakeupBlacklistedTags) + .containsExactly("tag1", "tag2", "with,comma", "with:colon"); assertThat(anomalyDetectionPolicy.bluetoothScanDetectionEnabled).isTrue(); assertThat(anomalyDetectionPolicy.bluetoothScanThreshold).isEqualTo(2000); } @Test - public void testInit_containsDefaultData() { + public void testInit_defaultValues() { Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ANOMALY_DETECTION_CONSTANTS, ""); // Mock it to avoid noSuchMethodError @@ -82,18 +86,19 @@ public class AnomalyDetectionPolicyTest { AnomalyDetectionPolicy anomalyDetectionPolicy = new AnomalyDetectionPolicy(mContext, mKeyValueListParserWrapper); - assertThat(anomalyDetectionPolicy.anomalyDetectionEnabled).isTrue(); - assertThat(anomalyDetectionPolicy.wakeLockDetectionEnabled).isTrue(); + assertThat(anomalyDetectionPolicy.anomalyDetectionEnabled).isFalse(); + assertThat(anomalyDetectionPolicy.wakeLockDetectionEnabled).isFalse(); assertThat(anomalyDetectionPolicy.wakeLockThreshold).isEqualTo(DateUtils.HOUR_IN_MILLIS); assertThat(anomalyDetectionPolicy.wakeupAlarmDetectionEnabled).isFalse(); - assertThat(anomalyDetectionPolicy.wakeupAlarmThreshold).isEqualTo(60); - assertThat(anomalyDetectionPolicy.bluetoothScanDetectionEnabled).isTrue(); + assertThat(anomalyDetectionPolicy.wakeupAlarmThreshold).isEqualTo(10); + assertThat(anomalyDetectionPolicy.wakeupBlacklistedTags).isNull(); + assertThat(anomalyDetectionPolicy.bluetoothScanDetectionEnabled).isFalse(); assertThat(anomalyDetectionPolicy.bluetoothScanThreshold).isEqualTo( 30 * DateUtils.MINUTE_IN_MILLIS); } @Test - public void testIsAnomalyDetectorEnabled() { + public void testIsAnomalyDetectorEnabled_usesConfigValues() { AnomalyDetectionPolicy anomalyDetectionPolicy = createAnomalyPolicyWithConfig(); assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled( @@ -104,18 +109,37 @@ public class AnomalyDetectionPolicyTest { Anomaly.AnomalyType.BLUETOOTH_SCAN)).isTrue(); } + @Test + public void testIsAnomalyDetectorEnabled_usesDefaultValues() { + Settings.Global.putString(mContext.getContentResolver(), + Settings.Global.ANOMALY_DETECTION_CONSTANTS, ""); + // Mock it to avoid noSuchMethodError + doReturn(true).when(mKeyValueListParserWrapper).getBoolean(anyString(), eq(true)); + doReturn(false).when(mKeyValueListParserWrapper).getBoolean(anyString(), eq(false)); + + AnomalyDetectionPolicy anomalyDetectionPolicy = new AnomalyDetectionPolicy(mContext, + mKeyValueListParserWrapper); + + assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled( + Anomaly.AnomalyType.WAKE_LOCK)).isFalse(); + assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled( + Anomaly.AnomalyType.WAKEUP_ALARM)).isFalse(); + assertThat(anomalyDetectionPolicy.isAnomalyDetectorEnabled( + Anomaly.AnomalyType.BLUETOOTH_SCAN)).isFalse(); + } + private AnomalyDetectionPolicy createAnomalyPolicyWithConfig() { Settings.Global.putString(mContext.getContentResolver(), Settings.Global.ANOMALY_DETECTION_CONSTANTS, ANOMALY_DETECTION_CONSTANTS_VALUE); // Mock it to avoid noSuchMethodError doReturn(true).when(mKeyValueListParserWrapper).getBoolean( - AnomalyDetectionPolicy.KEY_ANOMALY_DETECTION_ENABLED, true); + AnomalyDetectionPolicy.KEY_ANOMALY_DETECTION_ENABLED, false); doReturn(false).when(mKeyValueListParserWrapper).getBoolean( - AnomalyDetectionPolicy.KEY_WAKELOCK_DETECTION_ENABLED, true); + AnomalyDetectionPolicy.KEY_WAKELOCK_DETECTION_ENABLED, false); doReturn(true).when(mKeyValueListParserWrapper).getBoolean( AnomalyDetectionPolicy.KEY_WAKEUP_ALARM_DETECTION_ENABLED, false); doReturn(true).when(mKeyValueListParserWrapper).getBoolean( - AnomalyDetectionPolicy.KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, true); + AnomalyDetectionPolicy.KEY_BLUETOOTH_SCAN_DETECTION_ENABLED, false); return new AnomalyDetectionPolicy(mContext, mKeyValueListParserWrapper); } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java index 55be734e232..13a5ab8531f 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/anomaly/checker/WakeupAlarmAnomalyDetectorTest.java @@ -30,6 +30,7 @@ import android.os.BatteryStats; import android.os.Build; import android.text.format.DateUtils; import android.util.ArrayMap; +import android.util.ArraySet; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; @@ -52,6 +53,7 @@ import org.robolectric.util.ReflectionHelpers; import java.util.ArrayList; import java.util.List; +import java.util.Set; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @@ -69,6 +71,7 @@ public class WakeupAlarmAnomalyDetectorTest { 1 * DateUtils.HOUR_IN_MILLIS + 10 * DateUtils.MINUTE_IN_MILLIS; private static final int ANOMALY_WAKEUP_COUNT = 500; private static final int NORMAL_WAKEUP_COUNT = 61; + private static final int BLACKLISTED_WAKEUP_COUNT = 37; private static final int ANOMALY_WAKEUP_FREQUENCY = 428; // count per hour @Mock private BatteryStatsHelper mBatteryStatsHelper; @@ -87,12 +90,12 @@ public class WakeupAlarmAnomalyDetectorTest { @Mock private BatteryUtils mBatteryUtils; @Mock - private ApplicationInfo mApplicationInfo; - @Mock private BatteryStats.Uid.Pkg mPkg; @Mock private BatteryStats.Counter mCounter; @Mock + private BatteryStats.Counter mCounter2; + @Mock private AnomalyDetectionPolicy mPolicy; @Mock private AnomalyAction mAnomalyAction; @@ -111,6 +114,9 @@ public class WakeupAlarmAnomalyDetectorTest { mContext = spy(RuntimeEnvironment.application); ReflectionHelpers.setField(mPolicy, "wakeupAlarmThreshold", 60); + final Set blacklistedTags = new ArraySet<>(); + blacklistedTags.add("blacklistedTag"); + ReflectionHelpers.setField(mPolicy, "wakeupBlacklistedTags", blacklistedTags); doReturn(false).when(mBatteryUtils).shouldHideSipper(any()); doReturn(RUNNING_TIME_MS).when(mBatteryUtils).calculateRunningTimeBasedOnStatsType(any(), @@ -207,4 +213,20 @@ public class WakeupAlarmAnomalyDetectorTest { assertThat(mWakeupAlarmAnomalyDetector.getWakeupAlarmCountFromUid(mAnomalyUid)).isEqualTo( 2 * NORMAL_WAKEUP_COUNT); } + + @Test + public void testGetWakeupAlarmCountFromUid_filterOutBlacklistedTags() { + final ArrayMap packageStats = new ArrayMap<>(); + final ArrayMap alarms = new ArrayMap<>(); + doReturn(alarms).when(mPkg).getWakeupAlarmStats(); + doReturn(NORMAL_WAKEUP_COUNT).when(mCounter).getCountLocked(anyInt()); + doReturn(BLACKLISTED_WAKEUP_COUNT).when(mCounter2).getCountLocked(anyInt()); + doReturn(packageStats).when(mAnomalyUid).getPackageStats(); + packageStats.put("", mPkg); + alarms.put("allowedTag", mCounter); + alarms.put("blacklistedTag", mCounter2); + + assertThat(mWakeupAlarmAnomalyDetector.getWakeupAlarmCountFromUid(mAnomalyUid)).isEqualTo( + NORMAL_WAKEUP_COUNT); + } }