• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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