[DO NOT MERGE] Fix flicker for Data Usage page am: 5a2f5ecff5 am: 298ca56920

Original change: https://googleplex-android-review.googlesource.com/c/platform/packages/apps/Settings/+/18281653

Change-Id: I140a085bc4a18196f28295c1835eebd02f77665e
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Chaohui Wang
2022-05-13 03:55:28 +00:00
committed by Automerger Merge Worker
5 changed files with 74 additions and 56 deletions

View File

@@ -17,7 +17,8 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory <PreferenceCategory
android:key="usage_amount"> android:key="usage_amount"
android:title="@string/summary_placeholder">
<com.android.settings.datausage.ChartDataUsagePreference <com.android.settings.datausage.ChartDataUsagePreference
android:key="chart_data" /> android:key="chart_data" />

View File

@@ -21,7 +21,6 @@ import com.android.settingslib.net.NetworkCycleData;
import com.android.settingslib.widget.SettingsSpinnerAdapter; import com.android.settingslib.widget.SettingsSpinnerAdapter;
import java.util.List; import java.util.List;
import java.util.Objects;
public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> { public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> {
@@ -67,7 +66,7 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem>
* Rebuild list based on network data. Always selects the newest item, * Rebuild list based on network data. Always selects the newest item,
* updating the inspection range on chartData. * updating the inspection range on chartData.
*/ */
public boolean updateCycleList(List<? extends NetworkCycleData> cycleData) { public void updateCycleList(List<? extends NetworkCycleData> cycleData) {
mSpinner.setOnItemSelectedListener(mListener); mSpinner.setOnItemSelectedListener(mListener);
// stash away currently selected cycle to try restoring below // stash away currently selected cycle to try restoring below
final CycleAdapter.CycleItem previousItem = (CycleAdapter.CycleItem) final CycleAdapter.CycleItem previousItem = (CycleAdapter.CycleItem)
@@ -83,16 +82,7 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem>
if (getCount() > 0) { if (getCount() > 0) {
final int position = findNearestPosition(previousItem); final int position = findNearestPosition(previousItem);
mSpinner.setSelection(position); mSpinner.setSelection(position);
// only force-update cycle when changed; skipping preserves any
// user-defined inspection region.
final CycleAdapter.CycleItem selectedItem = getItem(position);
if (!Objects.equals(selectedItem, previousItem)) {
mListener.onItemSelected(null, null, position, 0);
return false;
}
} }
return true;
} }
/** /**

View File

@@ -69,6 +69,7 @@ import com.android.settingslib.net.UidDetailProvider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* Panel showing data usage history across various networks, including options * Panel showing data usage history across various networks, including options
@@ -111,7 +112,11 @@ public class DataUsageList extends DataUsageBaseFragment
private ChartDataUsagePreference mChart; private ChartDataUsagePreference mChart;
private List<NetworkCycleChartData> mCycleData; private List<NetworkCycleChartData> mCycleData;
// Caches the cycles for startAppDataUsage usage, which need be cleared when resumed.
private ArrayList<Long> mCycles; private ArrayList<Long> mCycles;
// Spinner will keep the selected cycle even after paused, this only keeps the displayed cycle,
// which need be cleared when resumed.
private CycleAdapter.CycleItem mLastDisplayedCycle;
private UidDetailProvider mUidDetailProvider; private UidDetailProvider mUidDetailProvider;
private CycleAdapter mCycleAdapter; private CycleAdapter mCycleAdapter;
private Preference mUsageAmount; private Preference mUsageAmount;
@@ -199,13 +204,15 @@ public class DataUsageList extends DataUsageBaseFragment
mLoadingViewController = new LoadingViewController( mLoadingViewController = new LoadingViewController(
getView().findViewById(R.id.loading_container), getListView()); getView().findViewById(R.id.loading_container), getListView());
mLoadingViewController.showLoadingViewDelayed();
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
mLoadingViewController.showLoadingViewDelayed();
mDataStateListener.start(mSubId); mDataStateListener.start(mSubId);
mCycles = null;
mLastDisplayedCycle = null;
// kick off loader for network history // kick off loader for network history
// TODO: consider chaining two loaders together instead of reloading // TODO: consider chaining two loaders together instead of reloading
@@ -319,9 +326,46 @@ public class DataUsageList extends DataUsageBaseFragment
} }
// generate cycle list based on policy and available history // generate cycle list based on policy and available history
if (mCycleAdapter.updateCycleList(mCycleData)) { mCycleAdapter.updateCycleList(mCycleData);
updateDetailData(); updateSelectedCycle();
}
/**
* Updates the chart and detail data when initial loaded or selected cycle changed.
*/
private void updateSelectedCycle() {
// Avoid from updating UI after #onStop.
if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
return;
} }
// Avoid from updating UI when async query still on-going.
// This could happen when a request from #onMobileDataEnabledChange.
if (mCycleData == null) {
return;
}
final int position = mCycleSpinner.getSelectedItemPosition();
if (mCycleAdapter.getCount() == 0 || position < 0) {
return;
}
final CycleAdapter.CycleItem cycle = mCycleAdapter.getItem(position);
if (Objects.equals(cycle, mLastDisplayedCycle)) {
// Avoid duplicate update to avoid page flash.
return;
}
mLastDisplayedCycle = cycle;
if (LOGD) {
Log.d(TAG, "showing cycle " + cycle + ", [start=" + cycle.start + ", end="
+ cycle.end + "]");
}
// update chart to show selected cycle, and update detail data
// to match updated sweep bounds.
mChart.setNetworkCycleData(mCycleData.get(position));
updateDetailData();
} }
/** /**
@@ -495,33 +539,10 @@ public class DataUsageList extends DataUsageBaseFragment
return Math.max(largest, item.total); return Math.max(largest, item.total);
} }
private OnItemSelectedListener mCycleListener = new OnItemSelectedListener() { private final OnItemSelectedListener mCycleListener = new OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem) updateSelectedCycle();
mCycleSpinner.getSelectedItem();
if (LOGD) {
Log.d(TAG, "showing cycle " + cycle + ", start=" + cycle.start + ", end="
+ cycle.end + "]");
}
// Avoid from updating UI after #onStop.
if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
return;
}
// Avoid from updating UI when async query still on-going.
// This could happen when a request from #onMobileDataEnabledChange.
if (mCycleData == null) {
return;
}
// update chart to show selected cycle, and update detail data
// to match updated sweep bounds.
mChart.setNetworkCycleData(mCycleData.get(position));
updateDetailData();
} }
@Override @Override

View File

@@ -14,6 +14,7 @@
package com.android.settings.datausage; package com.android.settings.datausage;
import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
@@ -28,6 +29,7 @@ import com.android.settings.R;
public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface { public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface {
private CycleAdapter mAdapter; private CycleAdapter mAdapter;
@Nullable
private AdapterView.OnItemSelectedListener mListener; private AdapterView.OnItemSelectedListener mListener;
private Object mCurrentObject; private Object mCurrentObject;
private int mPosition; private int mPosition;
@@ -88,19 +90,24 @@ public class SpinnerPreference extends Preference implements CycleAdapter.Spinne
view.findViewById(R.id.cycles_spinner).performClick(); view.findViewById(R.id.cycles_spinner).performClick();
} }
private final AdapterView.OnItemSelectedListener mOnSelectedListener private final AdapterView.OnItemSelectedListener mOnSelectedListener =
= new AdapterView.OnItemSelectedListener() { new AdapterView.OnItemSelectedListener() {
@Override @Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected(
if (mPosition == position) return; AdapterView<?> parent, View view, int position, long id) {
mPosition = position; if (mPosition == position) return;
mCurrentObject = mAdapter.getItem(position); mPosition = position;
mListener.onItemSelected(parent, view, position, id); mCurrentObject = mAdapter.getItem(position);
} if (mListener != null) {
mListener.onItemSelected(parent, view, position, id);
}
}
@Override @Override
public void onNothingSelected(AdapterView<?> parent) { public void onNothingSelected(AdapterView<?> parent) {
mListener.onNothingSelected(parent); if (mListener != null) {
} mListener.onNothingSelected(parent);
}; }
}
};
} }

View File

@@ -94,6 +94,7 @@ public class DataUsageListTest {
mMobileDataEnabledListener); mMobileDataEnabledListener);
ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices); ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices);
doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager(); doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager();
mDataUsageList.mLoadingViewController = mock(LoadingViewController.class);
} }
@Test @Test
@@ -207,8 +208,6 @@ public class DataUsageListTest {
@Test @Test
public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() { public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() {
final LoadingViewController loadingViewController = mock(LoadingViewController.class);
mDataUsageList.mLoadingViewController = loadingViewController;
final Spinner spinner = getSpinner(getHeader()); final Spinner spinner = getSpinner(getHeader());
spinner.setVisibility(View.INVISIBLE); spinner.setVisibility(View.INVISIBLE);
mDataUsageList.mCycleSpinner = spinner; mDataUsageList.mCycleSpinner = spinner;