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 org.jetbrains.annotations.NotNull; 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 mAllowlistInitialized; 45 private boolean mDenylistInitialized; 46 47 // TODO: Staticize into only one. DataSaverBackend(@otNull Context context)48 public DataSaverBackend(@NotNull Context context) { 49 // TODO(b/246537614):Use fragment context to DataSaverBackend class will caused memory leak 50 mContext = context.getApplicationContext(); 51 mMetricsFeatureProvider = FeatureFactory.getFactory(mContext).getMetricsFeatureProvider(); 52 mPolicyManager = NetworkPolicyManager.from(mContext); 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 refreshAllowlist()80 public void refreshAllowlist() { 81 loadAllowlist(); 82 } 83 setIsAllowlisted(int uid, String packageName, boolean allowlisted)84 public void setIsAllowlisted(int uid, String packageName, boolean allowlisted) { 85 final int policy = allowlisted ? POLICY_ALLOW_METERED_BACKGROUND : POLICY_NONE; 86 mPolicyManager.setUidPolicy(uid, policy); 87 mUidPolicies.put(uid, policy); 88 if (allowlisted) { 89 mMetricsFeatureProvider.action( 90 mContext, SettingsEnums.ACTION_DATA_SAVER_WHITELIST, packageName); 91 } 92 } 93 isAllowlisted(int uid)94 public boolean isAllowlisted(int uid) { 95 loadAllowlist(); 96 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_ALLOW_METERED_BACKGROUND; 97 } 98 loadAllowlist()99 private void loadAllowlist() { 100 if (mAllowlistInitialized) { 101 return; 102 } 103 104 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND)) { 105 mUidPolicies.put(uid, POLICY_ALLOW_METERED_BACKGROUND); 106 } 107 mAllowlistInitialized = true; 108 } 109 refreshDenylist()110 public void refreshDenylist() { 111 loadDenylist(); 112 } 113 setIsDenylisted(int uid, String packageName, boolean denylisted)114 public void setIsDenylisted(int uid, String packageName, boolean denylisted) { 115 final int policy = denylisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE; 116 mPolicyManager.setUidPolicy(uid, policy); 117 mUidPolicies.put(uid, policy); 118 if (denylisted) { 119 mMetricsFeatureProvider.action( 120 mContext, SettingsEnums.ACTION_DATA_SAVER_BLACKLIST, packageName); 121 } 122 } 123 isDenylisted(int uid)124 public boolean isDenylisted(int uid) { 125 loadDenylist(); 126 return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND; 127 } 128 loadDenylist()129 private void loadDenylist() { 130 if (mDenylistInitialized) { 131 return; 132 } 133 for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) { 134 mUidPolicies.put(uid, POLICY_REJECT_METERED_BACKGROUND); 135 } 136 mDenylistInitialized = 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 handleAllowlistChanged(int uid, boolean isAllowlisted)145 private void handleAllowlistChanged(int uid, boolean isAllowlisted) { 146 for (int i = 0; i < mListeners.size(); i++) { 147 mListeners.get(i).onAllowlistStatusChanged(uid, isAllowlisted); 148 } 149 } 150 handleDenylistChanged(int uid, boolean isDenylisted)151 private void handleDenylistChanged(int uid, boolean isDenylisted) { 152 for (int i = 0; i < mListeners.size(); i++) { 153 mListeners.get(i).onDenylistStatusChanged(uid, isDenylisted); 154 } 155 } 156 handleUidPoliciesChanged(int uid, int newPolicy)157 private void handleUidPoliciesChanged(int uid, int newPolicy) { 158 loadAllowlist(); 159 loadDenylist(); 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 wasAllowlisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND; 169 final boolean wasDenylisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND; 170 final boolean isAllowlisted = newPolicy == POLICY_ALLOW_METERED_BACKGROUND; 171 final boolean isDenylisted = newPolicy == POLICY_REJECT_METERED_BACKGROUND; 172 173 if (wasAllowlisted != isAllowlisted) { 174 handleAllowlistChanged(uid, isAllowlisted); 175 } 176 177 if (wasDenylisted != isDenylisted) { 178 handleDenylistChanged(uid, isDenylisted); 179 } 180 181 } 182 183 private final NetworkPolicyManager.Listener mPolicyListener = 184 new NetworkPolicyManager.Listener() { 185 @Override 186 public void onUidPoliciesChanged(final int uid, final int uidPolicies) { 187 ThreadUtils.postOnMainThread(() -> handleUidPoliciesChanged(uid, uidPolicies)); 188 } 189 190 @Override 191 public void onRestrictBackgroundChanged(final boolean isDataSaving) { 192 ThreadUtils.postOnMainThread(() -> handleRestrictBackgroundChanged(isDataSaving)); 193 } 194 }; 195 196 public interface Listener { onDataSaverChanged(boolean isDataSaving)197 void onDataSaverChanged(boolean isDataSaving); 198 199 /** This is called when allow list status is changed. */ onAllowlistStatusChanged(int uid, boolean isAllowlisted)200 default void onAllowlistStatusChanged(int uid, boolean isAllowlisted) {} 201 202 /** This is called when deny list status is changed. */ onDenylistStatusChanged(int uid, boolean isDenylisted)203 default void onDenylistStatusChanged(int uid, boolean isDenylisted) {} 204 } 205 } 206