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.checkIfMeteredDataRestricted;
17 
18 import android.content.Context;
19 import android.os.UserHandle;
20 import android.view.View;
21 
22 import androidx.preference.PreferenceViewHolder;
23 
24 import com.android.settings.R;
25 import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
26 import com.android.settings.dashboard.DashboardFragment;
27 import com.android.settings.widget.AppSwitchPreference;
28 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
29 import com.android.settingslib.RestrictedPreferenceHelper;
30 import com.android.settingslib.applications.ApplicationsState;
31 import com.android.settingslib.applications.ApplicationsState.AppEntry;
32 
33 public class UnrestrictedDataAccessPreference extends AppSwitchPreference implements
34         DataSaverBackend.Listener {
35 
36     private final ApplicationsState mApplicationsState;
37     private final AppEntry mEntry;
38     private final AppStateDataUsageBridge.DataUsageState mDataUsageState;
39     private final DataSaverBackend mDataSaverBackend;
40     private final DashboardFragment mParentFragment;
41     private final RestrictedPreferenceHelper mHelper;
42 
UnrestrictedDataAccessPreference(final Context context, AppEntry entry, ApplicationsState applicationsState, DataSaverBackend dataSaverBackend, DashboardFragment parentFragment)43     public UnrestrictedDataAccessPreference(final Context context, AppEntry entry,
44             ApplicationsState applicationsState, DataSaverBackend dataSaverBackend,
45             DashboardFragment parentFragment) {
46         super(context);
47         setWidgetLayoutResource(R.layout.restricted_switch_widget);
48         mHelper = new RestrictedPreferenceHelper(context, this, null);
49         mEntry = entry;
50         mDataUsageState = (AppStateDataUsageBridge.DataUsageState) mEntry.extraInfo;
51         mEntry.ensureLabel(context);
52         mApplicationsState = applicationsState;
53         mDataSaverBackend = dataSaverBackend;
54         mParentFragment = parentFragment;
55         setDisabledByAdmin(checkIfMeteredDataRestricted(context, entry.info.packageName,
56                 UserHandle.getUserId(entry.info.uid)));
57         updateState();
58         setKey(generateKey(mEntry));
59         if (mEntry.icon != null) {
60             setIcon(mEntry.icon);
61         }
62     }
63 
generateKey(final AppEntry entry)64     static String generateKey(final AppEntry entry) {
65         return entry.info.packageName + "|" + entry.info.uid;
66     }
67 
68     @Override
onAttached()69     public void onAttached() {
70         super.onAttached();
71         mDataSaverBackend.addListener(this);
72     }
73 
74     @Override
onDetached()75     public void onDetached() {
76         mDataSaverBackend.remListener(this);
77         super.onDetached();
78     }
79 
80     @Override
onClick()81     protected void onClick() {
82         if (mDataUsageState.isDataSaverBlacklisted) {
83             // app is blacklisted, launch App Data Usage screen
84             AppInfoDashboardFragment.startAppInfoFragment(AppDataUsage.class,
85                     R.string.data_usage_app_summary_title,
86                     null /* arguments */,
87                     mParentFragment,
88                     mEntry);
89         } else {
90             // app is not blacklisted, let superclass handle toggle switch
91             super.onClick();
92         }
93     }
94 
95     @Override
performClick()96     public void performClick() {
97         if (!mHelper.performClick()) {
98             super.performClick();
99         }
100     }
101 
102     @Override
onBindViewHolder(PreferenceViewHolder holder)103     public void onBindViewHolder(PreferenceViewHolder holder) {
104         if (mEntry.icon == null) {
105             holder.itemView.post(new Runnable() {
106                 @Override
107                 public void run() {
108                     // Ensure we have an icon before binding.
109                     mApplicationsState.ensureIcon(mEntry);
110                     // This might trigger us to bind again, but it gives an easy way to only
111                     // load the icon once its needed, so its probably worth it.
112                     setIcon(mEntry.icon);
113                 }
114             });
115         }
116         final boolean disabledByAdmin = isDisabledByAdmin();
117         final View widgetFrame = holder.findViewById(android.R.id.widget_frame);
118         if (disabledByAdmin) {
119             widgetFrame.setVisibility(View.VISIBLE);
120         } else {
121             widgetFrame.setVisibility(
122                     mDataUsageState != null && mDataUsageState.isDataSaverBlacklisted
123                             ? View.INVISIBLE : View.VISIBLE);
124         }
125         super.onBindViewHolder(holder);
126 
127         mHelper.onBindViewHolder(holder);
128         holder.findViewById(R.id.restricted_icon).setVisibility(
129                 disabledByAdmin ? View.VISIBLE : View.GONE);
130         holder.findViewById(android.R.id.switch_widget).setVisibility(
131                 disabledByAdmin ? View.GONE : View.VISIBLE);
132     }
133 
134     @Override
onDataSaverChanged(boolean isDataSaving)135     public void onDataSaverChanged(boolean isDataSaving) {
136     }
137 
138     @Override
onWhitelistStatusChanged(int uid, boolean isWhitelisted)139     public void onWhitelistStatusChanged(int uid, boolean isWhitelisted) {
140         if (mDataUsageState != null && mEntry.info.uid == uid) {
141             mDataUsageState.isDataSaverWhitelisted = isWhitelisted;
142             updateState();
143         }
144     }
145 
146     @Override
onBlacklistStatusChanged(int uid, boolean isBlacklisted)147     public void onBlacklistStatusChanged(int uid, boolean isBlacklisted) {
148         if (mDataUsageState != null && mEntry.info.uid == uid) {
149             mDataUsageState.isDataSaverBlacklisted = isBlacklisted;
150             updateState();
151         }
152     }
153 
getDataUsageState()154     public AppStateDataUsageBridge.DataUsageState getDataUsageState() {
155         return mDataUsageState;
156     }
157 
getEntry()158     public AppEntry getEntry() {
159         return mEntry;
160     }
161 
isDisabledByAdmin()162     public boolean isDisabledByAdmin() {
163         return mHelper.isDisabledByAdmin();
164     }
165 
setDisabledByAdmin(EnforcedAdmin admin)166     public void setDisabledByAdmin(EnforcedAdmin admin) {
167         mHelper.setDisabledByAdmin(admin);
168     }
169 
170     // Sets UI state based on whitelist/blacklist status.
updateState()171     public void updateState() {
172         setTitle(mEntry.label);
173         if (mDataUsageState != null) {
174             setChecked(mDataUsageState.isDataSaverWhitelisted);
175             if (isDisabledByAdmin()) {
176                 setSummary(R.string.disabled_by_admin);
177             } else if (mDataUsageState.isDataSaverBlacklisted) {
178                 setSummary(R.string.restrict_background_blacklisted);
179             } else {
180                 setSummary("");
181             }
182         }
183         notifyChanged();
184     }
185 }
186