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 android.content.Context; 18 import android.net.INetworkPolicyListener; 19 import android.net.NetworkPolicyManager; 20 import android.os.Handler; 21 import android.os.RemoteException; 22 import android.util.SparseIntArray; 23 24 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 25 import com.android.settings.core.instrumentation.MetricsFeatureProvider; 26 import com.android.settings.overlay.FeatureFactory; 27 28 import java.util.ArrayList; 29 30 import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND; 31 import static android.net.NetworkPolicyManager.POLICY_NONE; 32 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; 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 Handler mHandler = new Handler(); 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, MetricsEvent.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, MetricsEvent.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 getWhitelistedCount()99 public int getWhitelistedCount() { 100 int count = 0; 101 loadWhitelist(); 102 for (int i = 0; i < mUidPolicies.size(); i++) { 103 if (mUidPolicies.valueAt(i) == POLICY_ALLOW_METERED_BACKGROUND) { 104 count++; 105 } 106 } 107 return count; 108 } 109 loadWhitelist()110 private void loadWhitelist() { 111 if (mWhitelistInitialized) return; 112 113 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND)) { 114 mUidPolicies.put(uid, POLICY_ALLOW_METERED_BACKGROUND); 115 } 116 mWhitelistInitialized = true; 117 } 118 refreshBlacklist()119 public void refreshBlacklist() { 120 loadBlacklist(); 121 } 122 setIsBlacklisted(int uid, String packageName, boolean blacklisted)123 public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) { 124 final int policy = blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE; 125 mPolicyManager.setUidPolicy(uid, policy); 126 mUidPolicies.put(uid, policy); 127 if (blacklisted) { 128 mMetricsFeatureProvider.action( 129 mContext, MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, packageName); 130 } 131 } 132 isBlacklisted(int uid)133 public boolean isBlacklisted(int uid) { 134 loadBlacklist(); 135 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND; 136 } 137 loadBlacklist()138 private void loadBlacklist() { 139 if (mBlacklistInitialized) return; 140 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) { 141 mUidPolicies.put(uid, POLICY_REJECT_METERED_BACKGROUND); 142 } 143 mBlacklistInitialized = true; 144 } 145 handleRestrictBackgroundChanged(boolean isDataSaving)146 private void handleRestrictBackgroundChanged(boolean isDataSaving) { 147 for (int i = 0; i < mListeners.size(); i++) { 148 mListeners.get(i).onDataSaverChanged(isDataSaving); 149 } 150 } 151 handleWhitelistChanged(int uid, boolean isWhitelisted)152 private void handleWhitelistChanged(int uid, boolean isWhitelisted) { 153 for (int i = 0; i < mListeners.size(); i++) { 154 mListeners.get(i).onWhitelistStatusChanged(uid, isWhitelisted); 155 } 156 } 157 handleBlacklistChanged(int uid, boolean isBlacklisted)158 private void handleBlacklistChanged(int uid, boolean isBlacklisted) { 159 for (int i = 0; i < mListeners.size(); i++) { 160 mListeners.get(i).onBlacklistStatusChanged(uid, isBlacklisted); 161 } 162 } 163 handleUidPoliciesChanged(int uid, int newPolicy)164 private void handleUidPoliciesChanged(int uid, int newPolicy) { 165 loadWhitelist(); 166 loadBlacklist(); 167 168 final int oldPolicy = mUidPolicies.get(uid, POLICY_NONE); 169 if (newPolicy == POLICY_NONE) { 170 mUidPolicies.delete(uid); 171 } else { 172 mUidPolicies.put(uid, newPolicy); 173 } 174 175 final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; 176 final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; 177 final boolean isWhitelisted = newPolicy == POLICY_ALLOW_METERED_BACKGROUND; 178 final boolean isBlacklisted = newPolicy == POLICY_REJECT_METERED_BACKGROUND; 179 180 if (wasWhitelisted != isWhitelisted) { 181 handleWhitelistChanged(uid, isWhitelisted); 182 } 183 184 if (wasBlacklisted != isBlacklisted) { 185 handleBlacklistChanged(uid, isBlacklisted); 186 } 187 188 } 189 190 private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { 191 @Override 192 public void onUidRulesChanged(int uid, int uidRules) throws RemoteException { 193 } 194 195 @Override 196 public void onUidPoliciesChanged(final int uid, final int uidPolicies) { 197 mHandler.post(new Runnable() { 198 @Override 199 public void run() { 200 handleUidPoliciesChanged(uid, uidPolicies); 201 } 202 }); 203 } 204 205 @Override 206 public void onMeteredIfacesChanged(String[] strings) throws RemoteException { 207 } 208 209 @Override 210 public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException { 211 mHandler.post(new Runnable() { 212 @Override 213 public void run() { 214 handleRestrictBackgroundChanged(isDataSaving); 215 } 216 }); 217 } 218 }; 219 220 public interface Listener { onDataSaverChanged(boolean isDataSaving)221 void onDataSaverChanged(boolean isDataSaving); onWhitelistStatusChanged(int uid, boolean isWhitelisted)222 void onWhitelistStatusChanged(int uid, boolean isWhitelisted); onBlacklistStatusChanged(int uid, boolean isBlacklisted)223 void onBlacklistStatusChanged(int uid, boolean isBlacklisted); 224 } 225 } 226