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