Fix LoaderCallback.onLoadFinished uncalled issue
When two loaders started almost at the same time,
it is possible onLoadFinished is never called.
Bug: 256523472
Test: Unit tests passed and manual test on device
Change-Id: I41a041d5878f9930db44775408380d0d4588faba
Signed-off-by: Zhenwei Chen <zhenwec@google.com>
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
index e376d85..2dba3c2 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageAdvanced.java
@@ -52,7 +52,6 @@
private static final String KEY_REFRESH_TYPE = "refresh_type";
private static final String KEY_BATTERY_GRAPH = "battery_graph";
private static final String KEY_APP_LIST = "app_list";
- private static final int LOADER_BATTERY_USAGE_STATS = 2;
@VisibleForTesting
BatteryHistoryPreference mHistPref;
@@ -165,7 +164,7 @@
bundle.putInt(KEY_REFRESH_TYPE, refreshType);
if (!mIsChartDataLoaded) {
mIsChartDataLoaded = true;
- getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
+ restartLoader(LoaderIndex.BATTERY_HISTORY_LOADER, bundle,
mBatteryHistoryLoaderCallbacks);
}
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
index ccefdf2..ed3a921 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBase.java
@@ -24,6 +24,7 @@
import android.os.UserManager;
import android.util.Log;
+import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.loader.app.LoaderManager;
@@ -33,17 +34,19 @@
import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
import com.android.settings.fuelgauge.BatteryUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Common base class for things that need to show the battery usage graph.
*/
public abstract class PowerUsageBase extends DashboardFragment {
-
private static final String TAG = "PowerUsageBase";
- private static final String KEY_REFRESH_TYPE = "refresh_type";
- private static final String KEY_INCLUDE_HISTORY = "include_history";
- private static final int LOADER_BATTERY_USAGE_STATS = 1;
-
+ @VisibleForTesting
+ static final String KEY_REFRESH_TYPE = "refresh_type";
+ @VisibleForTesting
+ static final String KEY_INCLUDE_HISTORY = "include_history";
@VisibleForTesting
BatteryUsageStats mBatteryUsageStats;
@@ -55,6 +58,21 @@
final BatteryUsageStatsLoaderCallbacks mBatteryUsageStatsLoaderCallbacks =
new BatteryUsageStatsLoaderCallbacks();
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ LoaderIndex.BATTERY_USAGE_STATS_LOADER,
+ LoaderIndex.BATTERY_INFO_LOADER,
+ LoaderIndex.BATTERY_TIP_LOADER,
+ LoaderIndex.BATTERY_HISTORY_LOADER
+
+ })
+ public @interface LoaderIndex {
+ int BATTERY_USAGE_STATS_LOADER = 0;
+ int BATTERY_INFO_LOADER = 1;
+ int BATTERY_TIP_LOADER = 2;
+ int BATTERY_HISTORY_LOADER = 3;
+ }
+
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
@@ -91,10 +109,28 @@
final Bundle bundle = new Bundle();
bundle.putInt(KEY_REFRESH_TYPE, refreshType);
bundle.putBoolean(KEY_INCLUDE_HISTORY, isBatteryHistoryNeeded());
- getLoaderManager().restartLoader(LOADER_BATTERY_USAGE_STATS, bundle,
+ restartLoader(LoaderIndex.BATTERY_USAGE_STATS_LOADER, bundle,
mBatteryUsageStatsLoaderCallbacks);
}
+ protected LoaderManager getLoaderManagerForCurrentFragment() {
+ return LoaderManager.getInstance(this);
+ }
+
+ protected void restartLoader(int loaderId, Bundle bundle,
+ LoaderManager.LoaderCallbacks<?> loaderCallbacks) {
+ LoaderManager loaderManager = getLoaderManagerForCurrentFragment();
+ Loader<?> loader = loaderManager.getLoader(
+ loaderId);
+ if (loader != null && !loader.isReset()) {
+ loaderManager.restartLoader(loaderId, bundle,
+ loaderCallbacks);
+ } else {
+ loaderManager.initLoader(loaderId, bundle,
+ loaderCallbacks);
+ }
+ }
+
protected void onLoadFinished(@BatteryUpdateType int refreshType) {
refreshUi(refreshType);
}
diff --git a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
index bca32a7..f266492 100644
--- a/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
+++ b/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummary.java
@@ -65,11 +65,6 @@
static final String KEY_BATTERY_USAGE = "battery_usage_summary";
@VisibleForTesting
- static final int BATTERY_INFO_LOADER = 1;
- @VisibleForTesting
- static final int BATTERY_TIP_LOADER = 2;
-
- @VisibleForTesting
PowerUsageFeatureProvider mPowerFeatureProvider;
@VisibleForTesting
BatteryUtils mBatteryUtils;
@@ -241,7 +236,7 @@
@VisibleForTesting
void restartBatteryTipLoader() {
- getLoaderManager().restartLoader(BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks);
+ restartLoader(LoaderIndex.BATTERY_TIP_LOADER, Bundle.EMPTY, mBatteryTipsCallbacks);
}
@VisibleForTesting
@@ -274,8 +269,7 @@
if (!mIsBatteryPresent) {
return;
}
- getLoaderManager().restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY,
- mBatteryInfoLoaderCallbacks);
+ restartLoader(LoaderIndex.BATTERY_INFO_LOADER, Bundle.EMPTY, mBatteryInfoLoaderCallbacks);
}
@VisibleForTesting
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
index 2700930..6ed10cd 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageBaseTest.java
@@ -15,18 +15,26 @@
*/
package com.android.settings.fuelgauge.batteryusage;
+import static com.android.settings.fuelgauge.batteryusage.PowerUsageBase.KEY_INCLUDE_HISTORY;
+import static com.android.settings.fuelgauge.batteryusage.PowerUsageBase.KEY_REFRESH_TYPE;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.refEq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
+import android.os.BatteryUsageStats;
import android.os.Bundle;
import androidx.loader.app.LoaderManager;
+import androidx.loader.content.Loader;
+import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
import com.android.settings.testutils.shadow.ShadowDashboardFragment;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -46,14 +54,15 @@
@Mock
private LoaderManager mLoaderManager;
+ @Mock
+ private Loader<BatteryUsageStats> mBatteryUsageStatsLoader;
private TestFragment mFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mFragment = spy(new TestFragment());
- doReturn(mLoaderManager).when(mFragment).getLoaderManager();
+ mFragment = spy(new TestFragment(mLoaderManager));
}
@Test
@@ -63,7 +72,62 @@
verify(mLoaderManager, never()).initLoader(anyInt(), any(Bundle.class), any());
}
- public static class TestFragment extends PowerUsageBase {
+ @Test
+ public void restartBatteryInfoLoader() {
+ final Bundle bundle = new Bundle();
+ bundle.putInt(KEY_REFRESH_TYPE, BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+ bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
+ doReturn(mBatteryUsageStatsLoader).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER);
+ doReturn(false).when(mBatteryUsageStatsLoader).isReset();
+
+ mFragment.restartBatteryStatsLoader(
+ BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+
+ verify(mLoaderManager)
+ .restartLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER),
+ refEq(bundle), any());
+ }
+
+ @Test
+ public void restartBatteryInfoLoader_loaderReset_initLoader() {
+ final Bundle bundle = new Bundle();
+ bundle.putInt(KEY_REFRESH_TYPE, BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+ bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
+ doReturn(mBatteryUsageStatsLoader).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER);
+ doReturn(true).when(mBatteryUsageStatsLoader).isReset();
+
+ mFragment.restartBatteryStatsLoader(
+ BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+
+ verify(mLoaderManager)
+ .initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER),
+ refEq(bundle), any());
+ }
+
+ @Test
+ public void restartBatteryInfoLoader_nullLoader_initLoader() {
+ final Bundle bundle = new Bundle();
+ bundle.putInt(KEY_REFRESH_TYPE, BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+ bundle.putBoolean(KEY_INCLUDE_HISTORY, false);
+ doReturn(null).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER);
+
+ mFragment.restartBatteryStatsLoader(
+ BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_STATUS);
+
+ verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_USAGE_STATS_LOADER),
+ refEq(bundle), any());
+ }
+
+ private static class TestFragment extends PowerUsageBase {
+
+ private LoaderManager mLoaderManager;
+
+ TestFragment(LoaderManager loaderManager) {
+ mLoaderManager = loaderManager;
+ }
@Override
public int getMetricsCategory() {
@@ -94,5 +158,10 @@
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return null;
}
+
+ @Override
+ protected LoaderManager getLoaderManagerForCurrentFragment() {
+ return mLoaderManager;
+ }
}
}
diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
index e134490..e44d92c 100644
--- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
+++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PowerUsageSummaryTest.java
@@ -15,7 +15,6 @@
*/
package com.android.settings.fuelgauge.batteryusage;
-import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.BATTERY_INFO_LOADER;
import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.KEY_BATTERY_ERROR;
import static com.android.settings.fuelgauge.batteryusage.PowerUsageSummary.KEY_BATTERY_USAGE;
@@ -39,14 +38,17 @@
import android.provider.Settings;
import androidx.loader.app.LoaderManager;
+import androidx.loader.content.Loader;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.fuelgauge.BatteryBroadcastReceiver;
+import com.android.settings.fuelgauge.BatteryInfo;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.fuelgauge.batterytip.BatteryTipPreferenceController;
+import com.android.settings.fuelgauge.batterytip.tips.BatteryTip;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.XmlTestUtils;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -69,8 +71,6 @@
// TODO: Improve this test class so that it starts up the real activity and fragment.
@RunWith(RobolectricTestRunner.class)
public class PowerUsageSummaryTest {
-
- private static final long TIME_SINCE_LAST_FULL_CHARGE_MS = 120 * 60 * 1000;
private static Intent sAdditionalBatteryInfoIntent;
@BeforeClass
@@ -83,6 +83,10 @@
@Mock
private LoaderManager mLoaderManager;
@Mock
+ private Loader<BatteryTip> mBatteryTipLoader;
+ @Mock
+ private Loader<BatteryInfo> mBatteryInfoLoader;
+ @Mock
private ContentResolver mContentResolver;
@Mock
private BatteryBroadcastReceiver mBatteryBroadcastReceiver;
@@ -105,11 +109,9 @@
mRealContext = spy(RuntimeEnvironment.application);
mFeatureFactory = FakeFeatureFactory.setupForTest();
- mFragment = spy(new TestFragment(mRealContext));
+ mFragment = spy(new TestFragment(mRealContext, mLoaderManager));
mFragment.initFeatureProvider();
doNothing().when(mFragment).restartBatteryStatsLoader(anyInt());
- doReturn(mock(LoaderManager.class)).when(mFragment).getLoaderManager();
-
when(mFragment.getActivity()).thenReturn(mSettingsActivity);
when(mFeatureFactory.powerUsageFeatureProvider.getAdditionalBatteryInfoIntent())
.thenReturn(sAdditionalBatteryInfoIntent);
@@ -153,12 +155,58 @@
@Test
public void restartBatteryTipLoader() {
//TODO: add policy logic here when BatteryTipPolicy is implemented
- doReturn(mLoaderManager).when(mFragment).getLoaderManager();
+ doReturn(mBatteryTipLoader).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER);
+ doReturn(false).when(mBatteryTipLoader).isReset();
mFragment.restartBatteryTipLoader();
- verify(mLoaderManager)
- .restartLoader(eq(PowerUsageSummary.BATTERY_TIP_LOADER), eq(Bundle.EMPTY), any());
+ verify(mLoaderManager).restartLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER),
+ eq(Bundle.EMPTY), any());
+ }
+
+ @Test
+ public void restartBatteryTipLoader_nullLoader_initLoader() {
+ doReturn(null).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER);
+
+ mFragment.restartBatteryTipLoader();
+
+ verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER),
+ eq(Bundle.EMPTY), any());
+ }
+
+ @Test
+ public void restartBatteryTipLoader_loaderReset_initLoader() {
+ doReturn(mBatteryTipLoader).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER);
+ doReturn(true).when(mBatteryTipLoader).isReset();
+
+ mFragment.restartBatteryTipLoader();
+
+
+ verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_TIP_LOADER),
+ eq(Bundle.EMPTY), any());
+ }
+
+
+ @Test
+ public void refreshUi_contextNull_doNothing() {
+ doReturn(null).when(mFragment).getContext();
+
+ mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
+
+ verify(mFragment, never()).restartBatteryTipLoader();
+ verify(mFragment, never()).restartBatteryInfoLoader();
+ }
+
+ @Test
+ public void refreshUi_batteryNotPresent_doNothing() {
+ mFragment.setIsBatteryPresent(false);
+ mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
+
+ verify(mFragment, never()).restartBatteryTipLoader();
+ verify(mFragment, never()).restartBatteryInfoLoader();
}
@Test
@@ -166,10 +214,12 @@
mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class);
when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(false);
mFragment.updateBatteryTipFlag(new Bundle());
+ doNothing().when(mFragment).restartBatteryInfoLoader();
mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
verify(mFragment, never()).restartBatteryTipLoader();
+ verify(mFragment).restartBatteryInfoLoader();
}
@Test
@@ -177,10 +227,12 @@
mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class);
when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true);
mFragment.updateBatteryTipFlag(new Bundle());
+ doNothing().when(mFragment).restartBatteryInfoLoader();
mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.BATTERY_LEVEL);
verify(mFragment, never()).restartBatteryTipLoader();
+ verify(mFragment).restartBatteryInfoLoader();
}
@Test
@@ -188,10 +240,13 @@
mFragment.mBatteryTipPreferenceController = mock(BatteryTipPreferenceController.class);
when(mFragment.mBatteryTipPreferenceController.needUpdate()).thenReturn(true);
mFragment.updateBatteryTipFlag(new Bundle());
+ doNothing().when(mFragment).restartBatteryInfoLoader();
+ doNothing().when(mFragment).restartBatteryTipLoader();
mFragment.refreshUi(BatteryBroadcastReceiver.BatteryUpdateType.MANUAL);
verify(mFragment).restartBatteryTipLoader();
+ verify(mFragment).restartBatteryInfoLoader();
}
@Test
@@ -215,19 +270,68 @@
@Test
public void restartBatteryInfoLoader_contextNull_doNothing() {
when(mFragment.getContext()).thenReturn(null);
- when(mFragment.getLoaderManager()).thenReturn(mLoaderManager);
mFragment.restartBatteryInfoLoader();
- verify(mLoaderManager, never()).restartLoader(BATTERY_INFO_LOADER, Bundle.EMPTY,
+ verify(mLoaderManager, never()).restartLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER, Bundle.EMPTY,
mFragment.mBatteryInfoLoaderCallbacks);
}
- public static class TestFragment extends PowerUsageSummary {
- private Context mContext;
+ @Test
+ public void restartBatteryInfoLoader_batteryIsNotPresent_doNothing() {
+ mFragment.setIsBatteryPresent(false);
- public TestFragment(Context context) {
+ mFragment.restartBatteryInfoLoader();
+
+ verify(mLoaderManager, never()).restartLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER, Bundle.EMPTY,
+ mFragment.mBatteryInfoLoaderCallbacks);
+ }
+
+ @Test
+ public void restartBatteryInfoLoader() {
+ doReturn(mBatteryInfoLoader).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER);
+ doReturn(false).when(mBatteryTipLoader).isReset();
+
+ mFragment.restartBatteryInfoLoader();
+
+ verify(mLoaderManager).restartLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER),
+ eq(Bundle.EMPTY), any());
+ }
+
+ @Test
+ public void restartBatteryInfoLoader_nullLoader_initLoader() {
+ doReturn(null).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER);
+
+ mFragment.restartBatteryInfoLoader();
+
+ verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER),
+ eq(Bundle.EMPTY), any());
+ }
+
+ @Test
+ public void restartBatteryInfoLoader_loaderReset_initLoader() {
+ mFragment.setIsBatteryPresent(true);
+ doReturn(mBatteryInfoLoader).when(mLoaderManager).getLoader(
+ PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER);
+ doReturn(true).when(mBatteryInfoLoader).isReset();
+
+ mFragment.restartBatteryInfoLoader();
+
+ verify(mLoaderManager).initLoader(eq(PowerUsageBase.LoaderIndex.BATTERY_INFO_LOADER),
+ eq(Bundle.EMPTY), any());
+ }
+
+ private static class TestFragment extends PowerUsageSummary {
+ private Context mContext;
+ private LoaderManager mLoaderManager;
+
+ TestFragment(Context context, LoaderManager loaderManager) {
mContext = context;
+ mLoaderManager = loaderManager;
}
@Override
@@ -240,5 +344,15 @@
// Override it so we can access this method in test
return super.getContentResolver();
}
+
+ public void setIsBatteryPresent(boolean isBatteryPresent) {
+ mIsBatteryPresent = isBatteryPresent;
+ }
+
+ @Override
+ protected LoaderManager getLoaderManagerForCurrentFragment() {
+ return mLoaderManager;
+ }
}
+
}