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.telephony.SubscriptionPlan; 27 import android.util.SparseIntArray; 28 29 import com.android.settings.overlay.FeatureFactory; 30 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 31 import com.android.settingslib.utils.ThreadUtils; 32 33 import java.util.ArrayList; 34 35 public class DataSaverBackend { 36 37 private static final String TAG = "DataSaverBackend"; 38 39 private final Context mContext; 40 private final MetricsFeatureProvider mMetricsFeatureProvider; 41 42 private final NetworkPolicyManager mPolicyManager; 43 private final ArrayList<Listener> mListeners = new ArrayList<>(); 44 private SparseIntArray mUidPolicies = new SparseIntArray(); 45 private boolean mWhitelistInitialized; 46 private boolean mBlacklistInitialized; 47 48 // TODO: Staticize into only one. DataSaverBackend(Context context)49 public DataSaverBackend(Context context) { 50 mContext = context; 51 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); 52 mPolicyManager = NetworkPolicyManager.from(context); 53 } 54 addListener(Listener listener)55 public void addListener(Listener listener) { 56 mListeners.add(listener); 57 if (mListeners.size() == 1) { 58 mPolicyManager.registerListener(mPolicyListener); 59 } 60 listener.onDataSaverChanged(isDataSaverEnabled()); 61 } 62 remListener(Listener listener)63 public void remListener(Listener listener) { 64 mListeners.remove(listener); 65 if (mListeners.size() == 0) { 66 mPolicyManager.unregisterListener(mPolicyListener); 67 } 68 } 69 isDataSaverEnabled()70 public boolean isDataSaverEnabled() { 71 return mPolicyManager.getRestrictBackground(); 72 } 73 setDataSaverEnabled(boolean enabled)74 public void setDataSaverEnabled(boolean enabled) { 75 mPolicyManager.setRestrictBackground(enabled); 76 mMetricsFeatureProvider.action( 77 mContext, SettingsEnums.ACTION_DATA_SAVER_MODE, enabled ? 1 : 0); 78 } 79 refreshWhitelist()80 public void refreshWhitelist() { 81 loadWhitelist(); 82 } 83 setIsWhitelisted(int uid, String packageName, boolean whitelisted)84 public void setIsWhitelisted(int uid, String packageName, boolean whitelisted) { 85 final int policy = whitelisted ? POLICY_ALLOW_METERED_BACKGROUND : POLICY_NONE; 86 mPolicyManager.setUidPolicy(uid, policy); 87 mUidPolicies.put(uid, policy); 88 if (whitelisted) { 89 mMetricsFeatureProvider.action( 90 mContext, SettingsEnums.ACTION_DATA_SAVER_WHITELIST, packageName); 91 } 92 } 93 isWhitelisted(int uid)94 public boolean isWhitelisted(int uid) { 95 loadWhitelist(); 96 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_ALLOW_METERED_BACKGROUND; 97 } 98 loadWhitelist()99 private void loadWhitelist() { 100 if (mWhitelistInitialized) { 101 return; 102 } 103 104 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND)) { 105 mUidPolicies.put(uid, POLICY_ALLOW_METERED_BACKGROUND); 106 } 107 mWhitelistInitialized = true; 108 } 109 refreshBlacklist()110 public void refreshBlacklist() { 111 loadBlacklist(); 112 } 113 setIsBlacklisted(int uid, String packageName, boolean blacklisted)114 public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) { 115 final int policy = blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE; 116 mPolicyManager.setUidPolicy(uid, policy); 117 mUidPolicies.put(uid, policy); 118 if (blacklisted) { 119 mMetricsFeatureProvider.action( 120 mContext, SettingsEnums.ACTION_DATA_SAVER_BLACKLIST, packageName); 121 } 122 } 123 isBlacklisted(int uid)124 public boolean isBlacklisted(int uid) { 125 loadBlacklist(); 126 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND; 127 } 128 loadBlacklist()129 private void loadBlacklist() { 130 if (mBlacklistInitialized) { 131 return; 132 } 133 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) { 134 mUidPolicies.put(uid, POLICY_REJECT_METERED_BACKGROUND); 135 } 136 mBlacklistInitialized = true; 137 } 138 handleRestrictBackgroundChanged(boolean isDataSaving)139 private void handleRestrictBackgroundChanged(boolean isDataSaving) { 140 for (int i = 0; i < mListeners.size(); i++) { 141 mListeners.get(i).onDataSaverChanged(isDataSaving); 142 } 143 } 144 handleWhitelistChanged(int uid, boolean isWhitelisted)145 private void handleWhitelistChanged(int uid, boolean isWhitelisted) { 146 for (int i = 0; i < mListeners.size(); i++) { 147 mListeners.get(i).onWhitelistStatusChanged(uid, isWhitelisted); 148 } 149 } 150 handleBlacklistChanged(int uid, boolean isBlacklisted)151 private void handleBlacklistChanged(int uid, boolean isBlacklisted) { 152 for (int i = 0; i < mListeners.size(); i++) { 153 mListeners.get(i).onBlacklistStatusChanged(uid, isBlacklisted); 154 } 155 } 156 handleUidPoliciesChanged(int uid, int newPolicy)157 private void handleUidPoliciesChanged(int uid, int newPolicy) { 158 loadWhitelist(); 159 loadBlacklist(); 160 161 final int oldPolicy = mUidPolicies.get(uid, POLICY_NONE); 162 if (newPolicy == POLICY_NONE) { 163 mUidPolicies.delete(uid); 164 } else { 165 mUidPolicies.put(uid, newPolicy); 166 } 167 168 final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; 169 final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; 170 final boolean isWhitelisted = newPolicy == POLICY_ALLOW_METERED_BACKGROUND; 171 final boolean isBlacklisted = newPolicy == POLICY_REJECT_METERED_BACKGROUND; 172 173 if (wasWhitelisted != isWhitelisted) { 174 handleWhitelistChanged(uid, isWhitelisted); 175 } 176 177 if (wasBlacklisted != isBlacklisted) { 178 handleBlacklistChanged(uid, isBlacklisted); 179 } 180 181 } 182 183 private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { 184 @Override 185 public void onUidRulesChanged(int uid, int uidRules) throws RemoteException { 186 } 187 188 @Override 189 public void onUidPoliciesChanged(final int uid, final int uidPolicies) { 190 ThreadUtils.postOnMainThread(() -> handleUidPoliciesChanged(uid, uidPolicies)); 191 } 192 193 @Override 194 public void onMeteredIfacesChanged(String[] strings) throws RemoteException { 195 } 196 197 @Override 198 public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException { 199 ThreadUtils.postOnMainThread(() -> handleRestrictBackgroundChanged(isDataSaving)); 200 } 201 202 @Override 203 public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) { 204 } 205 206 @Override 207 public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { 208 } 209 }; 210 211 public interface Listener { onDataSaverChanged(boolean isDataSaving)212 void onDataSaverChanged(boolean isDataSaving); 213 onWhitelistStatusChanged(int uid, boolean isWhitelisted)214 void onWhitelistStatusChanged(int uid, boolean isWhitelisted); 215 onBlacklistStatusChanged(int uid, boolean isBlacklisted)216 void onBlacklistStatusChanged(int uid, boolean isBlacklisted); 217 } 218 } 219