From 59241610611470e49794185854ff1d024a25f7c8 Mon Sep 17 00:00:00 2001 From: Tiffany Nguyen Date: Wed, 28 Apr 2021 08:54:29 +0000 Subject: [PATCH] Redirect battery-level settings preference clicks if needed Change-Id: I64d0992544cc7e0cb41293b799577cbc43dfbb38 Bug: 181827923 Test: unit --- .../TopLevelBatteryPreferenceController.java | 56 +++++++++ ...pLevelBatteryPreferenceControllerTest.java | 107 +++++++++++++++++- 2 files changed, 161 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java index 99eb05d8116..2eb7cf413fc 100644 --- a/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java +++ b/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceController.java @@ -16,7 +16,9 @@ package com.android.settings.fuelgauge; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; @@ -29,6 +31,8 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; +import java.util.HashMap; + public class TopLevelBatteryPreferenceController extends BasePreferenceController implements LifecycleObserver, OnStart, OnStop, BatteryPreferenceController { @@ -37,9 +41,13 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle private final BatteryBroadcastReceiver mBatteryBroadcastReceiver; private Preference mPreference; private BatteryInfo mBatteryInfo; + private BatterySettingsFeatureProvider mBatterySettingsFeatureProvider; private BatteryStatusFeatureProvider mBatteryStatusFeatureProvider; private String mBatteryStatusLabel; + @VisibleForTesting + protected static HashMap sReplacingActivityMap = new HashMap<>(); + public TopLevelBatteryPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); mBatteryBroadcastReceiver = new BatteryBroadcastReceiver(mContext); @@ -53,6 +61,8 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle }, true /* shortString */); }); + mBatterySettingsFeatureProvider = FeatureFactory.getFactory(context) + .getBatterySettingsFeatureProvider(context); mBatteryStatusFeatureProvider = FeatureFactory.getFactory(context) .getBatteryStatusFeatureProvider(context); } @@ -69,6 +79,37 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle mPreference = screen.findPreference(getPreferenceKey()); } + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + String prefFrag = preference.getFragment(); + if (prefFrag == null || prefFrag.isEmpty()) { + // Not a redirect, so use the default. + return super.handlePreferenceTreeClick(preference); + } + + ComponentName currentFragmentName = convertClassPathToComponentName(prefFrag); + if (currentFragmentName == null) { + return super.handlePreferenceTreeClick(preference); + } + + ComponentName replacingActivity; + if (sReplacingActivityMap.containsKey(prefFrag)) { + replacingActivity = sReplacingActivityMap.get(prefFrag); + } else { + replacingActivity = mBatterySettingsFeatureProvider.getReplacingActivity( + currentFragmentName); + sReplacingActivityMap.put(prefFrag, replacingActivity); + } + + if (replacingActivity == null || currentFragmentName.compareTo(replacingActivity) == 0) { + return super.handlePreferenceTreeClick(preference); + } + Intent intent = new Intent(); + intent.setComponent(currentFragmentName); + mContext.startActivity(intent); + return true; + } + @Override public void onStart() { mBatteryBroadcastReceiver.register(); @@ -133,4 +174,19 @@ public class TopLevelBatteryPreferenceController extends BasePreferenceControlle } } } + + @VisibleForTesting + protected static ComponentName convertClassPathToComponentName(String classPath) { + if (classPath == null || classPath.isEmpty()) { + return null; + } + String[] split = classPath.split("\\."); + int classNameIndex = split.length - 1; + if (classNameIndex < 0) { + return null; + } + int lastPkgIndex = classPath.length() - split[classNameIndex].length() - 1; + String pkgName = lastPkgIndex > 0 ? classPath.substring(0, lastPkgIndex) : ""; + return new ComponentName(pkgName, split[classNameIndex]); + } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java index 1a3c98f8ba1..af4ab0f9198 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/TopLevelBatteryPreferenceControllerTest.java @@ -21,26 +21,55 @@ import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_ import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +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.ComponentName; import android.content.Context; +import android.util.FeatureFlagUtils; + +import androidx.preference.Preference; import com.android.settings.R; +import com.android.settings.core.FeatureFlags; +import com.android.settings.testutils.FakeFeatureFactory; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) public class TopLevelBatteryPreferenceControllerTest { private Context mContext; + private FakeFeatureFactory mFeatureFactory; private TopLevelBatteryPreferenceController mController; + private BatterySettingsFeatureProvider mBatterySettingsFeatureProvider; @Before public void setUp() { - mContext = RuntimeEnvironment.application; + MockitoAnnotations.initMocks(this); + mFeatureFactory = FakeFeatureFactory.setupForTest(); + mContext = spy(Robolectric.setupActivity(Activity.class)); mController = new TopLevelBatteryPreferenceController(mContext, "test_key"); + mBatterySettingsFeatureProvider = + mFeatureFactory.batterySettingsFeatureProvider; + FeatureFlagUtils.setEnabled(mContext, FeatureFlags.SILKY_HOME, false); + } + + @After + public void cleanUp() { + TopLevelBatteryPreferenceController.sReplacingActivityMap.clear(); } @Test @@ -54,6 +83,80 @@ public class TopLevelBatteryPreferenceControllerTest { assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } + @Test + public void handlePreferenceTreeClick_noFragment_noCustomActivityCalled() { + Preference preference = new Preference(mContext); + + assertThat(mController.handlePreferenceTreeClick(preference)).isFalse(); + } + + @Test + public void handlePreferenceTreeClick_sameActivityReturned_noCustomActivityCalled() { + String fragmentPath = "my.fragment.ClassName"; + Preference preference = mock(Preference.class); + when(preference.getFragment()).thenReturn(fragmentPath); + ComponentName pathName = mController.convertClassPathToComponentName(fragmentPath); + when(mBatterySettingsFeatureProvider.getReplacingActivity(any())).thenReturn(pathName); + + assertThat(mController.handlePreferenceTreeClick(preference)).isFalse(); + } + + @Test + public void handlePreferenceTreeClick_newActivityReturned_newActivityRedirected() { + String fragmentPath = "my.fragment.ClassName"; + Preference preference = mock(Preference.class); + when(preference.getFragment()).thenReturn(fragmentPath); + String newFragmentPath = "my.fragment.NewClassName"; + ComponentName newPathName = mController.convertClassPathToComponentName(newFragmentPath); + when(mBatterySettingsFeatureProvider.getReplacingActivity(any())).thenReturn( + newPathName); + doNothing().when(mContext).startActivity(any()); + + assertThat(mController.handlePreferenceTreeClick(preference)).isTrue(); + } + + @Test + public void handlePreferenceTreeClick_calledMultipleTimes_fetchedFromCache() { + String fragmentPath = "my.fragment.ClassName"; + Preference preference = mock(Preference.class); + when(preference.getFragment()).thenReturn(fragmentPath); + String newFragmentPath = "my.fragment.NewClassName"; + ComponentName newPathName = mController.convertClassPathToComponentName(newFragmentPath); + when(mBatterySettingsFeatureProvider.getReplacingActivity(any())).thenReturn( + newPathName); + doNothing().when(mContext).startActivity(any()); + + assertThat(mController.handlePreferenceTreeClick(preference)).isTrue(); + assertThat(mController.handlePreferenceTreeClick(preference)).isTrue(); + verify(mBatterySettingsFeatureProvider, times(1)).getReplacingActivity(any()); + } + + @Test + public void convertClassPathToComponentName_nullInput_returnsNull() { + assertThat(mController.convertClassPathToComponentName(null)).isNull(); + } + + @Test + public void convertClassPathToComponentName_emptyStringInput_returnsNull() { + assertThat(mController.convertClassPathToComponentName("")).isNull(); + } + + @Test + public void convertClassPathToComponentName_singleClassName_returnsCorrectComponentName() { + ComponentName output = mController.convertClassPathToComponentName("ClassName"); + + assertThat(output.getPackageName()).isEqualTo(""); + assertThat(output.getClassName()).isEqualTo("ClassName"); + } + + @Test + public void convertClassPathToComponentName_validAddress_returnsCorrectComponentName() { + ComponentName output = mController.convertClassPathToComponentName("my.fragment.ClassName"); + + assertThat(output.getPackageName()).isEqualTo("my.fragment"); + assertThat(output.getClassName()).isEqualTo("ClassName"); + } + @Test public void getDashboardLabel_returnsCorrectLabel() { BatteryInfo info = new BatteryInfo();