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