1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.settings.datausage; 16 17 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; 18 import static android.net.NetworkPolicyManager.POLICY_NONE; 19 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; 20 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.net.INetworkPolicyListener; 24 import android.net.NetworkPolicyManager; 25 import android.os.RemoteException; 26 import android.util.SparseIntArray; 27 28 import com.android.settings.overlay.FeatureFactory; 29 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 30 import com.android.settingslib.utils.ThreadUtils; 31 32 import java.util.ArrayList; 33 34 public class DataSaverBackend { 35 36 private static final String TAG = "DataSaverBackend"; 37 38 private final Context mContext; 39 private final MetricsFeatureProvider mMetricsFeatureProvider; 40 41 private final NetworkPolicyManager mPolicyManager; 42 private final ArrayList<Listener> mListeners = new ArrayList<>(); 43 private SparseIntArray mUidPolicies = new SparseIntArray(); 44 private boolean mWhitelistInitialized; 45 private boolean mBlacklistInitialized; 46 47 // TODO: Staticize into only one. DataSaverBackend(Context context)48 public DataSaverBackend(Context context) { 49 mContext = context; 50 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); 51 mPolicyManager = NetworkPolicyManager.from(context); 52 } 53 addListener(Listener listener)54 public void addListener(Listener listener) { 55 mListeners.add(listener); 56 if (mListeners.size() == 1) { 57 mPolicyManager.registerListener(mPolicyListener); 58 } 59 listener.onDataSaverChanged(isDataSaverEnabled()); 60 } 61 remListener(Listener listener)62 public void remListener(Listener listener) { 63 mListeners.remove(listener); 64 if (mListeners.size() == 0) { 65 mPolicyManager.unregisterListener(mPolicyListener); 66 } 67 } 68 isDataSaverEnabled()69 public boolean isDataSaverEnabled() { 70 return mPolicyManager.getRestrictBackground(); 71 } 72 setDataSaverEnabled(boolean enabled)73 public void setDataSaverEnabled(boolean enabled) { 74 mPolicyManager.setRestrictBackground(enabled); 75 mMetricsFeatureProvider.action( 76 mContext, SettingsEnums.ACTION_DATA_SAVER_MODE, enabled ? 1 : 0); 77 } 78 refreshWhitelist()79 public void refreshWhitelist() { 80 loadWhitelist(); 81 } 82 setIsWhitelisted(int uid, String packageName, boolean whitelisted)83 public void setIsWhitelisted(int uid, String packageName, boolean whitelisted) { 84 final int policy = whitelisted ? POLICY_ALLOW_METERED_BACKGROUND : POLICY_NONE; 85 mPolicyManager.setUidPolicy(uid, policy); 86 mUidPolicies.put(uid, policy); 87 if (whitelisted) { 88 mMetricsFeatureProvider.action( 89 mContext, SettingsEnums.ACTION_DATA_SAVER_WHITELIST, packageName); 90 } 91 } 92 isWhitelisted(int uid)93 public boolean isWhitelisted(int uid) { 94 loadWhitelist(); 95 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_ALLOW_METERED_BACKGROUND; 96 } 97 loadWhitelist()98 private void loadWhitelist() { 99 if (mWhitelistInitialized) { 100 return; 101 } 102 103 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND)) { 104 mUidPolicies.put(uid, POLICY_ALLOW_METERED_BACKGROUND); 105 } 106 mWhitelistInitialized = true; 107 } 108 refreshBlacklist()109 public void refreshBlacklist() { 110 loadBlacklist(); 111 } 112 setIsBlacklisted(int uid, String packageName, boolean blacklisted)113 public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) { 114 final int policy = blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE; 115 mPolicyManager.setUidPolicy(uid, policy); 116 mUidPolicies.put(uid, policy); 117 if (blacklisted) { 118 mMetricsFeatureProvider.action( 119 mContext, SettingsEnums.ACTION_DATA_SAVER_BLACKLIST, packageName); 120 } 121 } 122 isBlacklisted(int uid)123 public boolean isBlacklisted(int uid) { 124 loadBlacklist(); 125 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND; 126 } 127 loadBlacklist()128 private void loadBlacklist() { 129 if (mBlacklistInitialized) { 130 return; 131 } 132 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) { 133 mUidPolicies.put(uid, POLICY_REJECT_METERED_BACKGROUND); 134 } 135 mBlacklistInitialized = true; 136 } 137 handleRestrictBackgroundChanged(boolean isDataSaving)138 private void handleRestrictBackgroundChanged(boolean isDataSaving) { 139 for (int i = 0; i < mListeners.size(); i++) { 140 mListeners.get(i).onDataSaverChanged(isDataSaving); 141 } 142 } 143 handleWhitelistChanged(int uid, boolean isWhitelisted)144 private void handleWhitelistChanged(int uid, boolean isWhitelisted) { 145 for (int i = 0; i < mListeners.size(); i++) { 146 mListeners.get(i).onWhitelistStatusChanged(uid, isWhitelisted); 147 } 148 } 149 handleBlacklistChanged(int uid, boolean isBlacklisted)150 private void handleBlacklistChanged(int uid, boolean isBlacklisted) { 151 for (int i = 0; i < mListeners.size(); i++) { 152 mListeners.get(i).onBlacklistStatusChanged(uid, isBlacklisted); 153 } 154 } 155 handleUidPoliciesChanged(int uid, int newPolicy)156 private void handleUidPoliciesChanged(int uid, int newPolicy) { 157 loadWhitelist(); 158 loadBlacklist(); 159 160 final int oldPolicy = mUidPolicies.get(uid, POLICY_NONE); 161 if (newPolicy == POLICY_NONE) { 162 mUidPolicies.delete(uid); 163 } else { 164 mUidPolicies.put(uid, newPolicy); 165 } 166 167 final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; 168 final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; 169 final boolean isWhitelisted = newPolicy == POLICY_ALLOW_METERED_BACKGROUND; 170 final boolean isBlacklisted = newPolicy == POLICY_REJECT_METERED_BACKGROUND; 171 172 if (wasWhitelisted != isWhitelisted) { 173 handleWhitelistChanged(uid, isWhitelisted); 174 } 175 176 if (wasBlacklisted != isBlacklisted) { 177 handleBlacklistChanged(uid, isBlacklisted); 178 } 179 180 } 181 182 private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { 183 @Override 184 public void onUidRulesChanged(int uid, int uidRules) throws RemoteException { 185 } 186 187 @Override 188 public void onUidPoliciesChanged(final int uid, final int uidPolicies) { 189 ThreadUtils.postOnMainThread(() -> handleUidPoliciesChanged(uid, uidPolicies)); 190 } 191 192 @Override 193 public void onMeteredIfacesChanged(String[] strings) throws RemoteException { 194 } 195 196 @Override 197 public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException { 198 ThreadUtils.postOnMainThread(() -> handleRestrictBackgroundChanged(isDataSaving)); 199 } 200 201 @Override 202 public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) { 203 } 204 }; 205 206 public interface Listener { onDataSaverChanged(boolean isDataSaving)207 void onDataSaverChanged(boolean isDataSaving); 208 onWhitelistStatusChanged(int uid, boolean isWhitelisted)209 void onWhitelistStatusChanged(int uid, boolean isWhitelisted); 210 onBlacklistStatusChanged(int uid, boolean isBlacklisted)211 void onBlacklistStatusChanged(int uid, boolean isBlacklisted); 212 } 213 } 214