<!-- Button that leads to list of apps with unrestricted data access [CHAR LIMIT=60] -->
<string name="unrestricted_data_saver">Unrestricted data access</string>
+ <!-- Description of message shown when app is blacklisted for background data access [CHAR LIMIT=NONE] -->
+ <string name="restrict_background_blacklisted">Background data is turned off</string>
+
<!-- Summary for the Data Saver feature being on [CHAR LIMIT=NONE] -->
<string name="data_saver_on">On</string>
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.internal.os.BatterySipper;
import com.android.internal.os.BatteryStatsHelper;
import com.android.settings.DeviceAdminAdd;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
+import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.applications.PermissionsSummaryHelper.PermissionsResultCallback;
import com.android.settings.datausage.AppDataUsage;
}
private void startAppInfoFragment(Class<?> fragment, CharSequence title) {
+ startAppInfoFragment(fragment, title, this, mAppEntry);
+ }
+
+ public static void startAppInfoFragment(Class<?> fragment, CharSequence title,
+ SettingsPreferenceFragment caller, AppEntry appEntry) {
// start new fragment to display extended information
Bundle args = new Bundle();
- args.putString(ARG_PACKAGE_NAME, mAppEntry.info.packageName);
- args.putInt(ARG_PACKAGE_UID, mAppEntry.info.uid);
+ args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
+ args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
- SettingsActivity sa = (SettingsActivity) getActivity();
- sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT);
+ SettingsActivity sa = (SettingsActivity) caller.getActivity();
+ sa.startPreferencePanel(fragment.getName(), args, -1, title, caller, SUB_INFO_FRAGMENT);
}
/*
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference == mRestrictBackground) {
- setAppRestrictBackground(!(Boolean) newValue);
+ mDataSaverBackend.setIsBlacklisted(mAppItem.key, mPackageName, !(Boolean) newValue);
+ updatePrefs(); // TODO: should have been notified by NPMS instead
return true;
} else if (preference == mUnrestrictedData) {
mDataSaverBackend.setIsWhitelisted(mAppItem.key, mPackageName, (Boolean) newValue);
return (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0;
}
- private void setAppRestrictBackground(boolean restrictBackground) {
- final int uid = mAppItem.key;
- services.mPolicyManager.setUidPolicy(
- uid, restrictBackground ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
- updatePrefs(); // TODO: should have been notified by NPMS instead
- if (restrictBackground) {
- MetricsLogger.action(getContext(),
- MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, mPackageName);
- }
- }
-
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
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));
+ app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(app.info.uid),
+ mDataSaverBackend.isBlacklisted(app.info.uid));
}
}
@Override
protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
- app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(uid));
+ app.extraInfo = new DataUsageState(mDataSaverBackend.isWhitelisted(uid),
+ mDataSaverBackend.isBlacklisted(uid));
}
public static class DataUsageState {
public boolean isDataSaverWhitelisted;
+ public boolean isDataSaverBlacklisted;
- public DataUsageState(boolean isDataSaverWhitelisted) {
+ public DataUsageState(boolean isDataSaverWhitelisted, boolean isDataSaverBlacklisted) {
this.isDataSaverWhitelisted = isDataSaverWhitelisted;
+ this.isDataSaverBlacklisted = isDataSaverBlacklisted;
}
}
}
import java.util.ArrayList;
+import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
+
public class DataSaverBackend {
private static final String TAG = "DataSaverBackend";
private final INetworkPolicyManager mIPolicyManager;
private final ArrayList<Listener> mListeners = new ArrayList<>();
private SparseBooleanArray mWhitelist;
+ private SparseBooleanArray mBlacklist;
// TODO: Staticize into only one.
public DataSaverBackend(Context context) {
}
}
+ public void refreshBlacklist() {
+ loadBlacklist();
+ }
+
+ public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) {
+ mPolicyManager.setUidPolicy(
+ uid, blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE);
+ if (blacklisted) {
+ MetricsLogger.action(mContext, MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, packageName);
+ }
+ }
+
+ public boolean isBlacklisted(int uid) {
+ if (mBlacklist == null) {
+ loadBlacklist();
+ }
+ return mBlacklist.get(uid);
+ }
+
+ private void loadBlacklist() {
+ mBlacklist = new SparseBooleanArray();
+ try {
+ for (int uid : mIPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
+ mBlacklist.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 {
+ public void onUidRulesChanged(int uid, int uidRules) throws RemoteException {
+ // TODO: update UI accordingly
}
@Override
public void onResume() {
super.onResume();
mDataSaverBackend.refreshWhitelist();
+ mDataSaverBackend.refreshBlacklist();
mDataSaverBackend.addListener(this);
mSession.resume();
mDataUsageBridge.resume();
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
+
import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.settings.AppHeader;
import com.android.settings.R;
+import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppStateBaseBridge;
+import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 42;
private static final String EXTRA_SHOW_SYSTEM = "show_system";
+
private ApplicationsState mApplicationsState;
private AppStateDataUsageBridge mDataUsageBridge;
private ApplicationsState.Session mSession;
}
@Override
- public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
+ public void onRebuildComplete(ArrayList<AppEntry> apps) {
cacheRemoveAllPrefs(getPreferenceScreen());
final int N = apps.size();
for (int i = 0; i < N; i++) {
- ApplicationsState.AppEntry entry = apps.get(i);
+ AppEntry entry = apps.get(i);
String key = entry.info.packageName + "|" + entry.info.uid;
AccessPreference preference = (AccessPreference) getCachedPreference(key);
if (preference == null) {
boolean whitelisted = newValue == Boolean.TRUE;
mDataSaverBackend.setIsWhitelisted(accessPreference.mEntry.info.uid,
accessPreference.mEntry.info.packageName, whitelisted);
- ((AppStateDataUsageBridge.DataUsageState) accessPreference.mEntry.extraInfo)
- .isDataSaverWhitelisted = whitelisted;
+ accessPreference.mState.isDataSaverWhitelisted = whitelisted;
return true;
}
return false;
}
private class AccessPreference extends SwitchPreference {
- private final ApplicationsState.AppEntry mEntry;
+ private final AppEntry mEntry;
+ private final DataUsageState mState;
- public AccessPreference(Context context, ApplicationsState.AppEntry entry) {
+ public AccessPreference(final Context context, AppEntry entry) {
super(context);
mEntry = entry;
+ mState = (DataUsageState) mEntry.extraInfo;
mEntry.ensureLabel(getContext());
- setTitle(entry.label);
- final DataUsageState state = (DataUsageState) entry.extraInfo;
- setChecked(state != null && state.isDataSaverWhitelisted);
+ setState();
if (mEntry.icon != null) {
setIcon(mEntry.icon);
}
+ setOnPreferenceClickListener( new OnPreferenceClickListener() {
+
+ @Override
+ public boolean onPreferenceClick(Preference pref) {
+ if (mState.isDataSaverBlacklisted) {
+ InstalledAppDetails.startAppInfoFragment(AppDataUsage.class,
+ context.getString(R.string.app_data_usage),
+ UnrestrictedDataAccess.this,
+ mEntry);
+ return false;
+ }
+ return true;
+ }});
}
- public void reuse() {
+ // Sets UI state based on whitelist/blacklist status.
+ private void setState() {
setTitle(mEntry.label);
- final DataUsageState state = (DataUsageState) mEntry.extraInfo;
- setChecked(state != null && state.isDataSaverWhitelisted);
+ // TODO: state is cached, so if blacklist/whitelist changes, it's not updated.
+ // For example, if the initial state is blacklisted, the user taps the preference,
+ // removes the blacklist, and then taps back, the state is not refreshed.
+ // The proper fix for this problem is to implement onUidRulesChanged() on
+ // DataSaverBackend and update the UI accordingly.
+ if (mState != null) {
+ setChecked(mState.isDataSaverWhitelisted);
+ if (mState.isDataSaverBlacklisted) {
+ setSummary(R.string.restrict_background_blacklisted);
+ }
+ // TODO: might need to reset summary once it listens to onUidRulesChanged()
+ }
+ }
+
+ public void reuse() {
+ setState();
+ notifyChanged();
}
@Override
}
});
}
+ holder.findViewById(android.R.id.widget_frame)
+ .setVisibility(mState.isDataSaverBlacklisted ? View.INVISIBLE : View.VISIBLE);
super.onBindViewHolder(holder);
}
}
+
}