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.NetworkPolicyManager; 24 import android.util.SparseIntArray; 25 26 import com.android.settings.overlay.FeatureFactory; 27 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 28 import com.android.settingslib.utils.ThreadUtils; 29 30 import java.util.ArrayList; 31 32 public class DataSaverBackend { 33 34 private static final String TAG = "DataSaverBackend"; 35 36 private final Context mContext; 37 private final MetricsFeatureProvider mMetricsFeatureProvider; 38 39 private final NetworkPolicyManager mPolicyManager; 40 private final ArrayList<Listener> mListeners = new ArrayList<>(); 41 private SparseIntArray mUidPolicies = new SparseIntArray(); 42 private boolean mAllowlistInitialized; 43 private boolean mDenylistInitialized; 44 45 // TODO: Staticize into only one. DataSaverBackend(Context context)46 public DataSaverBackend(Context context) { 47 mContext = context; 48 mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); 49 mPolicyManager = NetworkPolicyManager.from(context); 50 } 51 addListener(Listener listener)52 public void addListener(Listener listener) { 53 mListeners.add(listener); 54 if (mListeners.size() == 1) { 55 mPolicyManager.registerListener(mPolicyListener); 56 } 57 listener.onDataSaverChanged(isDataSaverEnabled()); 58 } 59 remListener(Listener listener)60 public void remListener(Listener listener) { 61 mListeners.remove(listener); 62 if (mListeners.size() == 0) { 63 mPolicyManager.unregisterListener(mPolicyListener); 64 } 65 } 66 isDataSaverEnabled()67 public boolean isDataSaverEnabled() { 68 return mPolicyManager.getRestrictBackground(); 69 } 70 setDataSaverEnabled(boolean enabled)71 public void setDataSaverEnabled(boolean enabled) { 72 mPolicyManager.setRestrictBackground(enabled); 73 mMetricsFeatureProvider.action( 74 mContext, SettingsEnums.ACTION_DATA_SAVER_MODE, enabled ? 1 : 0); 75 } 76 refreshAllowlist()77 public void refreshAllowlist() { 78 loadAllowlist(); 79 } 80 setIsAllowlisted(int uid, String packageName, boolean allowlisted)81 public void setIsAllowlisted(int uid, String packageName, boolean allowlisted) { 82 final int policy = allowlisted ? POLICY_ALLOW_METERED_BACKGROUND : POLICY_NONE; 83 mPolicyManager.setUidPolicy(uid, policy); 84 mUidPolicies.put(uid, policy); 85 if (allowlisted) { 86 mMetricsFeatureProvider.action( 87 mContext, SettingsEnums.ACTION_DATA_SAVER_WHITELIST, packageName); 88 } 89 } 90 isAllowlisted(int uid)91 public boolean isAllowlisted(int uid) { 92 loadAllowlist(); 93 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_ALLOW_METERED_BACKGROUND; 94 } 95 loadAllowlist()96 private void loadAllowlist() { 97 if (mAllowlistInitialized) { 98 return; 99 } 100 101 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND)) { 102 mUidPolicies.put(uid, POLICY_ALLOW_METERED_BACKGROUND); 103 } 104 mAllowlistInitialized = true; 105 } 106 refreshDenylist()107 public void refreshDenylist() { 108 loadDenylist(); 109 } 110 setIsDenylisted(int uid, String packageName, boolean denylisted)111 public void setIsDenylisted(int uid, String packageName, boolean denylisted) { 112 final int policy = denylisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE; 113 mPolicyManager.setUidPolicy(uid, policy); 114 mUidPolicies.put(uid, policy); 115 if (denylisted) { 116 mMetricsFeatureProvider.action( 117 mContext, SettingsEnums.ACTION_DATA_SAVER_BLACKLIST, packageName); 118 } 119 } 120 isDenylisted(int uid)121 public boolean isDenylisted(int uid) { 122 loadDenylist(); 123 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND; 124 } 125 loadDenylist()126 private void loadDenylist() { 127 if (mDenylistInitialized) { 128 return; 129 } 130 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) { 131 mUidPolicies.put(uid, POLICY_REJECT_METERED_BACKGROUND); 132 } 133 mDenylistInitialized = true; 134 } 135 handleRestrictBackgroundChanged(boolean isDataSaving)136 private void handleRestrictBackgroundChanged(boolean isDataSaving) { 137 for (int i = 0; i < mListeners.size(); i++) { 138 mListeners.get(i).onDataSaverChanged(isDataSaving); 139 } 140 } 141 handleAllowlistChanged(int uid, boolean isAllowlisted)142 private void handleAllowlistChanged(int uid, boolean isAllowlisted) { 143 for (int i = 0; i < mListeners.size(); i++) { 144 mListeners.get(i).onAllowlistStatusChanged(uid, isAllowlisted); 145 } 146 } 147 handleDenylistChanged(int uid, boolean isDenylisted)148 private void handleDenylistChanged(int uid, boolean isDenylisted) { 149 for (int i = 0; i < mListeners.size(); i++) { 150 mListeners.get(i).onDenylistStatusChanged(uid, isDenylisted); 151 } 152 } 153 handleUidPoliciesChanged(int uid, int newPolicy)154 private void handleUidPoliciesChanged(int uid, int newPolicy) { 155 loadAllowlist(); 156 loadDenylist(); 157 158 final int oldPolicy = mUidPolicies.get(uid, POLICY_NONE); 159 if (newPolicy == POLICY_NONE) { 160 mUidPolicies.delete(uid); 161 } else { 162 mUidPolicies.put(uid, newPolicy); 163 } 164 165 final boolean wasAllowlisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; 166 final boolean wasDenylisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; 167 final boolean isAllowlisted = newPolicy == POLICY_ALLOW_METERED_BACKGROUND; 168 final boolean isDenylisted = newPolicy == POLICY_REJECT_METERED_BACKGROUND; 169 170 if (wasAllowlisted != isAllowlisted) { 171 handleAllowlistChanged(uid, isAllowlisted); 172 } 173 174 if (wasDenylisted != isDenylisted) { 175 handleDenylistChanged(uid, isDenylisted); 176 } 177 178 } 179 180 private final NetworkPolicyManager.Listener mPolicyListener = 181 new NetworkPolicyManager.Listener() { 182 @Override 183 public void onUidPoliciesChanged(final int uid, final int uidPolicies) { 184 ThreadUtils.postOnMainThread(() -> handleUidPoliciesChanged(uid, uidPolicies)); 185 } 186 187 @Override 188 public void onRestrictBackgroundChanged(final boolean isDataSaving) { 189 ThreadUtils.postOnMainThread(() -> handleRestrictBackgroundChanged(isDataSaving)); 190 } 191 }; 192 193 public interface Listener { onDataSaverChanged(boolean isDataSaving)194 void onDataSaverChanged(boolean isDataSaving); 195 onAllowlistStatusChanged(int uid, boolean isAllowlisted)196 void onAllowlistStatusChanged(int uid, boolean isAllowlisted); 197 onDenylistStatusChanged(int uid, boolean isDenylisted)198 void onDenylistStatusChanged(int uid, boolean isDenylisted); 199 } 200 } 201