• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 package com.android.settings.datausage;
15 
16 import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfMeteredDataUsageUserControlDisabled;
17 
18 import android.content.Context;
19 import android.graphics.drawable.Drawable;
20 import android.os.UserHandle;
21 import android.view.View;
22 
23 import androidx.annotation.NonNull;
24 import androidx.annotation.Nullable;
25 import androidx.annotation.VisibleForTesting;
26 import androidx.preference.PreferenceViewHolder;
27 
28 import com.android.settings.R;
29 import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
30 import com.android.settings.dashboard.DashboardFragment;
31 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
32 import com.android.settingslib.RestrictedPreferenceHelper;
33 import com.android.settingslib.RestrictedPreferenceHelperProvider;
34 import com.android.settingslib.applications.AppUtils;
35 import com.android.settingslib.applications.ApplicationsState;
36 import com.android.settingslib.applications.ApplicationsState.AppEntry;
37 import com.android.settingslib.utils.ThreadUtils;
38 import com.android.settingslib.widget.AppSwitchPreference;
39 
40 public class UnrestrictedDataAccessPreference extends AppSwitchPreference implements
41         DataSaverBackend.Listener, RestrictedPreferenceHelperProvider {
42     private static final String ECM_SETTING_IDENTIFIER = "android:unrestricted_data_access";
43 
44     private final ApplicationsState mApplicationsState;
45     private final AppEntry mEntry;
46     private final AppStateDataUsageBridge.DataUsageState mDataUsageState;
47     private final DataSaverBackend mDataSaverBackend;
48     private final DashboardFragment mParentFragment;
49     private final RestrictedPreferenceHelper mHelper;
50     private Drawable mCacheIcon;
51 
UnrestrictedDataAccessPreference(final Context context, AppEntry entry, ApplicationsState applicationsState, DataSaverBackend dataSaverBackend, DashboardFragment parentFragment)52     public UnrestrictedDataAccessPreference(final Context context, AppEntry entry,
53             ApplicationsState applicationsState, DataSaverBackend dataSaverBackend,
54             DashboardFragment parentFragment) {
55         super(context);
56         mHelper = new RestrictedPreferenceHelper(context, this, null);
57         mEntry = entry;
58         mDataUsageState = (AppStateDataUsageBridge.DataUsageState) mEntry.extraInfo;
59         mEntry.ensureLabel(context);
60         mApplicationsState = applicationsState;
61         mDataSaverBackend = dataSaverBackend;
62         mParentFragment = parentFragment;
63         setDisabledByAdmin(checkIfMeteredDataUsageUserControlDisabled(
64                 context, entry.info.packageName, UserHandle.getUserId(entry.info.uid)));
65         mHelper.checkEcmRestrictionAndSetDisabled(ECM_SETTING_IDENTIFIER, entry.info.packageName);
66         updateState();
67         setKey(generateKey(mEntry));
68 
69         mCacheIcon = AppUtils.getIconFromCache(mEntry);
70         if (mCacheIcon != null) {
71             setIcon(mCacheIcon);
72         } else {
73             // Set empty icon as default.
74             setIcon(R.drawable.empty_icon);
75         }
76     }
77 
generateKey(final AppEntry entry)78     static String generateKey(final AppEntry entry) {
79         return entry.info.packageName + "|" + entry.info.uid;
80     }
81 
82     @Override
getRestrictedPreferenceHelper()83     public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() {
84         return mHelper;
85     }
86 
87     @Override
onAttached()88     public void onAttached() {
89         super.onAttached();
90         mDataSaverBackend.addListener(this);
91     }
92 
93     @Override
onDetached()94     public void onDetached() {
95         mDataSaverBackend.remListener(this);
96         super.onDetached();
97     }
98 
99     @Override
onClick()100     protected void onClick() {
101         if (mDataUsageState != null && mDataUsageState.isDataSaverDenylisted) {
102             // app is denylisted, launch App Data Usage screen
103             AppInfoDashboardFragment.startAppInfoFragment(AppDataUsage.class,
104                     R.string.data_usage_app_summary_title,
105                     null /* arguments */,
106                     mParentFragment,
107                     mEntry);
108         } else {
109             // app is not denylisted, let superclass handle toggle switch
110             super.onClick();
111         }
112     }
113 
114     @Override
performClick()115     public void performClick() {
116         if (!mHelper.performClick()) {
117             super.performClick();
118         }
119     }
120 
121     @Override
onBindViewHolder(PreferenceViewHolder holder)122     public void onBindViewHolder(PreferenceViewHolder holder) {
123         if (mCacheIcon == null) {
124             ThreadUtils.postOnBackgroundThread(() -> {
125                 final Drawable icon = AppUtils.getIcon(getContext(), mEntry);
126                 ThreadUtils.postOnMainThread(() -> {
127                     setIcon(icon);
128                     mCacheIcon = icon;
129                 });
130             });
131         }
132         final boolean disabledByAdmin = isDisabledByAdmin();
133         final View widgetFrame = holder.findViewById(android.R.id.widget_frame);
134         if (disabledByAdmin) {
135             widgetFrame.setVisibility(View.VISIBLE);
136         } else {
137             widgetFrame.setVisibility(
138                     mDataUsageState != null && mDataUsageState.isDataSaverDenylisted
139                             ? View.INVISIBLE : View.VISIBLE);
140         }
141         super.onBindViewHolder(holder);
142 
143         mHelper.onBindViewHolder(holder);
144     }
145 
146     @Override
onDataSaverChanged(boolean isDataSaving)147     public void onDataSaverChanged(boolean isDataSaving) {
148     }
149 
150     @Override
onAllowlistStatusChanged(int uid, boolean isAllowlisted)151     public void onAllowlistStatusChanged(int uid, boolean isAllowlisted) {
152         if (mDataUsageState != null && mEntry.info.uid == uid) {
153             mDataUsageState.isDataSaverAllowlisted = isAllowlisted;
154             updateState();
155         }
156     }
157 
158     @Override
onDenylistStatusChanged(int uid, boolean isDenylisted)159     public void onDenylistStatusChanged(int uid, boolean isDenylisted) {
160         if (mDataUsageState != null && mEntry.info.uid == uid) {
161             mDataUsageState.isDataSaverDenylisted = isDenylisted;
162             updateState();
163         }
164     }
165 
166     @Nullable
getDataUsageState()167     public AppStateDataUsageBridge.DataUsageState getDataUsageState() {
168         return mDataUsageState;
169     }
170 
getEntry()171     public AppEntry getEntry() {
172         return mEntry;
173     }
174 
isDisabledByAdmin()175     public boolean isDisabledByAdmin() {
176         return mHelper.isDisabledByAdmin();
177     }
178 
179     @VisibleForTesting
isDisabledByEcm()180     boolean isDisabledByEcm() {
181         return mHelper.isDisabledByEcm();
182     }
183 
setDisabledByAdmin(EnforcedAdmin admin)184     public void setDisabledByAdmin(EnforcedAdmin admin) {
185         mHelper.setDisabledByAdmin(admin);
186     }
187 
188     /**
189      * Checks if the given setting is subject to Enhanced Confirmation Mode restrictions for this
190      * package. Marks the preference as disabled if so.
191      * @param packageName the package to check the restriction for
192      */
checkEcmRestrictionAndSetDisabled(@onNull String packageName)193     public void checkEcmRestrictionAndSetDisabled(@NonNull String packageName) {
194         mHelper.checkEcmRestrictionAndSetDisabled(ECM_SETTING_IDENTIFIER, packageName);
195     }
196 
197     // Sets UI state based on allowlist/denylist status.
updateState()198     public void updateState() {
199         setTitle(mEntry.label);
200         if (mDataUsageState != null) {
201             setChecked(mDataUsageState.isDataSaverAllowlisted);
202             if (isDisabledByAdmin()) {
203                 setSummary(com.android.settingslib.widget.restricted.R.string.disabled_by_admin);
204             } else if (mDataUsageState.isDataSaverDenylisted) {
205                 setSummary(R.string.restrict_background_blocklisted);
206             // If disabled by ECM, the summary is set directly by the switch.
207             } else if (!isDisabledByEcm()) {
208                 setSummary("");
209             }
210         }
211         notifyChanged();
212     }
213 }
214