From 319d53497563cdec535d1fb1e65c3e8b7a7dd5c4 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Tue, 27 Feb 2018 14:30:57 -0800 Subject: [PATCH] Create new PowerUsageAdvanced page This page contains the graph at the top and app list at the bottom In this cl, we reused some part of the code in PowerUsageAdvancedLegacy to construct the graph, and also used controller to construct the app list(So glad that we extracted it to controller before..) Bug: 73300636 Test: RunSettingsRoboTests Change-Id: I30afbc0327a5186f8280f5e3678330b363e2dc0d --- res/xml/power_usage_advanced.xml | 31 +++ res/xml/power_usage_summary.xml | 4 - .../BatteryAppListPreferenceController.java | 13 +- .../fuelgauge/PowerUsageAdvanced.java | 176 ++++++++++++++++++ .../settings/fuelgauge/PowerUsageSummary.java | 9 - ...atteryAppListPreferenceControllerTest.java | 14 -- .../fuelgauge/PowerUsageAdvancedTest.java | 111 +++++++++++ 7 files changed, 327 insertions(+), 31 deletions(-) create mode 100644 res/xml/power_usage_advanced.xml create mode 100644 src/com/android/settings/fuelgauge/PowerUsageAdvanced.java create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java diff --git a/res/xml/power_usage_advanced.xml b/res/xml/power_usage_advanced.xml new file mode 100644 index 00000000000..d32611ce969 --- /dev/null +++ b/res/xml/power_usage_advanced.xml @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/res/xml/power_usage_summary.xml b/res/xml/power_usage_summary.xml index d89653ae5ce..ac96151557e 100644 --- a/res/xml/power_usage_summary.xml +++ b/res/xml/power_usage_summary.xml @@ -66,8 +66,4 @@ - - diff --git a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java index 3ba5ee47fc0..5028264b596 100644 --- a/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java +++ b/src/com/android/settings/fuelgauge/BatteryAppListPreferenceController.java @@ -149,7 +149,7 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro @Override public boolean isAvailable() { - return FeatureFlagUtils.isEnabled(mContext, FeatureFlags.BATTERY_DISPLAY_APP_LIST); + return true; } @Override @@ -186,12 +186,17 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro } } - public void refreshAppListGroup(BatteryStatsHelper statsHelper, boolean showAllApps, - CharSequence timeSequence) { + public void refreshAppListGroup(BatteryStatsHelper statsHelper, boolean showAllApps) { if (!isAvailable()) { return; } + mBatteryStatsHelper = statsHelper; + final long lastFullChargeTime = mBatteryUtils.calculateLastFullChargeTime( + mBatteryStatsHelper, System.currentTimeMillis()); + final CharSequence timeSequence = StringUtil.formatRelativeTime(mContext, + lastFullChargeTime, + false); final int resId = showAllApps ? R.string.power_usage_list_summary_device : R.string.power_usage_list_summary; mAppListGroup.setTitle(TextUtils.expandTemplate(mContext.getText(resId), timeSequence)); @@ -361,7 +366,7 @@ public class BatteryAppListPreferenceController extends AbstractPreferenceContro final long usageTimeMs = sipper.usageTimeMs; if (usageTimeMs >= DateUtils.MINUTE_IN_MILLIS) { final CharSequence timeSequence = - StringUtil.formatElapsedTime(mContext, usageTimeMs, false); + StringUtil.formatElapsedTime(mContext, usageTimeMs, false); preference.setSummary( (sipper.drainType != DrainType.APP || mBatteryUtils.shouldHideSipper(sipper)) ? timeSequence diff --git a/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java new file mode 100644 index 00000000000..89f66bd8806 --- /dev/null +++ b/src/com/android/settings/fuelgauge/PowerUsageAdvanced.java @@ -0,0 +1,176 @@ +/* + * 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.fuelgauge; + +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; +import android.os.Bundle; +import android.provider.SearchIndexableResource; +import android.support.annotation.VisibleForTesting; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.overlay.FeatureFactory; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settingslib.core.AbstractPreferenceController; +import com.android.settingslib.utils.StringUtil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class PowerUsageAdvanced extends PowerUsageBase { + private static final String TAG = "AdvancedBatteryUsage"; + private static final String KEY_BATTERY_GRAPH = "battery_graph"; + private static final String KEY_APP_LIST = "app_list"; + private static final String KEY_SHOW_ALL_APPS = "show_all_apps"; + @VisibleForTesting + static final int MENU_TOGGLE_APPS = Menu.FIRST + 1; + + @VisibleForTesting + BatteryHistoryPreference mHistPref; + private BatteryUtils mBatteryUtils; + private PowerUsageFeatureProvider mPowerUsageFeatureProvider; + private BatteryAppListPreferenceController mBatteryAppListPreferenceController; + @VisibleForTesting + boolean mShowAllApps = false; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + final Context context = getContext(); + + mHistPref = (BatteryHistoryPreference) findPreference(KEY_BATTERY_GRAPH); + mPowerUsageFeatureProvider = FeatureFactory.getFactory(context) + .getPowerUsageFeatureProvider(context); + mBatteryUtils = BatteryUtils.getInstance(context); + + // init the summary so other preferences won't have unnecessary move + updateHistPrefSummary(context); + restoreSavedInstance(icicle); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (getActivity().isChangingConfigurations()) { + BatteryEntry.clearUidCache(); + } + } + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.FUELGAUGE_BATTERY_HISTORY_DETAIL; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.power_usage_advanced; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + menu.add(Menu.NONE, MENU_TOGGLE_APPS, Menu.NONE, + mShowAllApps ? R.string.hide_extra_apps : R.string.show_all_apps); + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case MENU_TOGGLE_APPS: + mShowAllApps = !mShowAllApps; + item.setTitle(mShowAllApps ? R.string.hide_extra_apps : R.string.show_all_apps); + mMetricsFeatureProvider.action(getContext(), + MetricsProto.MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE, + mShowAllApps); + restartBatteryStatsLoader(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @VisibleForTesting + void restoreSavedInstance(Bundle savedInstance) { + if (savedInstance != null) { + mShowAllApps = savedInstance.getBoolean(KEY_SHOW_ALL_APPS, false); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(KEY_SHOW_ALL_APPS, mShowAllApps); + } + + @Override + protected List createPreferenceControllers(Context context) { + final List controllers = new ArrayList<>(); + + mBatteryAppListPreferenceController = new BatteryAppListPreferenceController(context, + KEY_APP_LIST, getLifecycle(), (SettingsActivity) getActivity(), this); + controllers.add(mBatteryAppListPreferenceController); + + return controllers; + } + + @Override + protected void refreshUi() { + final Context context = getContext(); + if (context == null) { + return; + } + updatePreference(mHistPref); + updateHistPrefSummary(context); + + mBatteryAppListPreferenceController.refreshAppListGroup(mStatsHelper, mShowAllApps); + } + + private void updateHistPrefSummary(Context context) { + Intent batteryIntent = + context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); + final boolean plugged = batteryIntent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0; + + if (mPowerUsageFeatureProvider.isEnhancedBatteryPredictionEnabled(context) && !plugged) { + mHistPref.setBottomSummary( + mPowerUsageFeatureProvider.getAdvancedUsageScreenInfoString()); + } else { + mHistPref.hideBottomSummary(); + } + } + + public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex( + Context context, boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.power_usage_advanced; + return Arrays.asList(sir); + } + }; + +} diff --git a/src/com/android/settings/fuelgauge/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/PowerUsageSummary.java index bf0b627f910..8d70e46463f 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageSummary.java +++ b/src/com/android/settings/fuelgauge/PowerUsageSummary.java @@ -101,7 +101,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList SparseArray> mAnomalySparseArray; @VisibleForTesting BatteryHeaderPreferenceController mBatteryHeaderPreferenceController; - private BatteryAppListPreferenceController mBatteryAppListPreferenceController; private BatteryTipPreferenceController mBatteryTipPreferenceController; private int mStatsType = BatteryStats.STATS_SINCE_CHARGED; @@ -231,9 +230,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList mBatteryHeaderPreferenceController = new BatteryHeaderPreferenceController( context, activity, this /* host */, lifecycle); controllers.add(mBatteryHeaderPreferenceController); - mBatteryAppListPreferenceController = new BatteryAppListPreferenceController(context, - KEY_APP_LIST, lifecycle, activity, this); - controllers.add(mBatteryAppListPreferenceController); mBatteryTipPreferenceController = new BatteryTipPreferenceController(context, KEY_BATTERY_TIP, (SettingsActivity) getActivity(), this /* fragment */, this /* BatteryTipListener */); @@ -294,11 +290,6 @@ public class PowerUsageSummary extends PowerUsageBase implements OnLongClickList updateLastFullChargePreference(lastFullChargeTime); mScreenUsagePref.setSubtitle(StringUtil.formatElapsedTime(getContext(), mBatteryUtils.calculateScreenUsageTime(mStatsHelper), false)); - - final CharSequence timeSequence = StringUtil.formatRelativeTime(context, lastFullChargeTime, - false); - mBatteryAppListPreferenceController.refreshAppListGroup(mStatsHelper, - false /* showAllApps */, timeSequence); } @VisibleForTesting diff --git a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java index b223a10ed21..8156428d136 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/BatteryAppListPreferenceControllerTest.java @@ -202,20 +202,6 @@ public class BatteryAppListPreferenceControllerTest { assertThat(mPreferenceController.shouldHideSipper(mNormalBatterySipper)).isFalse(); } - @Test - public void testIsAvailable_featureOn_returnTrue() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.BATTERY_DISPLAY_APP_LIST, true); - - assertThat(mPreferenceController.isAvailable()).isTrue(); - } - - @Test - public void testIsAvailable_featureOff_returnFalse() { - FeatureFlagUtils.setEnabled(mContext, FeatureFlags.BATTERY_DISPLAY_APP_LIST, false); - - assertThat(mPreferenceController.isAvailable()).isFalse(); - } - @Test public void testNeverUseFakeData() { assertThat(BatteryAppListPreferenceController.USE_FAKE_DATA).isFalse(); diff --git a/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java new file mode 100644 index 00000000000..eba62522b80 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/PowerUsageAdvancedTest.java @@ -0,0 +1,111 @@ +/* + * 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.fuelgauge; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Matchers.eq; +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.os.Bundle; +import android.support.v7.preference.PreferenceScreen; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.TestConfig; +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.RuntimeEnvironment; +import org.robolectric.annotation.Config; + +@RunWith(SettingsRobolectricTestRunner.class) +@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) +public class PowerUsageAdvancedTest { + @Mock + private PreferenceScreen mPreferenceScreen; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Menu mMenu; + @Mock + private MenuInflater mMenuInflater; + @Mock + private MenuItem mToggleAppsMenu; + private Context mContext; + private PowerUsageAdvanced mFragment; + private FakeFeatureFactory mFeatureFactory; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = RuntimeEnvironment.application; + mFeatureFactory = FakeFeatureFactory.setupForTest(); + when(mToggleAppsMenu.getItemId()).thenReturn(PowerUsageAdvanced.MENU_TOGGLE_APPS); + + mFragment = spy(new PowerUsageAdvanced()); + mFragment.onAttach(mContext); + } + + @Test + public void testSaveInstanceState_showAllAppsRestored() { + Bundle bundle = new Bundle(); + mFragment.mShowAllApps = true; + doReturn(mPreferenceScreen).when(mFragment).getPreferenceScreen(); + + mFragment.onSaveInstanceState(bundle); + mFragment.restoreSavedInstance(bundle); + + assertThat(mFragment.mShowAllApps).isTrue(); + } + + @Test + public void testOptionsMenu_menuAppToggle_metricEventInvoked() { + mFragment.mShowAllApps = false; + doNothing().when(mFragment).restartBatteryStatsLoader(); + + mFragment.onOptionsItemSelected(mToggleAppsMenu); + + verify(mFeatureFactory.metricsFeatureProvider).action(nullable(Context.class), + eq(MetricsProto.MetricsEvent.ACTION_SETTINGS_MENU_BATTERY_APPS_TOGGLE), eq(true)); + } + + @Test + public void testOptionsMenu_toggleAppsEnabled() { + when(mFeatureFactory.powerUsageFeatureProvider.isPowerAccountingToggleEnabled()) + .thenReturn(true); + mFragment.mShowAllApps = false; + + mFragment.onCreateOptionsMenu(mMenu, mMenuInflater); + + verify(mMenu).add(Menu.NONE, PowerUsageAdvanced.MENU_TOGGLE_APPS, Menu.NONE, + R.string.show_all_apps); + } +}