| /* | |
| * Copyright (C) 2018 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file | |
| * except in compliance with the License. You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software distributed under the | |
| * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| * KIND, either express or implied. See the License for the specific language governing | |
| * permissions and limitations under the License. | |
| */ | |
| package com.android.settings.datausage; | |
| import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfMeteredDataUsageUserControlDisabled; | |
| import android.content.Context; | |
| import android.graphics.drawable.Drawable; | |
| import android.os.UserHandle; | |
| import android.view.View; | |
| import androidx.annotation.NonNull; | |
| import androidx.annotation.Nullable; | |
| import androidx.annotation.VisibleForTesting; | |
| import androidx.preference.PreferenceViewHolder; | |
| import com.android.settings.R; | |
| import com.android.settings.applications.appinfo.AppInfoDashboardFragment; | |
| import com.android.settings.dashboard.DashboardFragment; | |
| import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; | |
| import com.android.settingslib.RestrictedPreferenceHelper; | |
| import com.android.settingslib.RestrictedPreferenceHelperProvider; | |
| import com.android.settingslib.applications.AppUtils; | |
| import com.android.settingslib.applications.ApplicationsState; | |
| import com.android.settingslib.applications.ApplicationsState.AppEntry; | |
| import com.android.settingslib.utils.ThreadUtils; | |
| import com.android.settingslib.widget.AppSwitchPreference; | |
| public class UnrestrictedDataAccessPreference extends AppSwitchPreference implements | |
| DataSaverBackend.Listener, RestrictedPreferenceHelperProvider { | |
| private static final String ECM_SETTING_IDENTIFIER = "android:unrestricted_data_access"; | |
| private final ApplicationsState mApplicationsState; | |
| private final AppEntry mEntry; | |
| private final AppStateDataUsageBridge.DataUsageState mDataUsageState; | |
| private final DataSaverBackend mDataSaverBackend; | |
| private final DashboardFragment mParentFragment; | |
| private final RestrictedPreferenceHelper mHelper; | |
| private Drawable mCacheIcon; | |
| public UnrestrictedDataAccessPreference(final Context context, AppEntry entry, | |
| ApplicationsState applicationsState, DataSaverBackend dataSaverBackend, | |
| DashboardFragment parentFragment) { | |
| super(context); | |
| mHelper = new RestrictedPreferenceHelper(context, this, null); | |
| mEntry = entry; | |
| mDataUsageState = (AppStateDataUsageBridge.DataUsageState) mEntry.extraInfo; | |
| mEntry.ensureLabel(context); | |
| mApplicationsState = applicationsState; | |
| mDataSaverBackend = dataSaverBackend; | |
| mParentFragment = parentFragment; | |
| setDisabledByAdmin(checkIfMeteredDataUsageUserControlDisabled( | |
| context, entry.info.packageName, UserHandle.getUserId(entry.info.uid))); | |
| mHelper.checkEcmRestrictionAndSetDisabled(ECM_SETTING_IDENTIFIER, entry.info.packageName); | |
| updateState(); | |
| setKey(generateKey(mEntry)); | |
| mCacheIcon = AppUtils.getIconFromCache(mEntry); | |
| if (mCacheIcon != null) { | |
| setIcon(mCacheIcon); | |
| } else { | |
| // Set empty icon as default. | |
| setIcon(R.drawable.empty_icon); | |
| } | |
| } | |
| static String generateKey(final AppEntry entry) { | |
| return entry.info.packageName + "|" + entry.info.uid; | |
| } | |
| @Override | |
| public @NonNull RestrictedPreferenceHelper getRestrictedPreferenceHelper() { | |
| return mHelper; | |
| } | |
| @Override | |
| public void onAttached() { | |
| super.onAttached(); | |
| mDataSaverBackend.addListener(this); | |
| } | |
| @Override | |
| public void onDetached() { | |
| mDataSaverBackend.remListener(this); | |
| super.onDetached(); | |
| } | |
| @Override | |
| protected void onClick() { | |
| if (mDataUsageState != null && mDataUsageState.isDataSaverDenylisted) { | |
| // app is denylisted, launch App Data Usage screen | |
| AppInfoDashboardFragment.startAppInfoFragment(AppDataUsage.class, | |
| R.string.data_usage_app_summary_title, | |
| null /* arguments */, | |
| mParentFragment, | |
| mEntry); | |
| } else { | |
| // app is not denylisted, let superclass handle toggle switch | |
| super.onClick(); | |
| } | |
| } | |
| @Override | |
| public void performClick() { | |
| if (!mHelper.performClick()) { | |
| super.performClick(); | |
| } | |
| } | |
| @Override | |
| public void onBindViewHolder(PreferenceViewHolder holder) { | |
| if (mCacheIcon == null) { | |
| ThreadUtils.postOnBackgroundThread(() -> { | |
| final Drawable icon = AppUtils.getIcon(getContext(), mEntry); | |
| ThreadUtils.postOnMainThread(() -> { | |
| setIcon(icon); | |
| mCacheIcon = icon; | |
| }); | |
| }); | |
| } | |
| final boolean disabledByAdmin = isDisabledByAdmin(); | |
| final View widgetFrame = holder.findViewById(android.R.id.widget_frame); | |
| if (disabledByAdmin) { | |
| widgetFrame.setVisibility(View.VISIBLE); | |
| } else { | |
| widgetFrame.setVisibility( | |
| mDataUsageState != null && mDataUsageState.isDataSaverDenylisted | |
| ? View.INVISIBLE : View.VISIBLE); | |
| } | |
| super.onBindViewHolder(holder); | |
| mHelper.onBindViewHolder(holder); | |
| } | |
| @Override | |
| public void onDataSaverChanged(boolean isDataSaving) { | |
| } | |
| @Override | |
| public void onAllowlistStatusChanged(int uid, boolean isAllowlisted) { | |
| if (mDataUsageState != null && mEntry.info.uid == uid) { | |
| mDataUsageState.isDataSaverAllowlisted = isAllowlisted; | |
| updateState(); | |
| } | |
| } | |
| @Override | |
| public void onDenylistStatusChanged(int uid, boolean isDenylisted) { | |
| if (mDataUsageState != null && mEntry.info.uid == uid) { | |
| mDataUsageState.isDataSaverDenylisted = isDenylisted; | |
| updateState(); | |
| } | |
| } | |
| @Nullable | |
| public AppStateDataUsageBridge.DataUsageState getDataUsageState() { | |
| return mDataUsageState; | |
| } | |
| public AppEntry getEntry() { | |
| return mEntry; | |
| } | |
| public boolean isDisabledByAdmin() { | |
| return mHelper.isDisabledByAdmin(); | |
| } | |
| @VisibleForTesting | |
| boolean isDisabledByEcm() { | |
| return mHelper.isDisabledByEcm(); | |
| } | |
| public void setDisabledByAdmin(EnforcedAdmin admin) { | |
| mHelper.setDisabledByAdmin(admin); | |
| } | |
| /** | |
| * Checks if the given setting is subject to Enhanced Confirmation Mode restrictions for this | |
| * package. Marks the preference as disabled if so. | |
| * @param packageName the package to check the restriction for | |
| */ | |
| public void checkEcmRestrictionAndSetDisabled(@NonNull String packageName) { | |
| mHelper.checkEcmRestrictionAndSetDisabled(ECM_SETTING_IDENTIFIER, packageName); | |
| } | |
| // Sets UI state based on allowlist/denylist status. | |
| public void updateState() { | |
| setTitle(mEntry.label); | |
| if (mDataUsageState != null) { | |
| setChecked(mDataUsageState.isDataSaverAllowlisted); | |
| if (isDisabledByAdmin()) { | |
| setSummary(com.android.settingslib.widget.restricted.R.string.disabled_by_admin); | |
| } else if (mDataUsageState.isDataSaverDenylisted) { | |
| setSummary(R.string.restrict_background_blocklisted); | |
| // If disabled by ECM, the summary is set directly by the switch. | |
| } else if (!isDisabledByEcm()) { | |
| setSummary(""); | |
| } | |
| } | |
| notifyChanged(); | |
| } | |
| } |