Loading res/xml/data_usage_list.xml +2 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:key="usage_amount"> android:key="usage_amount" android:title="@string/summary_placeholder"> <com.android.settings.datausage.ChartDataUsagePreference android:key="chart_data" /> Loading src/com/android/settings/datausage/CycleAdapter.java +1 −11 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import com.android.settingslib.net.NetworkCycleData; import com.android.settingslib.widget.SettingsSpinnerAdapter; import java.util.List; import java.util.Objects; public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> { Loading Loading @@ -67,7 +66,7 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> * Rebuild list based on network data. Always selects the newest item, * updating the inspection range on chartData. */ public boolean updateCycleList(List<? extends NetworkCycleData> cycleData) { public void updateCycleList(List<? extends NetworkCycleData> cycleData) { mSpinner.setOnItemSelectedListener(mListener); // stash away currently selected cycle to try restoring below final CycleAdapter.CycleItem previousItem = (CycleAdapter.CycleItem) Loading @@ -83,16 +82,7 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> if (getCount() > 0) { final int position = findNearestPosition(previousItem); 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; } /** Loading src/com/android/settings/datausage/DataUsageList.java +49 −28 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import com.android.settingslib.net.UidDetailProvider; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; /** * Panel showing data usage history across various networks, including options Loading Loading @@ -111,7 +112,11 @@ public class DataUsageList extends DataUsageBaseFragment private ChartDataUsagePreference mChart; private List<NetworkCycleChartData> mCycleData; // Caches the cycles for startAppDataUsage usage, which need be cleared when resumed. 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 CycleAdapter mCycleAdapter; private Preference mUsageAmount; Loading Loading @@ -199,13 +204,15 @@ public class DataUsageList extends DataUsageBaseFragment mLoadingViewController = new LoadingViewController( getView().findViewById(R.id.loading_container), getListView()); mLoadingViewController.showLoadingViewDelayed(); } @Override public void onResume() { super.onResume(); mLoadingViewController.showLoadingViewDelayed(); mDataStateListener.start(mSubId); mCycles = null; mLastDisplayedCycle = null; // kick off loader for network history // TODO: consider chaining two loaders together instead of reloading Loading Loading @@ -319,9 +326,46 @@ public class DataUsageList extends DataUsageBaseFragment } // generate cycle list based on policy and available history if (mCycleAdapter.updateCycleList(mCycleData)) { updateDetailData(); mCycleAdapter.updateCycleList(mCycleData); 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(); } /** Loading Loading @@ -495,33 +539,10 @@ public class DataUsageList extends DataUsageBaseFragment return Math.max(largest, item.total); } private OnItemSelectedListener mCycleListener = new OnItemSelectedListener() { private final OnItemSelectedListener mCycleListener = new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem) 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(); updateSelectedCycle(); } @Override Loading src/com/android/settings/datausage/SpinnerPreference.java +22 −15 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ package com.android.settings.datausage; import android.annotation.Nullable; import android.content.Context; import android.util.AttributeSet; import android.view.View; Loading @@ -28,6 +29,7 @@ import com.android.settings.R; public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface { private CycleAdapter mAdapter; @Nullable private AdapterView.OnItemSelectedListener mListener; private Object mCurrentObject; private int mPosition; Loading Loading @@ -88,19 +90,24 @@ public class SpinnerPreference extends Preference implements CycleAdapter.Spinne view.findViewById(R.id.cycles_spinner).performClick(); } private final AdapterView.OnItemSelectedListener mOnSelectedListener = new AdapterView.OnItemSelectedListener() { private final AdapterView.OnItemSelectedListener mOnSelectedListener = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected( AdapterView<?> parent, View view, int position, long id) { if (mPosition == position) return; mPosition = position; mCurrentObject = mAdapter.getItem(position); if (mListener != null) { mListener.onItemSelected(parent, view, position, id); } } @Override public void onNothingSelected(AdapterView<?> parent) { if (mListener != null) { mListener.onNothingSelected(parent); } } }; } tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java +1 −2 Original line number Diff line number Diff line Loading @@ -94,6 +94,7 @@ public class DataUsageListTest { mMobileDataEnabledListener); ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices); doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager(); mDataUsageList.mLoadingViewController = mock(LoadingViewController.class); } @Test Loading Loading @@ -207,8 +208,6 @@ public class DataUsageListTest { @Test public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() { final LoadingViewController loadingViewController = mock(LoadingViewController.class); mDataUsageList.mLoadingViewController = loadingViewController; final Spinner spinner = getSpinner(getHeader()); spinner.setVisibility(View.INVISIBLE); mDataUsageList.mCycleSpinner = spinner; Loading Loading
res/xml/data_usage_list.xml +2 −1 Original line number Diff line number Diff line Loading @@ -17,7 +17,8 @@ <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:key="usage_amount"> android:key="usage_amount" android:title="@string/summary_placeholder"> <com.android.settings.datausage.ChartDataUsagePreference android:key="chart_data" /> Loading
src/com/android/settings/datausage/CycleAdapter.java +1 −11 Original line number Diff line number Diff line Loading @@ -21,7 +21,6 @@ import com.android.settingslib.net.NetworkCycleData; import com.android.settingslib.widget.SettingsSpinnerAdapter; import java.util.List; import java.util.Objects; public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> { Loading Loading @@ -67,7 +66,7 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> * Rebuild list based on network data. Always selects the newest item, * updating the inspection range on chartData. */ public boolean updateCycleList(List<? extends NetworkCycleData> cycleData) { public void updateCycleList(List<? extends NetworkCycleData> cycleData) { mSpinner.setOnItemSelectedListener(mListener); // stash away currently selected cycle to try restoring below final CycleAdapter.CycleItem previousItem = (CycleAdapter.CycleItem) Loading @@ -83,16 +82,7 @@ public class CycleAdapter extends SettingsSpinnerAdapter<CycleAdapter.CycleItem> if (getCount() > 0) { final int position = findNearestPosition(previousItem); 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; } /** Loading
src/com/android/settings/datausage/DataUsageList.java +49 −28 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import com.android.settingslib.net.UidDetailProvider; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; /** * Panel showing data usage history across various networks, including options Loading Loading @@ -111,7 +112,11 @@ public class DataUsageList extends DataUsageBaseFragment private ChartDataUsagePreference mChart; private List<NetworkCycleChartData> mCycleData; // Caches the cycles for startAppDataUsage usage, which need be cleared when resumed. 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 CycleAdapter mCycleAdapter; private Preference mUsageAmount; Loading Loading @@ -199,13 +204,15 @@ public class DataUsageList extends DataUsageBaseFragment mLoadingViewController = new LoadingViewController( getView().findViewById(R.id.loading_container), getListView()); mLoadingViewController.showLoadingViewDelayed(); } @Override public void onResume() { super.onResume(); mLoadingViewController.showLoadingViewDelayed(); mDataStateListener.start(mSubId); mCycles = null; mLastDisplayedCycle = null; // kick off loader for network history // TODO: consider chaining two loaders together instead of reloading Loading Loading @@ -319,9 +326,46 @@ public class DataUsageList extends DataUsageBaseFragment } // generate cycle list based on policy and available history if (mCycleAdapter.updateCycleList(mCycleData)) { updateDetailData(); mCycleAdapter.updateCycleList(mCycleData); 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(); } /** Loading Loading @@ -495,33 +539,10 @@ public class DataUsageList extends DataUsageBaseFragment return Math.max(largest, item.total); } private OnItemSelectedListener mCycleListener = new OnItemSelectedListener() { private final OnItemSelectedListener mCycleListener = new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem) 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(); updateSelectedCycle(); } @Override Loading
src/com/android/settings/datausage/SpinnerPreference.java +22 −15 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ package com.android.settings.datausage; import android.annotation.Nullable; import android.content.Context; import android.util.AttributeSet; import android.view.View; Loading @@ -28,6 +29,7 @@ import com.android.settings.R; public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface { private CycleAdapter mAdapter; @Nullable private AdapterView.OnItemSelectedListener mListener; private Object mCurrentObject; private int mPosition; Loading Loading @@ -88,19 +90,24 @@ public class SpinnerPreference extends Preference implements CycleAdapter.Spinne view.findViewById(R.id.cycles_spinner).performClick(); } private final AdapterView.OnItemSelectedListener mOnSelectedListener = new AdapterView.OnItemSelectedListener() { private final AdapterView.OnItemSelectedListener mOnSelectedListener = new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { public void onItemSelected( AdapterView<?> parent, View view, int position, long id) { if (mPosition == position) return; mPosition = position; mCurrentObject = mAdapter.getItem(position); if (mListener != null) { mListener.onItemSelected(parent, view, position, id); } } @Override public void onNothingSelected(AdapterView<?> parent) { if (mListener != null) { mListener.onNothingSelected(parent); } } }; }
tests/robotests/src/com/android/settings/datausage/DataUsageListTest.java +1 −2 Original line number Diff line number Diff line Loading @@ -94,6 +94,7 @@ public class DataUsageListTest { mMobileDataEnabledListener); ReflectionHelpers.setField(mDataUsageList, "services", mNetworkServices); doReturn(mLoaderManager).when(mDataUsageList).getLoaderManager(); mDataUsageList.mLoadingViewController = mock(LoadingViewController.class); } @Test Loading Loading @@ -207,8 +208,6 @@ public class DataUsageListTest { @Test public void onLoadFinished_networkCycleDataCallback_shouldShowCycleSpinner() { final LoadingViewController loadingViewController = mock(LoadingViewController.class); mDataUsageList.mLoadingViewController = loadingViewController; final Spinner spinner = getSpinner(getHeader()); spinner.setVisibility(View.INVISIBLE); mDataUsageList.mCycleSpinner = spinner; Loading