Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 218ef2f0 authored by Chaohui Wang's avatar Chaohui Wang Committed by Android (Google) Code Review
Browse files

Merge "Create AppDataUsageListController" into main

parents 17354749 b19eb9a4
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -76,6 +76,7 @@

    <PreferenceCategory
        android:key="app_list"
        android:title="@string/data_usage_other_apps" />
        android:title="@string/data_usage_other_apps"
        settings:controller="com.android.settings.datausage.AppDataUsageListController" />

</PreferenceScreen>
+7 −40
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@ package com.android.settings.datausage;

import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;

import static com.android.settings.datausage.lib.AppDataUsageRepository.getAppUid;

import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
@@ -32,6 +34,7 @@ import android.util.ArraySet;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.Range;
import android.util.SparseBooleanArray;
import android.view.View;
import android.widget.AdapterView;

@@ -42,7 +45,6 @@ import androidx.loader.app.LoaderManager;
import androidx.loader.content.Loader;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceCategory;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;

@@ -78,12 +80,10 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
    private static final String KEY_BACKGROUND_USAGE = "background_usage";
    private static final String KEY_APP_SETTINGS = "app_settings";
    private static final String KEY_RESTRICT_BACKGROUND = "restrict_background";
    private static final String KEY_APP_LIST = "app_list";
    private static final String KEY_CYCLE = "cycle";
    private static final String KEY_UNRESTRICTED_DATA = "unrestricted_data_saver";

    private static final int LOADER_APP_USAGE_DATA = 2;
    private static final int LOADER_APP_PREF = 3;

    private PackageManager mPackageManager;
    private final ArraySet<String> mPackages = new ArraySet<>();
@@ -92,7 +92,6 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
    private Preference mBackgroundUsage;
    private Preference mAppSettings;
    private RestrictedSwitchPreference mRestrictBackground;
    private PreferenceCategory mAppList;

    private Drawable mIcon;
    @VisibleForTesting
@@ -170,6 +169,7 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC

        final UidDetailProvider uidDetailProvider = getUidDetailProvider();

        final var appDataUsageListController = use(AppDataUsageListController.class);
        if (mAppItem.key > 0) {
            if ((!isSimHardwareVisible(mContext)) || !UserHandle.isApp(mAppItem.key)) {
                final UidDetail uidDetail = uidDetailProvider.getUidDetail(mAppItem.key, true);
@@ -212,14 +212,8 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
                removePreference(KEY_APP_SETTINGS);
                mAppSettings = null;
            }
            appDataUsageListController.init(mAppItem.uids);

            if (mPackages.size() > 1) {
                mAppList = findPreference(KEY_APP_LIST);
                LoaderManager.getInstance(this).restartLoader(LOADER_APP_PREF, Bundle.EMPTY,
                        mAppPrefCallbacks);
            } else {
                removePreference(KEY_APP_LIST);
            }
        } else {
            final Context context = getActivity();
            final UidDetail uidDetail = uidDetailProvider.getUidDetail(mAppItem.key, true);
@@ -230,7 +224,7 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
            removePreference(KEY_UNRESTRICTED_DATA);
            removePreference(KEY_APP_SETTINGS);
            removePreference(KEY_RESTRICT_BACKGROUND);
            removePreference(KEY_APP_LIST);
            appDataUsageListController.init(new SparseBooleanArray());
        }

        addEntityHeader();
@@ -360,11 +354,7 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
    }

    private void addUid(int uid) {
        if (Process.isSdkSandboxUid(uid)) {
            // For a sandbox process, get the associated app UID
            uid = Process.getAppUidForSdkSandboxUid(uid);
        }
        String[] packages = mPackageManager.getPackagesForUid(uid);
        String[] packages = mPackageManager.getPackagesForUid(getAppUid(uid));
        if (packages != null) {
            Collections.addAll(mPackages, packages);
        }
@@ -501,29 +491,6 @@ public class AppDataUsage extends DataUsageBaseFragment implements OnPreferenceC
                }
            };

    private final LoaderManager.LoaderCallbacks<ArraySet<Preference>> mAppPrefCallbacks =
            new LoaderManager.LoaderCallbacks<>() {
                @Override
                @NonNull
                public Loader<ArraySet<Preference>> onCreateLoader(int i, Bundle bundle) {
                    return new AppPrefLoader(getPrefContext(), mPackages, getPackageManager());
                }

                @Override
                public void onLoadFinished(@NonNull Loader<ArraySet<Preference>> loader,
                        ArraySet<Preference> preferences) {
                    if (preferences != null && mAppList != null) {
                        for (Preference preference : preferences) {
                            mAppList.addPreference(preference);
                        }
                    }
                }

                @Override
                public void onLoaderReset(@NonNull Loader<ArraySet<Preference>> loader) {
                }
            };

    @Override
    public void onDataSaverChanged(boolean isDataSaving) {

+79 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 android.content.Context
import android.util.SparseBooleanArray
import androidx.annotation.OpenForTesting
import androidx.core.util.keyIterator
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceScreen
import com.android.settings.core.BasePreferenceController
import com.android.settings.datausage.lib.AppDataUsageRepository.Companion.getAppUid
import com.android.settings.datausage.lib.AppPreferenceRepository
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

@OpenForTesting
open class AppDataUsageListController @JvmOverloads constructor(
    context: Context,
    preferenceKey: String,
    private val repository: AppPreferenceRepository = AppPreferenceRepository(context),
) : BasePreferenceController(context, preferenceKey) {

    private lateinit var uids: List<Int>
    private lateinit var preference: PreferenceGroup

    fun init(uids: SparseBooleanArray) {
        this.uids = uids.keyIterator().asSequence().map { getAppUid(it) }.distinct().toList()
    }

    override fun getAvailabilityStatus() = AVAILABLE

    override fun displayPreference(screen: PreferenceScreen) {
        super.displayPreference(screen)
        preference = screen.findPreference(preferenceKey)!!
    }

    override fun onViewCreated(viewLifecycleOwner: LifecycleOwner) {
        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                updateList()
            }
        }
    }

    private suspend fun updateList() {
        if (uids.size <= 1) {
            preference.isVisible = false
            return
        }
        preference.isVisible = true
        val appPreferences = withContext(Dispatchers.Default) {
            repository.loadAppPreferences(uids)
        }
        preference.removeAll()
        for (appPreference in appPreferences) {
            preference.addPreference(appPreference)
        }
    }
}
+0 −60
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 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 android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.util.ArraySet;

import androidx.preference.Preference;

import com.android.settingslib.utils.AsyncLoaderCompat;

public class AppPrefLoader extends AsyncLoaderCompat<ArraySet<Preference>> {
    private ArraySet<String> mPackages;
    private PackageManager mPackageManager;
    private Context mPrefContext;

    public AppPrefLoader(Context prefContext, ArraySet<String> pkgs, PackageManager pm) {
        super(prefContext);
        mPackages = pkgs;
        mPackageManager = pm;
        mPrefContext = prefContext;
    }

    @Override
    public ArraySet<Preference> loadInBackground() {
        ArraySet<Preference> results = new ArraySet<>();
        for (int i = 1, size = mPackages.size(); i < size; i++) {
            try {
                ApplicationInfo info = mPackageManager.getApplicationInfo(mPackages.valueAt(i), 0);
                Preference preference = new Preference(mPrefContext);
                preference.setIcon(info.loadIcon(mPackageManager));
                preference.setTitle(info.loadLabel(mPackageManager));
                preference.setSelectable(false);
                results.add(preference);
            } catch (PackageManager.NameNotFoundException e) {
            }
        }
        return results;
    }

    @Override
    protected void onDiscardResult(ArraySet<Preference> result) {
    }
}
+10 −6
Original line number Diff line number Diff line
@@ -126,12 +126,7 @@ class AppDataUsageRepository(
                            items = items,
                        )
                    }
                    // Map SDK sandbox back to its corresponding app
                    collapseKey = if (Process.isSdkSandboxUid(uid)) {
                        Process.getAppUidForSdkSandboxUid(uid)
                    } else {
                        uid
                    }
                    collapseKey = getAppUid(uid)
                    category = AppItem.CATEGORY_APP
                } else {
                    // If it is a removed user add it to the removed users' key
@@ -200,6 +195,15 @@ class AppDataUsageRepository(
            val bytes: Long,
        )

        @JvmStatic
        fun getAppUid(uid: Int): Int {
            if (Process.isSdkSandboxUid(uid)) {
                // For a sandbox process, get the associated app UID
                return Process.getAppUidForSdkSandboxUid(uid)
            }
            return uid
        }

        private fun convertToBuckets(stats: NetworkStats): List<Bucket> {
            val buckets = mutableListOf<Bucket>()
            stats.use {
Loading