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