Handle blacklisted apps on Data Saver whitelist.
When user blacklists an app for background data access, the "Unrestricted data access" list should not display the whitelist toggle option, but rather explain background access is turned off and offer the option to open the app's data usage screen to turn it back on. It still does not handle changed received by DataSaverBackend, so the UI will be stale when the user removes a blacklist and navigates back to the list. BUG: 27481520 Change-Id: I9d0fa9f0180a69ce9bd1417921bf89ec3ba31f01
This commit is contained in:
@@ -7243,6 +7243,9 @@
|
|||||||
<!-- Button that leads to list of apps with unrestricted data access [CHAR LIMIT=60] -->
|
<!-- Button that leads to list of apps with unrestricted data access [CHAR LIMIT=60] -->
|
||||||
<string name="unrestricted_data_saver">Unrestricted data access</string>
|
<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] -->
|
<!-- Summary for the Data Saver feature being on [CHAR LIMIT=NONE] -->
|
||||||
<string name="data_saver_on">On</string>
|
<string name="data_saver_on">On</string>
|
||||||
|
|
||||||
|
@@ -73,6 +73,7 @@ import android.webkit.IWebViewUpdateService;
|
|||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
||||||
import com.android.internal.os.BatterySipper;
|
import com.android.internal.os.BatterySipper;
|
||||||
import com.android.internal.os.BatteryStatsHelper;
|
import com.android.internal.os.BatteryStatsHelper;
|
||||||
@@ -81,6 +82,7 @@ import com.android.settings.AppHeader;
|
|||||||
import com.android.settings.DeviceAdminAdd;
|
import com.android.settings.DeviceAdminAdd;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsActivity;
|
import com.android.settings.SettingsActivity;
|
||||||
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settings.applications.PermissionsSummaryHelper.PermissionsResultCallback;
|
import com.android.settings.applications.PermissionsSummaryHelper.PermissionsResultCallback;
|
||||||
import com.android.settings.datausage.AppDataUsage;
|
import com.android.settings.datausage.AppDataUsage;
|
||||||
@@ -741,14 +743,19 @@ public class InstalledAppDetails extends AppInfoBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void startAppInfoFragment(Class<?> fragment, CharSequence title) {
|
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
|
// start new fragment to display extended information
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
args.putString(ARG_PACKAGE_NAME, mAppEntry.info.packageName);
|
args.putString(ARG_PACKAGE_NAME, appEntry.info.packageName);
|
||||||
args.putInt(ARG_PACKAGE_UID, mAppEntry.info.uid);
|
args.putInt(ARG_PACKAGE_UID, appEntry.info.uid);
|
||||||
args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
|
args.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
|
||||||
|
|
||||||
SettingsActivity sa = (SettingsActivity) getActivity();
|
SettingsActivity sa = (SettingsActivity) caller.getActivity();
|
||||||
sa.startPreferencePanel(fragment.getName(), args, -1, title, this, SUB_INFO_FRAGMENT);
|
sa.startPreferencePanel(fragment.getName(), args, -1, title, caller, SUB_INFO_FRAGMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -216,7 +216,8 @@ public class AppDataUsage extends DataUsageBase implements Preference.OnPreferen
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||||
if (preference == mRestrictBackground) {
|
if (preference == mRestrictBackground) {
|
||||||
setAppRestrictBackground(!(Boolean) newValue);
|
mDataSaverBackend.setIsBlacklisted(mAppItem.key, mPackageName, !(Boolean) newValue);
|
||||||
|
updatePrefs(); // TODO: should have been notified by NPMS instead
|
||||||
return true;
|
return true;
|
||||||
} else if (preference == mUnrestrictedData) {
|
} else if (preference == mUnrestrictedData) {
|
||||||
mDataSaverBackend.setIsWhitelisted(mAppItem.key, mPackageName, (Boolean) newValue);
|
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;
|
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
|
@Override
|
||||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
|
@@ -37,20 +37,24 @@ public class AppStateDataUsageBridge extends AppStateBaseBridge {
|
|||||||
final int N = apps.size();
|
final int N = apps.size();
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < N; i++) {
|
||||||
AppEntry app = apps.get(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
|
@Override
|
||||||
protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
|
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 static class DataUsageState {
|
||||||
public boolean isDataSaverWhitelisted;
|
public boolean isDataSaverWhitelisted;
|
||||||
|
public boolean isDataSaverBlacklisted;
|
||||||
|
|
||||||
public DataUsageState(boolean isDataSaverWhitelisted) {
|
public DataUsageState(boolean isDataSaverWhitelisted, boolean isDataSaverBlacklisted) {
|
||||||
this.isDataSaverWhitelisted = isDataSaverWhitelisted;
|
this.isDataSaverWhitelisted = isDataSaverWhitelisted;
|
||||||
|
this.isDataSaverBlacklisted = isDataSaverBlacklisted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,9 @@ import com.android.internal.logging.MetricsProto.MetricsEvent;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import static android.net.NetworkPolicyManager.POLICY_NONE;
|
||||||
|
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
|
||||||
|
|
||||||
public class DataSaverBackend {
|
public class DataSaverBackend {
|
||||||
|
|
||||||
private static final String TAG = "DataSaverBackend";
|
private static final String TAG = "DataSaverBackend";
|
||||||
@@ -40,6 +43,7 @@ public class DataSaverBackend {
|
|||||||
private final INetworkPolicyManager mIPolicyManager;
|
private final INetworkPolicyManager mIPolicyManager;
|
||||||
private final ArrayList<Listener> mListeners = new ArrayList<>();
|
private final ArrayList<Listener> mListeners = new ArrayList<>();
|
||||||
private SparseBooleanArray mWhitelist;
|
private SparseBooleanArray mWhitelist;
|
||||||
|
private SparseBooleanArray mBlacklist;
|
||||||
|
|
||||||
// TODO: Staticize into only one.
|
// TODO: Staticize into only one.
|
||||||
public DataSaverBackend(Context context) {
|
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) {
|
private void handleRestrictBackgroundChanged(boolean isDataSaving) {
|
||||||
for (int i = 0; i < mListeners.size(); i++) {
|
for (int i = 0; i < mListeners.size(); i++) {
|
||||||
mListeners.get(i).onDataSaverChanged(isDataSaving);
|
mListeners.get(i).onDataSaverChanged(isDataSaving);
|
||||||
@@ -129,7 +162,8 @@ public class DataSaverBackend {
|
|||||||
|
|
||||||
private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
|
private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
|
||||||
@Override
|
@Override
|
||||||
public void onUidRulesChanged(int i, int i1) throws RemoteException {
|
public void onUidRulesChanged(int uid, int uidRules) throws RemoteException {
|
||||||
|
// TODO: update UI accordingly
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -70,6 +70,7 @@ public class DataSaverSummary extends SettingsPreferenceFragment
|
|||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
mDataSaverBackend.refreshWhitelist();
|
mDataSaverBackend.refreshWhitelist();
|
||||||
|
mDataSaverBackend.refreshBlacklist();
|
||||||
mDataSaverBackend.addListener(this);
|
mDataSaverBackend.addListener(this);
|
||||||
mSession.resume();
|
mSession.resume();
|
||||||
mDataUsageBridge.resume();
|
mDataUsageBridge.resume();
|
||||||
|
@@ -24,10 +24,15 @@ import android.view.Menu;
|
|||||||
import android.view.MenuInflater;
|
import android.view.MenuInflater;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
||||||
|
import com.android.settings.AppHeader;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.SettingsActivity;
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
|
import com.android.settings.applications.AppInfoBase;
|
||||||
import com.android.settings.applications.AppStateBaseBridge;
|
import com.android.settings.applications.AppStateBaseBridge;
|
||||||
|
import com.android.settings.applications.InstalledAppDetails;
|
||||||
import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState;
|
import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState;
|
||||||
import com.android.settingslib.applications.ApplicationsState;
|
import com.android.settingslib.applications.ApplicationsState;
|
||||||
import com.android.settingslib.applications.ApplicationsState.AppEntry;
|
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 int MENU_SHOW_SYSTEM = Menu.FIRST + 42;
|
||||||
private static final String EXTRA_SHOW_SYSTEM = "show_system";
|
private static final String EXTRA_SHOW_SYSTEM = "show_system";
|
||||||
|
|
||||||
private ApplicationsState mApplicationsState;
|
private ApplicationsState mApplicationsState;
|
||||||
private AppStateDataUsageBridge mDataUsageBridge;
|
private AppStateDataUsageBridge mDataUsageBridge;
|
||||||
private ApplicationsState.Session mSession;
|
private ApplicationsState.Session mSession;
|
||||||
@@ -144,11 +150,11 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onRebuildComplete(ArrayList<ApplicationsState.AppEntry> apps) {
|
public void onRebuildComplete(ArrayList<AppEntry> apps) {
|
||||||
cacheRemoveAllPrefs(getPreferenceScreen());
|
cacheRemoveAllPrefs(getPreferenceScreen());
|
||||||
final int N = apps.size();
|
final int N = apps.size();
|
||||||
for (int i = 0; i < N; i++) {
|
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;
|
String key = entry.info.packageName + "|" + entry.info.uid;
|
||||||
AccessPreference preference = (AccessPreference) getCachedPreference(key);
|
AccessPreference preference = (AccessPreference) getCachedPreference(key);
|
||||||
if (preference == null) {
|
if (preference == null) {
|
||||||
@@ -202,32 +208,60 @@ public class UnrestrictedDataAccess extends SettingsPreferenceFragment
|
|||||||
boolean whitelisted = newValue == Boolean.TRUE;
|
boolean whitelisted = newValue == Boolean.TRUE;
|
||||||
mDataSaverBackend.setIsWhitelisted(accessPreference.mEntry.info.uid,
|
mDataSaverBackend.setIsWhitelisted(accessPreference.mEntry.info.uid,
|
||||||
accessPreference.mEntry.info.packageName, whitelisted);
|
accessPreference.mEntry.info.packageName, whitelisted);
|
||||||
((AppStateDataUsageBridge.DataUsageState) accessPreference.mEntry.extraInfo)
|
accessPreference.mState.isDataSaverWhitelisted = whitelisted;
|
||||||
.isDataSaverWhitelisted = whitelisted;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AccessPreference extends SwitchPreference {
|
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);
|
super(context);
|
||||||
mEntry = entry;
|
mEntry = entry;
|
||||||
|
mState = (DataUsageState) mEntry.extraInfo;
|
||||||
mEntry.ensureLabel(getContext());
|
mEntry.ensureLabel(getContext());
|
||||||
setTitle(entry.label);
|
setState();
|
||||||
final DataUsageState state = (DataUsageState) entry.extraInfo;
|
|
||||||
setChecked(state != null && state.isDataSaverWhitelisted);
|
|
||||||
if (mEntry.icon != null) {
|
if (mEntry.icon != null) {
|
||||||
setIcon(mEntry.icon);
|
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() {
|
public void reuse() {
|
||||||
setTitle(mEntry.label);
|
setState();
|
||||||
final DataUsageState state = (DataUsageState) mEntry.extraInfo;
|
notifyChanged();
|
||||||
setChecked(state != null && state.isDataSaverWhitelisted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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);
|
super.onBindViewHolder(holder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user