Add data saver to settings

Bug: 22817899

Change-Id: Ic3055aa6a5baae1653db350313366f180c049cc7
This commit is contained in:
Jason Monk
2016-01-21 14:12:11 -05:00
parent 3d71918c58
commit 764f45db91
18 changed files with 755 additions and 53 deletions

View File

@@ -14,14 +14,6 @@
package com.android.settings.datausage;
import com.android.settings.AppHeader;
import com.android.settings.InstrumentedFragment;
import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settingslib.AppItem;
import com.android.settingslib.net.ChartData;
import com.android.settingslib.net.ChartDataLoader;
import android.app.LoaderManager;
import android.content.Context;
import android.content.Intent;
@@ -43,10 +35,15 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.text.format.Formatter;
import android.util.ArraySet;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Spinner;
import com.android.settings.AppHeader;
import com.android.settings.InstrumentedFragment;
import com.android.settings.R;
import com.android.settings.applications.AppInfoBase;
import com.android.settingslib.AppItem;
import com.android.settingslib.net.ChartData;
import com.android.settingslib.net.ChartDataLoader;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
@@ -62,6 +59,8 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
private static final String KEY_APP_SETTINGS = "app_settings";
private static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
private static final String KEY_APP_LIST = "app_list";
private static final String KEY_CYCLE = "cycle";
private static final String KEY_UNRESTRICTED_DATA = "unrestricted_data_saver";
private static final int LOADER_CHART_DATA = 2;
@@ -76,7 +75,6 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
private Drawable mIcon;
private CharSequence mLabel;
private INetworkStatsSession mStatsSession;
private Spinner mCycleSpinner;
private CycleAdapter mCycleAdapter;
private long mStart;
@@ -86,6 +84,9 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
private NetworkPolicy mPolicy;
private AppItem mAppItem;
private Intent mAppSettingsIntent;
private SpinnerPreference mCycle;
private SwitchPreference mUnrestrictedData;
private DataSaverBackend mDataSaverBackend;
@Override
public void onCreate(Bundle icicle) {
@@ -137,9 +138,15 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
mForegroundUsage = findPreference(KEY_FOREGROUND_USAGE);
mBackgroundUsage = findPreference(KEY_BACKGROUND_USAGE);
mCycle = (SpinnerPreference) findPreference(KEY_CYCLE);
mCycleAdapter = new CycleAdapter(getContext(), mCycle, mCycleListener, false);
if (UserHandle.isApp(mAppItem.key)) {
mRestrictBackground = (SwitchPreference) findPreference(KEY_RESTRICT_BACKGROUND);
mRestrictBackground.setOnPreferenceChangeListener(this);
mUnrestrictedData = (SwitchPreference) findPreference(KEY_UNRESTRICTED_DATA);
mUnrestrictedData.setOnPreferenceChangeListener(this);
mDataSaverBackend = new DataSaverBackend(getContext());
mAppSettings = findPreference(KEY_APP_SETTINGS);
mAppSettingsIntent = new Intent(Intent.ACTION_MANAGE_NETWORK_USAGE);
@@ -169,6 +176,7 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
removePreference(KEY_APP_LIST);
}
} else {
removePreference(KEY_UNRESTRICTED_DATA);
removePreference(KEY_APP_SETTINGS);
removePreference(KEY_RESTRICT_BACKGROUND);
removePreference(KEY_APP_LIST);
@@ -195,6 +203,9 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
if (preference == mRestrictBackground) {
setAppRestrictBackground((Boolean) newValue);
return true;
} else if (preference == mUnrestrictedData) {
mDataSaverBackend.setIsWhitelisted(mAppItem.key, (Boolean) newValue);
return true;
}
return false;
}
@@ -214,6 +225,9 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
if (mRestrictBackground != null) {
mRestrictBackground.setChecked(getAppRestrictBackground());
}
if (mUnrestrictedData != null) {
mUnrestrictedData.setChecked(mDataSaverBackend.isWhitelisted(mAppItem.key));
}
}
private void addUid(int uid) {
@@ -260,7 +274,7 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
View header = setPinnedHeaderView(R.layout.data_usage_app_header);
View header = setPinnedHeaderView(R.layout.app_header);
String pkg = mPackages.size() != 0 ? mPackages.valueAt(0) : null;
int uid = 0;
try {
@@ -269,9 +283,6 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
}
AppHeader.setupHeaderView(getActivity(), mIcon, mLabel,
pkg, uid, AppHeader.includeAppInfo(this), 0, header);
mCycleSpinner = (Spinner) header.findViewById(R.id.filter_spinner);
mCycleAdapter = new CycleAdapter(getContext(), mCycleSpinner, mCycleListener);
}
@Override
@@ -283,8 +294,7 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
final CycleAdapter.CycleItem cycle =
(CycleAdapter.CycleItem) parent.getItemAtPosition(position);
final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem) mCycle.getSelectedItem();
mStart = cycle.start;
mEnd = cycle.end;

View File

@@ -0,0 +1,56 @@
/*
* Copyright (C) 2016 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.datausage;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import java.util.ArrayList;
public class AppStateDataUsageBridge extends AppStateBaseBridge {
private static final String TAG = "AppStateDataUsageBridge";
private final DataSaverBackend mDataSaverBackend;
public AppStateDataUsageBridge(ApplicationsState appState, Callback callback,
DataSaverBackend backend) {
super(appState, callback);
mDataSaverBackend = backend;
}
@Override
protected void loadAllExtraInfo() {
ArrayList<AppEntry> apps = mAppSession.getAllApps();
final int N = apps.size();
for (int i = 0; i < N; i++) {
AppEntry app = apps.get(i);
app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(app.info.uid));
}
}
@Override
protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(uid));
}
public static class DataUsageState {
public boolean isDataSaverWhitelisted;
public DataUsageState(boolean isDataSaverWhitelisted) {
this.isDataSaverWhitelisted = isDataSaverWhitelisted;
}
}
}

View File

@@ -13,17 +13,15 @@
*/
package com.android.settings.datausage;
import com.android.settings.Utils;
import com.android.settingslib.net.ChartData;
import android.content.Context;
import android.net.NetworkPolicy;
import android.net.NetworkStatsHistory;
import android.text.format.DateUtils;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settingslib.net.ChartData;
import libcore.util.Objects;
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
@@ -31,12 +29,13 @@ import static android.net.NetworkPolicyManager.computeNextCycleBoundary;
public class CycleAdapter extends ArrayAdapter<CycleAdapter.CycleItem> {
private final Spinner mSpinner;
private final SpinnerInterface mSpinner;
private final AdapterView.OnItemSelectedListener mListener;
public CycleAdapter(Context context, Spinner spinner,
AdapterView.OnItemSelectedListener listener) {
super(context, com.android.settings.R.layout.filter_spinner_item);
public CycleAdapter(Context context, SpinnerInterface spinner,
AdapterView.OnItemSelectedListener listener, boolean isHeader) {
super(context, isHeader ? R.layout.filter_spinner_item
: R.layout.data_usage_cycle_item);
setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpinner = spinner;
mListener = listener;
@@ -72,7 +71,7 @@ public class CycleAdapter extends ArrayAdapter<CycleAdapter.CycleItem> {
mSpinner.getSelectedItem();
clear();
final Context context = mSpinner.getContext();
final Context context = getContext();
NetworkStatsHistory.Entry entry = null;
long historyStart = Long.MAX_VALUE;
@@ -141,7 +140,7 @@ public class CycleAdapter extends ArrayAdapter<CycleAdapter.CycleItem> {
// user-defined inspection region.
final CycleAdapter.CycleItem selectedItem = getItem(position);
if (!Objects.equal(selectedItem, previousItem)) {
mListener.onItemSelected(mSpinner, null, position, 0);
mListener.onItemSelected(null, null, position, 0);
return false;
}
}
@@ -185,4 +184,11 @@ public class CycleAdapter extends ArrayAdapter<CycleAdapter.CycleItem> {
return Long.compare(start, another.start);
}
}
public interface SpinnerInterface {
void setAdapter(CycleAdapter cycleAdapter);
void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener);
Object getSelectedItem();
void setSelection(int position);
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (C) 2016 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.datausage;
import android.content.Context;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.net.NetworkPolicyManager;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.util.SparseBooleanArray;
import java.util.ArrayList;
public class DataSaverBackend {
private static final String TAG = "DataSaverBackend";
private final Context mContext;
private final Handler mHandler = new Handler();
private final NetworkPolicyManager mPolicyManager;
private final INetworkPolicyManager mIPolicyManager;
private final ArrayList<Listener> mListeners = new ArrayList<>();
private SparseBooleanArray mWhitelist;
// TODO: Staticize into only one.
public DataSaverBackend(Context context) {
mContext = context;
mIPolicyManager = INetworkPolicyManager.Stub.asInterface(
ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
mPolicyManager = NetworkPolicyManager.from(context);
}
public void addListener(Listener listener) {
mListeners.add(listener);
if (mListeners.size() == 1) {
mPolicyManager.registerListener(mPolicyListener);
}
listener.onDataSaverChanged(isDataSaverEnabled());
}
public void remListener(Listener listener) {
mListeners.remove(listener);
if (mListeners.size() == 0) {
mPolicyManager.unregisterListener(mPolicyListener);
}
}
public boolean isDataSaverEnabled() {
return mPolicyManager.getRestrictBackground();
}
public void setDataSaverEnabled(boolean enabled) {
mPolicyManager.setRestrictBackground(enabled);
}
public void refreshWhitelist() {
loadWhitelist();
}
public void setIsWhitelisted(int uid, boolean whitelisted) {
mWhitelist.put(uid, whitelisted);
try {
if (whitelisted) {
mIPolicyManager.addRestrictBackgroundWhitelistedUid(uid);
} else {
mIPolicyManager.removeRestrictBackgroundWhitelistedUid(uid);
}
} catch (RemoteException e) {
Log.w(TAG, "Can't reach policy manager", e);
}
}
public boolean isWhitelisted(int uid) {
if (mWhitelist == null) {
loadWhitelist();
}
return mWhitelist.get(uid);
}
public int getWhitelistedCount() {
int count = 0;
if (mWhitelist == null) {
loadWhitelist();
}
for (int i = 0; i < mWhitelist.size(); i++) {
if (mWhitelist.valueAt(i)) {
count++;
}
}
return count;
}
private void loadWhitelist() {
mWhitelist = new SparseBooleanArray();
try {
for (int uid : mIPolicyManager.getRestrictBackgroundWhitelistedUids()) {
mWhitelist.put(uid, true);
}
} catch (RemoteException e) {
}
}
private void handleRestrictBackgroundChanged(boolean isDataSaving) {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onDataSaverChanged(isDataSaving);
}
}
private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
@Override
public void onUidRulesChanged(int i, int i1) throws RemoteException {
}
@Override
public void onMeteredIfacesChanged(String[] strings) throws RemoteException {
}
@Override
public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException {
mHandler.post(new Runnable() {
@Override
public void run() {
handleRestrictBackgroundChanged(isDataSaving);
}
});
}
};
public interface Listener {
void onDataSaverChanged(boolean isDataSaving);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright (C) 2016 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.datausage;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.util.AttributeSet;
import com.android.settings.R;
public class DataSaverPreference extends Preference implements DataSaverBackend.Listener {
private final DataSaverBackend mDataSaverBackend;
public DataSaverPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mDataSaverBackend = new DataSaverBackend(context);
}
@Override
public void onAttached() {
super.onAttached();
mDataSaverBackend.addListener(this);
}
@Override
public void onDetached() {
super.onDetached();
mDataSaverBackend.addListener(this);
}
@Override
public void onDataSaverChanged(boolean isDataSaving) {
setSummary(isDataSaving ? R.string.data_saver_on : R.string.data_saver_off);
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright (C) 2016 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.datausage;
import android.os.Bundle;
import android.support.v7.preference.Preference;
import android.util.Log;
import android.widget.Switch;
import com.android.settings.InstrumentedFragment;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.widget.SwitchBar;
public class DataSaverSummary extends SettingsPreferenceFragment
implements SwitchBar.OnSwitchChangeListener, DataSaverBackend.Listener {
private static final String KEY_UNRESTRICTED_ACCESS = "unrestricted_access";
private SwitchBar mSwitchBar;
private DataSaverBackend mDataSaverBackend;
private Preference mUnrestrictedAccess;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
addPreferencesFromResource(R.xml.data_saver);
mUnrestrictedAccess = findPreference(KEY_UNRESTRICTED_ACCESS);
mDataSaverBackend = new DataSaverBackend(getContext());
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSwitchBar = ((SettingsActivity) getActivity()).getSwitchBar();
mSwitchBar.show();
mSwitchBar.addOnSwitchChangeListener(this);
}
@Override
public void onResume() {
super.onResume();
mDataSaverBackend.addListener(this);
mDataSaverBackend.refreshWhitelist();
int count = mDataSaverBackend.getWhitelistedCount();
mUnrestrictedAccess.setSummary(getResources().getQuantityString(
R.plurals.data_saver_unrestricted_summary, count, count));
}
@Override
public void onPause() {
super.onPause();
mDataSaverBackend.remListener(this);
}
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
mDataSaverBackend.setDataSaverEnabled(isChecked);
}
@Override
protected int getMetricsCategory() {
return InstrumentedFragment.DATA_SAVER_SUMMARY;
}
@Override
public void onDataSaverChanged(boolean isDataSaving) {
mSwitchBar.setChecked(isDataSaving);
}
}

View File

@@ -147,7 +147,27 @@ public class DataUsageList extends DataUsageBase {
mHeader = setPinnedHeaderView(R.layout.apps_filter_spinner);
mCycleSpinner = (Spinner) mHeader.findViewById(R.id.filter_spinner);
mCycleAdapter = new CycleAdapter(getContext(), mCycleSpinner, mCycleListener);
mCycleAdapter = new CycleAdapter(getContext(), new CycleAdapter.SpinnerInterface() {
@Override
public void setAdapter(CycleAdapter cycleAdapter) {
mCycleSpinner.setAdapter(cycleAdapter);
}
@Override
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
mCycleSpinner.setOnItemSelectedListener(listener);
}
@Override
public Object getSelectedItem() {
return mCycleSpinner.getSelectedItem();
}
@Override
public void setSelection(int position) {
mCycleSpinner.setSelection(position);
}
}, mCycleListener, true);
setLoading(true, false);
}
@@ -470,7 +490,7 @@ public class DataUsageList extends DataUsageBase {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
final CycleAdapter.CycleItem cycle = (CycleAdapter.CycleItem)
parent.getItemAtPosition(position);
mCycleSpinner.getSelectedItem();
if (LOGD) {
Log.d(TAG, "showing cycle " + cycle + ", start=" + cycle.start + ", end="

View File

@@ -0,0 +1,90 @@
/*
* Copyright (C) 2016 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.datausage;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Spinner;
import com.android.settings.R;
public class SpinnerPreference extends Preference implements CycleAdapter.SpinnerInterface {
private CycleAdapter mAdapter;
private AdapterView.OnItemSelectedListener mListener;
private Object mCurrentObject;
private int mPosition;
public SpinnerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setLayoutResource(R.layout.data_usage_cycles);
}
@Override
public void setAdapter(CycleAdapter cycleAdapter) {
mAdapter = cycleAdapter;
notifyChanged();
}
@Override
public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {
mListener = listener;
}
@Override
public Object getSelectedItem() {
return mCurrentObject;
}
@Override
public void setSelection(int position) {
mPosition = position;
mCurrentObject = mAdapter.getItem(mPosition);
notifyChanged();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
Spinner spinner = (Spinner) holder.findViewById(R.id.cycles_spinner);
spinner.setAdapter(mAdapter);
spinner.setSelection(mPosition);
spinner.setOnItemSelectedListener(mOnSelectedListener);
}
@Override
protected void performClick(View view) {
view.findViewById(R.id.cycles_spinner).performClick();
}
private final AdapterView.OnItemSelectedListener mOnSelectedListener
= new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (mPosition == position) return;
mPosition = position;
mCurrentObject = mAdapter.getItem(position);
mListener.onItemSelected(parent, view, position, id);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
mListener.onNothingSelected(parent);
}
};
}

View File

@@ -0,0 +1,184 @@
/*
* Copyright (C) 2016 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.datausage;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.view.View;
import com.android.settings.InstrumentedFragment;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settingslib.applications.ApplicationsState;
import java.util.ArrayList;
public class UnrestrictedDataAccess extends SettingsPreferenceFragment
implements ApplicationsState.Callbacks, AppStateBaseBridge.Callback, Preference.OnPreferenceChangeListener {
private ApplicationsState mApplicationsState;
private AppStateDataUsageBridge mDataUsageBridge;
private ApplicationsState.Session mSession;
private DataSaverBackend mDataSaverBackend;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
getPreferenceScreen().setOrderingAsAdded(false);
mApplicationsState = ApplicationsState.getInstance(
(Application) getContext().getApplicationContext());
mDataSaverBackend = new DataSaverBackend(getContext());
mDataUsageBridge = new AppStateDataUsageBridge(mApplicationsState, this, mDataSaverBackend);
mSession = mApplicationsState.newSession(this);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setLoading(true, false);
}
@Override
public void onResume() {
super.onResume();
mSession.resume();
mDataUsageBridge.resume();
}
@Override
public void onPause() {
super.onPause();
mDataUsageBridge.pause();
mSession.pause();
}
@Override
public void onDestroy() {
super.onDestroy();
mSession.release();
mDataUsageBridge.release();
}
@Override
public void onExtraInfoUpdated() {
ArrayList<ApplicationsState.AppEntry> apps = mSession.getAllApps();
final int N = apps.size();
for (int i = 0; i < N; i++) {
ApplicationsState.AppEntry entry = apps.get(i);
String key = entry.info.packageName + "|" + entry.info.uid;
AccessPreference preference = (AccessPreference) findPreference(key);
if (preference == null) {
preference = new AccessPreference(getContext(), entry);
preference.setKey(key);
preference.setOnPreferenceChangeListener(this);
getPreferenceScreen().addPreference(preference);
}
AppStateDataUsageBridge.DataUsageState state =
(AppStateDataUsageBridge.DataUsageState) entry.extraInfo;
preference.setChecked(state.isDataSaverWhitelisted);
}
setLoading(false, true);
}
@Override
public void onRunningStateChanged(boolean running) {
}
@Override
public void onPackageListChanged() {
}
@Override
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
}
@Override
public void onPackageIconChanged() {
}
@Override
public void onPackageSizeChanged(String packageName) {
}
@Override
public void onAllSizesComputed() {
}
@Override
public void onLauncherInfoChanged() {
}
@Override
public void onLoadEntriesCompleted() {
}
@Override
protected int getMetricsCategory() {
return InstrumentedFragment.DATA_USAGE_UNRESTRICTED_ACCESS;
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference instanceof AccessPreference) {
AccessPreference accessPreference = (AccessPreference) preference;
boolean whitelisted = newValue == Boolean.TRUE;
mDataSaverBackend.setIsWhitelisted(accessPreference.mEntry.info.uid, whitelisted);
((AppStateDataUsageBridge.DataUsageState) accessPreference.mEntry.extraInfo)
.isDataSaverWhitelisted = whitelisted;
return true;
}
return false;
}
private class AccessPreference extends SwitchPreference {
private final ApplicationsState.AppEntry mEntry;
public AccessPreference(Context context, ApplicationsState.AppEntry entry) {
super(context);
mEntry = entry;
mEntry.ensureLabel(getContext());
setTitle(entry.label);
setChecked(((AppStateDataUsageBridge.DataUsageState) entry.extraInfo)
.isDataSaverWhitelisted);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
holder.itemView.post(new Runnable() {
@Override
public void run() {
// Ensure we have an icon before binding.
mApplicationsState.ensureIcon(mEntry);
// This might trigger us to bind again, but it gives an easy way to only load the icon
// once its needed, so its probably worth it.
setIcon(mEntry.icon);
}
});
super.onBindViewHolder(holder);
}
}
}