diff --git a/res/values/strings.xml b/res/values/strings.xml index 16ab7082e7e..3eb6d3df240 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7243,6 +7243,9 @@ Unrestricted data access + + Background data is turned off + On diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java index 7813745085b..367969920a7 100755 --- a/src/com/android/settings/applications/InstalledAppDetails.java +++ b/src/com/android/settings/applications/InstalledAppDetails.java @@ -73,6 +73,7 @@ import android.webkit.IWebViewUpdateService; 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; @@ -81,6 +82,7 @@ import com.android.settings.AppHeader; 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; @@ -741,14 +743,19 @@ public class InstalledAppDetails extends AppInfoBase } 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); } /* diff --git a/src/com/android/settings/datausage/AppDataUsage.java b/src/com/android/settings/datausage/AppDataUsage.java index 3da3bacd26a..037614e1127 100644 --- a/src/com/android/settings/datausage/AppDataUsage.java +++ b/src/com/android/settings/datausage/AppDataUsage.java @@ -216,7 +216,8 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen @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); @@ -287,17 +288,6 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen 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); diff --git a/src/com/android/settings/datausage/AppStateDataUsageBridge.java b/src/com/android/settings/datausage/AppStateDataUsageBridge.java index 1aff49604f2..0b535d04b3a 100644 --- a/src/com/android/settings/datausage/AppStateDataUsageBridge.java +++ b/src/com/android/settings/datausage/AppStateDataUsageBridge.java @@ -37,20 +37,24 @@ public class AppStateDataUsageBridge extends AppStateBaseBridge { 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; } } } diff --git a/src/com/android/settings/datausage/DataSaverBackend.java b/src/com/android/settings/datausage/DataSaverBackend.java index d72fe3d5b72..55521a8775f 100644 --- a/src/com/android/settings/datausage/DataSaverBackend.java +++ b/src/com/android/settings/datausage/DataSaverBackend.java @@ -29,6 +29,9 @@ import com.android.internal.logging.MetricsProto.MetricsEvent; 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"; @@ -40,6 +43,7 @@ public class DataSaverBackend { private final INetworkPolicyManager mIPolicyManager; private final ArrayList mListeners = new ArrayList<>(); private SparseBooleanArray mWhitelist; + private SparseBooleanArray mBlacklist; // TODO: Staticize into only one. public DataSaverBackend(Context context) { @@ -121,6 +125,35 @@ public class DataSaverBackend { } } + 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); @@ -129,7 +162,8 @@ public class DataSaverBackend { 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 diff --git a/src/com/android/settings/datausage/DataSaverSummary.java b/src/com/android/settings/datausage/DataSaverSummary.java index e8c8cdd0c33..591f2c5b529 100644 --- a/src/com/android/settings/datausage/DataSaverSummary.java +++ b/src/com/android/settings/datausage/DataSaverSummary.java @@ -70,6 +70,7 @@ public class DataSaverSummary extends SettingsPreferenceFragment public void onResume() { super.onResume(); mDataSaverBackend.refreshWhitelist(); + mDataSaverBackend.refreshBlacklist(); mDataSaverBackend.addListener(this); mSession.resume(); mDataUsageBridge.resume(); diff --git a/src/com/android/settings/datausage/UnrestrictedDataAccess.java b/src/com/android/settings/datausage/UnrestrictedDataAccess.java index 36ec050d0ec..c8df0ba4457 100644 --- a/src/com/android/settings/datausage/UnrestrictedDataAccess.java +++ b/src/com/android/settings/datausage/UnrestrictedDataAccess.java @@ -24,10 +24,15 @@ import android.view.Menu; 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; @@ -40,6 +45,7 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment 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; @@ -144,11 +150,11 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment } @Override - public void onRebuildComplete(ArrayList apps) { + public void onRebuildComplete(ArrayList 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) { @@ -202,32 +208,60 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment 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; + }}); + } + + // Sets UI state based on whitelist/blacklist status. + private void setState() { + setTitle(mEntry.label); + // 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() { - setTitle(mEntry.label); - final DataUsageState state = (DataUsageState) mEntry.extraInfo; - setChecked(state != null && state.isDataSaverWhitelisted); + setState(); + notifyChanged(); } @Override @@ -244,7 +278,10 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment } }); } + holder.findViewById(android.R.id.widget_frame) + .setVisibility(mState.isDataSaverBlacklisted ? View.INVISIBLE : View.VISIBLE); super.onBindViewHolder(holder); } } + }