Files
app_Settings/src/com/android/settings/datausage/UnrestrictedDataAccessPreferenceController.java
Mill Chen fdbf748dc0 Ensure loading all apps once in ManageApplications
Some pages that extend ManageApplications always display a loading
spinner when entering them. This is caused by that it takes over
100 ms to load all apps and to sort the apps. In addition, the task of
loading all apps might be invoked twice, which caused loading time
increasing.

This CL is to make sure the task of loading all apps execute only once
in those pages that extend ManageApplications.

Bug: 222985623
Test: manual test
Change-Id: I3b15bf2eee2a4c220f42da39a29f0014cc620898
2022-05-06 15:55:36 +08:00

243 lines
8.2 KiB
Java

/*
* 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.checkIfMeteredDataRestricted;
import android.app.Application;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.UserHandle;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnDestroy;
import com.android.settingslib.core.lifecycle.events.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
import java.util.ArrayList;
import java.util.Set;
import java.util.TreeSet;
public class UnrestrictedDataAccessPreferenceController extends BasePreferenceController implements
LifecycleObserver, OnStart, OnStop, OnDestroy, ApplicationsState.Callbacks,
AppStateBaseBridge.Callback, Preference.OnPreferenceChangeListener {
private final ApplicationsState mApplicationsState;
private final AppStateDataUsageBridge mDataUsageBridge;
private final DataSaverBackend mDataSaverBackend;
private ApplicationsState.Session mSession;
private AppFilter mFilter;
private DashboardFragment mParentFragment;
private PreferenceScreen mScreen;
private boolean mExtraLoaded;
public UnrestrictedDataAccessPreferenceController(Context context, String key) {
super(context, key);
mApplicationsState = ApplicationsState.getInstance(
(Application) context.getApplicationContext());
mDataSaverBackend = new DataSaverBackend(context);
mDataUsageBridge = new AppStateDataUsageBridge(mApplicationsState, this, mDataSaverBackend);
}
public void setFilter(AppFilter filter) {
mFilter = filter;
}
public void setParentFragment(DashboardFragment parentFragment) {
mParentFragment = parentFragment;
}
public void setSession(Lifecycle lifecycle) {
mSession = mApplicationsState.newSession(this, lifecycle);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mScreen = screen;
}
@Override
public int getAvailabilityStatus() {
return mContext.getResources().getBoolean(R.bool.config_show_data_saver)
? AVAILABLE_UNSEARCHABLE
: UNSUPPORTED_ON_DEVICE;
}
@Override
public void onStart() {
mDataUsageBridge.resume(true /* forceLoadAllApps */);
}
@Override
public void onStop() {
mDataUsageBridge.pause();
}
@Override
public void onDestroy() {
mDataUsageBridge.release();
}
@Override
public void onExtraInfoUpdated() {
mExtraLoaded = true;
rebuild();
}
@Override
public void onRunningStateChanged(boolean running) {
}
@Override
public void onPackageListChanged() {
}
@Override
public void onRebuildComplete(ArrayList<AppEntry> apps) {
if (apps == null) {
return;
}
// Preload top visible icons of app list.
AppUtils.preloadTopIcons(mContext, apps,
mContext.getResources().getInteger(R.integer.config_num_visible_app_icons));
// Create apps key set for removing useless preferences
final Set<String> appsKeySet = new TreeSet<>();
// Add or update preferences
final int N = apps.size();
for (int i = 0; i < N; i++) {
final AppEntry entry = apps.get(i);
if (!shouldAddPreference(entry)) {
continue;
}
final String prefkey = UnrestrictedDataAccessPreference.generateKey(entry);
appsKeySet.add(prefkey);
UnrestrictedDataAccessPreference preference =
(UnrestrictedDataAccessPreference) mScreen.findPreference(prefkey);
if (preference == null) {
preference = new UnrestrictedDataAccessPreference(mScreen.getContext(), entry,
mApplicationsState, mDataSaverBackend, mParentFragment);
preference.setOnPreferenceChangeListener(this);
mScreen.addPreference(preference);
} else {
preference.setDisabledByAdmin(checkIfMeteredDataRestricted(mContext,
entry.info.packageName, UserHandle.getUserId(entry.info.uid)));
preference.updateState();
}
preference.setOrder(i);
}
// Remove useless preferences
removeUselessPrefs(appsKeySet);
}
@Override
public void onPackageIconChanged() {
}
@Override
public void onPackageSizeChanged(String packageName) {
}
@Override
public void onAllSizesComputed() {
}
@Override
public void onLauncherInfoChanged() {
}
@Override
public void onLoadEntriesCompleted() {
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (preference instanceof UnrestrictedDataAccessPreference) {
final UnrestrictedDataAccessPreference
accessPreference = (UnrestrictedDataAccessPreference) preference;
boolean allowlisted = newValue == Boolean.TRUE;
logSpecialPermissionChange(allowlisted, accessPreference.getEntry().info.packageName);
mDataSaverBackend.setIsAllowlisted(accessPreference.getEntry().info.uid,
accessPreference.getEntry().info.packageName, allowlisted);
accessPreference.getDataUsageState().isDataSaverAllowlisted = allowlisted;
return true;
}
return false;
}
public void rebuild() {
if (!mExtraLoaded) {
return;
}
final ArrayList<AppEntry> apps = mSession.rebuild(mFilter,
ApplicationsState.ALPHA_COMPARATOR);
if (apps != null) {
onRebuildComplete(apps);
}
}
private void removeUselessPrefs(final Set<String> appsKeySet) {
final int prefCount = mScreen.getPreferenceCount();
String prefKey;
if (prefCount > 0) {
for (int i = prefCount - 1; i >= 0; i--) {
Preference pref = mScreen.getPreference(i);
prefKey = pref.getKey();
if (!appsKeySet.isEmpty() && appsKeySet.contains(prefKey)) {
continue;
}
mScreen.removePreference(pref);
}
}
}
@VisibleForTesting
void logSpecialPermissionChange(boolean allowlisted, String packageName) {
final int logCategory = allowlisted ? SettingsEnums.APP_SPECIAL_PERMISSION_UNL_DATA_ALLOW
: SettingsEnums.APP_SPECIAL_PERMISSION_UNL_DATA_DENY;
FeatureFactory.getFactory(mContext).getMetricsFeatureProvider().action(mContext,
logCategory, packageName);
}
@VisibleForTesting
static boolean shouldAddPreference(AppEntry app) {
return app != null && UserHandle.isApp(app.info.uid);
}
}