【BUG】【K631AN】【应用分身】下载支持应用分身的应用(QQ),开启应用分身,返回桌面,会出现所有应用的分身。

1、进入设置中的应用界面逻辑代码

AppDashboardFragment.java,通过getPreferenceScreenResId()进入应用界面的布局文件app.xml

/** Copyright (C) 2021 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.applications;import android.app.settings.SettingsEnums;
import android.content.Context;
import android.provider.SearchIndexableResource;import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.search.SearchIndexable;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/** Settings page for apps. */
@SearchIndexable
public class AppDashboardFragment extends DashboardFragment {private static final String TAG = "AppDashboardFragment";private AppsPreferenceController mAppsPreferenceController;private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {final List<AbstractPreferenceController> controllers = new ArrayList<>();controllers.add(new AppsPreferenceController(context));return controllers;}@Overridepublic int getMetricsCategory() {return SettingsEnums.MANAGE_APPLICATIONS;}@Overrideprotected String getLogTag() {return TAG;}@Overridepublic int getHelpResource() {return R.string.help_url_apps_and_notifications;}@Overrideprotected int getPreferenceScreenResId() {return R.xml.apps;}@Overridepublic void onAttach(Context context) {super.onAttach(context);use(SpecialAppAccessPreferenceController.class).setSession(getSettingsLifecycle());mAppsPreferenceController = use(AppsPreferenceController.class);mAppsPreferenceController.setFragment(this /* fragment */);getSettingsLifecycle().addObserver(mAppsPreferenceController);final HibernatedAppsPreferenceController hibernatedAppsPreferenceController =use(HibernatedAppsPreferenceController.class);getSettingsLifecycle().addObserver(hibernatedAppsPreferenceController);}@Overrideprotected List<AbstractPreferenceController> createPreferenceControllers(Context context) {return buildPreferenceControllers(context);}public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =new BaseSearchIndexProvider() {@Overridepublic List<SearchIndexableResource> getXmlResourcesToIndex(Context context, boolean enabled) {final SearchIndexableResource sir = new SearchIndexableResource(context);sir.xmlResId = R.xml.apps;return Arrays.asList(sir);}@Overridepublic List<AbstractPreferenceController> createPreferenceControllers(Context context) {return buildPreferenceControllers(context);}};
}
<?xml version="1.0" encoding="utf-8"?>
<!--Copyright (C) 2020 The Android Open Source ProjectLicensed 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 athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, softwaredistributed 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 andlimitations under the License.--><PreferenceScreenxmlns:android="http://schemas.android.com/apk/res/android"xmlns:settings="http://schemas.android.com/apk/res-auto"android:key="apps_screen"android:title="@string/apps_dashboard_title"><Preferenceandroid:key="all_app_infos"android:title="@string/all_apps"android:summary="@string/summary_placeholder"android:order="-999"android:fragment="com.android.settings.applications.manageapplications.ManageApplications"settings:keywords="@string/keywords_applications_settings"/><!-- 最近打开的应用 --><PreferenceCategoryandroid:key="recent_apps_category"android:title="@string/recent_app_category_title"android:order="-998"settings:searchable="false"><!-- Placeholder for a list of recent apps --><!-- See all apps --><Preferenceandroid:key="see_all_apps"android:title="@string/default_see_all_apps_title"android:icon="@drawable/ic_chevron_right_24dp"android:fragment="com.android.settings.applications.manageapplications.ManageApplications"android:order="5"settings:searchable="false"></Preference></PreferenceCategory><PreferenceCategoryandroid:key="general_category"android:title="@string/category_name_general"android:order="-997"android:visibility="gone"settings:searchable="false"/><Preferenceandroid:key="default_apps"android:title="@string/app_default_dashboard_title"android:order="-996"settings:controller="com.android.settings.applications.DefaultAppsPreferenceController"><intent android:action="android.settings.MANAGE_DEFAULT_APPS_SETTINGS"/></Preference><Preferenceandroid:key="game_settings"android:title="@string/game_settings_title"android:summary="@string/game_settings_summary"android:order="-995"settings:controller="com.android.settings.applications.GameSettingsPreferenceController"></Preference><PreferenceCategoryandroid:key="dashboard_tile_placeholder"android:order="10"/><Preferenceandroid:key="hibernated_apps"android:title="@string/unused_apps"android:summary="@string/summary_placeholder"android:order="15"settings:keywords="app_hibernation_key"settings:controller="com.android.settings.applications.HibernatedAppsPreferenceController"><intent android:action="android.intent.action.MANAGE_UNUSED_APPS"/></Preference><Preferenceandroid:key="special_access"android:fragment="com.android.settings.applications.specialaccess.SpecialAccessSettings"android:title="@string/special_access"android:order="20"settings:controller="com.android.settings.applications.SpecialAppAccessPreferenceController"/><!-- 应用分身 --><Preferenceandroid:key="parallel_app"android:fragment="com.android.settings.applications.parallelapp.ParallelAppSettings"android:title="@string/parallel_app"android:order="25"settings:controller="com.android.settings.applications.parallelapp.ParallelAppPreferenceController"/>
</PreferenceScreen>

2、进入手机分身的fragment类

ParallelAppSettings.java

/** Copyright (C) 2016 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.applications.parallelapp;import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.widget.Switch;
import android.util.Log;import androidx.preference.PreferenceGroup;import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.SettingsActivity;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppFilter;import java.util.List;public class ParallelAppSettings extends DashboardFragment {private static final String TAG = "ParallelAppSettings";private static final String KEY = "app_list";private AppFilter mFilter;private int mCloneUserId = -1;private IActivityManager mAms;private UserManager mUm;PreferenceGroup mAppList;@Overridepublic void onAttach(Context context) {super.onAttach(context);mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);mFilter = ApplicationsState.FILTER_ALL_ENABLED;use(ManageParallelAppsPreferenceController.class).setSession(getSettingsLifecycle());use(ManageParallelAppsPreferenceController.class).setParentFragment(this);use(ManageParallelAppsPreferenceController.class).setFilter(mFilter);mAms = ActivityManager.getService();}@Overridepublic void onCreate(Bundle icicle) {super.onCreate(icicle);// 获取布局文件中PreferenceCategory中keymAppList = (PreferenceGroup) findPreference(KEY);android.util.Log.d("xin.wang", " Content of mAppList : " + mAppList.getPreferenceCount());// 视图反射进入ManageParallelAppsPreferenceController,设置setPreferenceGroupuse(ManageParallelAppsPreferenceController.class).setPreferenceGroup(mAppList);}@Overridepublic void onResume() {super.onResume();use(ManageParallelAppsPreferenceController.class).rebuild();}@Overrideprotected String getLogTag() {return TAG;}@Overrideprotected int getPreferenceScreenResId() {return R.xml.parallel_app_settings;}@Overridepublic int getMetricsCategory() {return SettingsEnums.PAGE_UNKNOWN;}
}

user()方法,是父类DashboardFragment的方法

 protected <T extends AbstractPreferenceController> T use(Class<T> clazz) {List<AbstractPreferenceController> controllerList = mPreferenceControllers.get(clazz);if (controllerList != null) {if (controllerList.size() > 1) {Log.w(TAG, "Multiple controllers of Class " + clazz.getSimpleName()+ " found, returning first one.");}return (T) controllerList.get(0);}return null;}

进入布局文件parallel_app_settings.xml

<PreferenceScreenxmlns:android="http://schemas.android.com/apk/res/android"xmlns:settings="http://schemas.android.com/apk/res-auto"android:key="parallel_app_settings"android:title="@string/parallel_app"settings:controller="com.android.settings.applications.parallelapp.ManageParallelAppsPreferenceController"settings:searchable="false"><com.android.settingslib.widget.TopIntroPreferenceandroid:key="support_app"android:title="@string/parallel_app_support"/><PreferenceCategoryandroid:key="app_list"android:order="10"settings:searchable="false"></PreferenceCategory></PreferenceScreen>

进入ManageParallelAppsPreferenceController

/** 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.applications.parallelapp;import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceGroup;import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.R;
import com.android.settings.Utils;
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 java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;public class ManageParallelAppsPreferenceController extends BasePreferenceController implementsApplicationsState.Callbacks, Preference.OnPreferenceChangeListener {private static final String TAG = "ManageParallelAppsPreferenceController";private final ApplicationsState mApplicationsState;private final PackageInstaller mPackageInstaller;private final PackageManager mPm;private final UserManager mUm;private ApplicationsState.Session mSession;private AppFilter mFilter;private Context mContext;private ParallelAppSettings mParentFragment;private HashSet<String> mSupportAppClone;PreferenceGroup mAppList;public ManageParallelAppsPreferenceController(Context context, String key) {super(context, key);mContext = context;mApplicationsState = ApplicationsState.getInstance((Application) context.getApplicationContext());mPm = mContext.getPackageManager();mPackageInstaller = mPm.getPackageInstaller();mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);//get app could cloning by -> com.tencent.mm=>微信,com.sina.weibo=>微博,com.tencent.mobilqq=>QQ,com.ss.android.ugc.aweme=>抖音// 读取支持手机分身的应用包名String[] supportApps = context.getResources().getStringArray(com.unisoc.internal.R.array.support_app_clone);// 将数组转化为列表mSupportAppClone = new HashSet<String>(Arrays.asList(supportApps));}@Overridepublic int getAvailabilityStatus() {ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);boolean isAdmin = mUm.isAdminUser();boolean isLowRam = activityManager.isLowRamDevice();boolean isSupportAppClone = mContext.getResources().getBoolean(R.bool.config_support_appclone);return isAdmin && !isLowRam && isSupportAppClone ? AVAILABLE : UNSUPPORTED_ON_DEVICE;}@Overridepublic void onRebuildComplete(ArrayList<AppEntry> apps) {if (apps == null) {return;}final Set<String> appsKeySet = new TreeSet<>();final int N = apps.size();android.util.Log.d("xin.wang", "apps.size -> " + N);for (int i = 0; i < N; i++) {final AppEntry entry = apps.get(i);android.util.Log.d("xin.wang", "AppEntry entry --> " + entry.toString());boolean isSupportClone = mSupportAppClone.contains(entry.info.packageName);android.util.Log.d("xin.wang", "get Should Clone for clone --> " + mSupportAppClone);android.util.Log.d("xin.wang", "get app packageName : -> " + entry.info.packageName + "<- isSupportClone ->" + isSupportClone );int userId = UserHandle.getUserId(entry.info.uid);boolean isAdminUser = mUm.isUserAdmin(userId);if (mSupportAppClone.contains(entry.info.packageName) && isAdminUser) {if (!shouldAddPreference(entry)) {continue;}final String prefkey = ParallelAppPreference.generateKey(entry);appsKeySet.add(prefkey);android.util.Log.d("xin.wang", " get appsKeySet -> " + appsKeySet + "<- prefkey ->" + prefkey);// 获取布局中keyParallelAppPreference preference =(ParallelAppPreference) mAppList.findPreference(prefkey);// 当布局为空的时候,实例化一个布局if (preference == null) {preference = new ParallelAppPreference(mContext, entry,mApplicationsState, mUm, mPm, mPackageInstaller);preference.setOnPreferenceChangeListener(this);mAppList.addPreference(preference);} else {preference.updateState();}preference.setOrder(i);}}removeUselessPrefs(appsKeySet);}@Overridepublic void onRunningStateChanged(boolean running) {}@Overridepublic void onPackageListChanged() {rebuild();}@Overridepublic void onPackageIconChanged() {}@Overridepublic void onPackageSizeChanged(String packageName) {}@Overridepublic void onAllSizesComputed() {}@Overridepublic void onLauncherInfoChanged() {}@Overridepublic void onLoadEntriesCompleted() {rebuild();}@Overridepublic boolean onPreferenceChange(Preference preference, Object newValue) {if (Utils.isMonkeyRunning()) {return true;}if (preference instanceof ParallelAppPreference) {ParallelAppPreference parAppPreference = (ParallelAppPreference)preference;if ((Boolean)newValue) {parAppPreference.openParApp();} else {parAppPreference.createCloseOptionsDialog(mParentFragment.getActivity());}}return true;}public void setFilter(AppFilter filter) {mFilter = filter;}public void setSession(Lifecycle lifecycle) {mSession = mApplicationsState.newSession(this, lifecycle);}public void setParentFragment(ParallelAppSettings parentFragment) {mParentFragment = parentFragment;}public void setPreferenceGroup(PreferenceGroup appList) {mAppList = appList;android.util.Log.d("xin.wang", "setPreferenceGroup: -> appList -> " + appList.getPreferenceCount());}private boolean shouldAddPreference(AppEntry app) {return app != null && UserHandle.isApp(app.info.uid);}private void removeUselessPrefs(final Set<String> appsKeySet) {final int prefCount = mAppList.getPreferenceCount();android.util.Log.d("xin.wang", "<- prefCount ->  " + prefCount);String prefKey;if (prefCount > 0) {for (int i = prefCount - 1; i >= 0; i--) {Preference pref = mAppList.getPreference(i);prefKey = pref.getKey();boolean isEmpty = !appsKeySet.isEmpty();boolean contains = appsKeySet.contains(prefKey);android.util.Log.d("xin.wang", "<- isEmpty -> " + isEmpty + "<- contains -> " + contains + "<- appsKeySet -> " + appsKeySet + "<- preKey ->" + prefKey);if (!appsKeySet.isEmpty() && appsKeySet.contains(prefKey)) {continue;}mAppList.removePreference(pref);}}}public void rebuild() {final ArrayList<AppEntry> apps = mSession.rebuild(mFilter,ApplicationsState.ALPHA_COMPARATOR);boolean flag = apps != null;if (apps != null) {android.util.Log.d("xin.wang", "rebuild: <-- apps -> " + apps.size());onRebuildComplete(apps);}}
}

进入分身的布局ParallelAppPreference.java

点击swicth开启分身的时候创建一个Toast来提醒

关闭分身弹出dialog,判断是否进行关闭

/** 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.applications.parallelapp;import android.app.Activity;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.view.View;
import android.widget.Toast;import androidx.appcompat.app.AlertDialog;
import androidx.preference.DialogPreference;
import androidx.preference.PreferenceViewHolder;import com.android.settings.R;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.widget.AppSwitchPreference;import java.util.List;public class ParallelAppPreference extends AppSwitchPreference {private final ApplicationsState mApplicationsState;private final AppEntry mEntry;private final PackageInstaller mPackageInstaller;private final PackageManager mPm;private final String TAG = "ParallelAppPreference";private final UserManager mUm;private Activity mActivity;private Context mContext;public ParallelAppPreference (final Context context, AppEntry entry,ApplicationsState applicationsState, UserManager um, PackageManager pm, PackageInstaller pi) {super(context);mContext = context;setWidgetLayoutResource(R.layout.restricted_switch_widget);mEntry = entry;mEntry.ensureLabel(context);mApplicationsState = applicationsState;mPm = pm;mPackageInstaller = pi;mUm = um;setKey(generateKey(mEntry));if (mEntry.icon == null) {mApplicationsState.ensureIcon(mEntry);}setIcon(mEntry.icon);setTitle(mEntry.label);updateState();}static String generateKey(final AppEntry entry) {android.util.Log.d("xin.wang", "generateKey: -> AppEntry ->  " + entry.info.packageName + " | " + entry.info.uid);return entry.info.packageName + "|" + entry.info.uid;}@Overridepublic void onBindViewHolder(PreferenceViewHolder holder) {if (mEntry.icon == null) {holder.itemView.post(new Runnable() {@Overridepublic void run() {mApplicationsState.ensureIcon(mEntry);setIcon(mEntry.icon);}});}final View widgetFrame = holder.findViewById(android.R.id.widget_frame);widgetFrame.setVisibility(View.VISIBLE);super.onBindViewHolder(holder);holder.findViewById(R.id.restricted_icon).setVisibility(View.GONE);holder.findViewById(android.R.id.switch_widget).setVisibility(View.VISIBLE);}// 更新状态public void updateState() {boolean isChecked = false;boolean hasCloneUser = hasCloneUser();try {if (hasCloneUser) {ApplicationInfo info = mPm.getApplicationInfoAsUser(mEntry.info.packageName, PackageManager.GET_META_DATA, getCloneUser());isChecked = (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 ? true : false;android.util.Log.d("xin.wang", "updateState -> 1 -> : " + isChecked);}android.util.Log.d("xin.wang", "updateState -> 2 -> : " + isChecked);setChecked(isChecked);} catch (NameNotFoundException e) {Log.e(TAG,"can not found Application "+mEntry.label);}}//关闭应用分身的时候弹出的dialog -> parallel_app_close -> 当关闭时分身应用的所有数据将会被清除。您确定要继续吗?public void createCloseOptionsDialog(Activity activity) {mActivity = activity;AlertDialog.Builder builder = new AlertDialog.Builder(mContext);builder.setMessage(mContext.getResources().getString(R.string.parallel_app_close));builder.setPositiveButton(android.R.string.ok, mDialogClickListener);builder.setNegativeButton(android.R.string.cancel, mDialogClickListener);AlertDialog dialog = builder.create();dialog.setCancelable(false);dialog.show();}// 开始手机分身public void openParApp() {if (!hasCloneUser()) {createAndStartCloneUser();}try {//应用双开的方法 -> installExistingPackageAsUser(String packageName,int userId);int status = mPm.installExistingPackageAsUser(mEntry.info.packageName, getCloneUser());android.util.Log.d("xin.wang", "openParApp: -> status -> " + status + "<- mEntry.info.packageName -> " + mEntry.info.packageName);if (status == PackageManager.INSTALL_SUCCEEDED) {   //PackageManager.INSTALL_SUCCEEDED -> 返回安装成功的状态码 1android.util.Log.d("xin.wang", "openParApp: -> status -> " + status);createToast();} else {Log.d(TAG, "open Parallel App failed status:"+status);}} catch (PackageManager.NameNotFoundException e) {Log.d(TAG, "open Parallel App failed ,"+e);}}// 创建开启分身的Toast -> 分身的 %1$s 已经创建private void createToast() {String content = String.format(mContext.getResources().getString(R.string.parallel_app_open), mEntry.label);Toast.makeText(mContext, content, Toast.LENGTH_LONG).show();}// 获取克隆的用户private int getCloneUser() {int cloneUserId = UserHandle.myUserId();int userCount = 0;List<UserInfo> users = mUm.getUsers();  //UserManager.getUser() -> 获取所有的用户信息for(UserInfo user : users){userCount++;android.util.Log.d("xin.wang", "getCloneUser: users -> " + userCount);if (user.userType != null && user.userType.equals(UserManager.USER_TYPE_PROFILE_CLONE)) {cloneUserId = user.id;}}return cloneUserId;}//判断是否克隆private boolean hasCloneUser() {boolean hasCloneUser = false;List<UserInfo> users = mUm.getUsers();  // UserManager.getUsers() -> 获取所有的用户信息android.util.Log.d("xin.wang", "hasCloneUser: -> user -> " + users + "<- user.size() -> " + users.size());for(UserInfo user : users){android.util.Log.d("xin.wang", "hasCloneUser: -> user.userType -> " + user.userType);if (user.userType != null && user.userType.equals(UserManager.USER_TYPE_PROFILE_CLONE)) {hasCloneUser = true;break;}}return hasCloneUser;}//创建第二个user用户private void createAndStartCloneUser() {String userName = mContext.getResources().getString(R.string.clone_user);UserInfo userInfo = mUm.createProfileForUser(userName, UserManager.USER_TYPE_PROFILE_CLONE,UserInfo.FLAG_PROFILE, UserHandle.USER_SYSTEM);IActivityManager ams = ActivityManager.getService();try {ams.startUserInBackground(userInfo.getUserHandle().getIdentifier());} catch(RemoteException e) {Log.d(TAG, "create and start clone user failed");e.printStackTrace();}}//关闭手机分身的时候弹出的dialogprivate DialogInterface.OnClickListener mDialogClickListener = new DialogInterface.OnClickListener() {public void onClick(DialogInterface arg0, int arg1) {if (arg1 == DialogInterface.BUTTON_NEGATIVE) { //DialogInterface.BUTTON_NEGATIVE -> 取消按钮,点击dialog的取消按钮setChecked(true);} else {//deletePackageAsUser(String packageName,IPackageDeleteObserver observer,int Flags,int userId);mPm.deletePackageAsUser(mEntry.info.packageName, null, 0, getCloneUser());android.util.Log.d("xin.wang", "DialogInterface.OnClickListener ->  mEntry.info.packageName -> " + mEntry.info.packageName);}}};
}

3、计算应用界面中应用的数量

通过该界面的布局文件app.xml中的key-> recent_apps_category

进入AppsPreferenceController.java类中,该类计算当前应用的数量,并且显示当前使用的应用数量

通过分析,可知,该方法中的loadAllAppsCount()加载所有app的数量,该方法实例化InstalledAppCounter类,并重写onCountComplete()方法

/** Copyright (C) 2021 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.applications;import android.app.Application;
import android.app.usage.UsageStats;
import android.content.Context;
import android.icu.text.RelativeDateTimeFormatter;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;import androidx.annotation.VisibleForTesting;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.OnLifecycleEvent;
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;import com.android.settings.R;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.Utils;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.utils.StringUtil;
import com.android.settingslib.widget.AppPreference;import java.util.List;
import java.util.Map;/*** This controller displays up to four recently used apps.* If there is no recently used app, we only show up an "App Info" preference.*/
public class AppsPreferenceController extends BasePreferenceController implementsLifecycleObserver {public static final int SHOW_RECENT_APP_COUNT = 4;@VisibleForTestingstatic final String KEY_RECENT_APPS_CATEGORY = "recent_apps_category";@VisibleForTestingstatic final String KEY_GENERAL_CATEGORY = "general_category";@VisibleForTestingstatic final String KEY_ALL_APP_INFO = "all_app_infos";@VisibleForTestingstatic final String KEY_SEE_ALL = "see_all_apps";private final ApplicationsState mApplicationsState;private final int mUserId;@VisibleForTestingList<UsageStats> mRecentApps;@VisibleForTestingPreferenceCategory mRecentAppsCategory;@VisibleForTestingPreferenceCategory mGeneralCategory;@VisibleForTestingPreference mAllAppsInfoPref;@VisibleForTestingPreference mSeeAllPref;private Fragment mHost;private boolean mInitialLaunch = false;public AppsPreferenceController(Context context) {super(context, KEY_RECENT_APPS_CATEGORY);mApplicationsState = ApplicationsState.getInstance((Application) mContext.getApplicationContext());mUserId = UserHandle.myUserId();}public void setFragment(Fragment fragment) {mHost = fragment;}@Overridepublic int getAvailabilityStatus() {return AVAILABLE_UNSEARCHABLE;}@Overridepublic void displayPreference(PreferenceScreen screen) {super.displayPreference(screen);initPreferences(screen);refreshUi();mInitialLaunch = true;}@Overridepublic void updateState(Preference preference) {super.updateState(preference);if (!mInitialLaunch) {refreshUi();}}/*** Called when the apps page pauses.*/@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)public void onPause() {mInitialLaunch = false;}@VisibleForTestingvoid refreshUi() {loadAllAppsCount();mRecentApps = loadRecentApps();android.util.Log.d("xin.wang", "mRecentApps -> : " + mRecentApps.size() + "<- loadAllAppsCount -> " + loadRecentApps());if (!mRecentApps.isEmpty()) {displayRecentApps();mAllAppsInfoPref.setVisible(false);mRecentAppsCategory.setVisible(true);mGeneralCategory.setVisible(true);mSeeAllPref.setVisible(true);} else {mAllAppsInfoPref.setVisible(true);mRecentAppsCategory.setVisible(false);mGeneralCategory.setVisible(false);mSeeAllPref.setVisible(false);}}// 计算应用的数量@VisibleForTestingvoid loadAllAppsCount() {// Show total number of installed apps as See all's summary.new InstalledAppCounter(mContext, InstalledAppCounter.IGNORE_INSTALL_REASON,mContext.getPackageManager()) {@Overrideprotected void onCountComplete(int num) {if (!mRecentApps.isEmpty()) {mSeeAllPref.setTitle(mContext.getResources().getQuantityString(R.plurals.see_all_apps_title,num, num));android.util.Log.d("xin.wang", "onCountComplete: -> AppsCount -> " + num);} else {mAllAppsInfoPref.setSummary(mContext.getString(R.string.apps_summary, num));}}}.execute();}@VisibleForTestingList<UsageStats> loadRecentApps() {final RecentAppStatsMixin recentAppStatsMixin = new RecentAppStatsMixin(mContext,SHOW_RECENT_APP_COUNT);recentAppStatsMixin.loadDisplayableRecentApps(SHOW_RECENT_APP_COUNT);return recentAppStatsMixin.mRecentApps;}private void initPreferences(PreferenceScreen screen) {mRecentAppsCategory = screen.findPreference(KEY_RECENT_APPS_CATEGORY);mGeneralCategory = screen.findPreference(KEY_GENERAL_CATEGORY);mAllAppsInfoPref = screen.findPreference(KEY_ALL_APP_INFO);mSeeAllPref = screen.findPreference(KEY_SEE_ALL);mRecentAppsCategory.setVisible(false);mGeneralCategory.setVisible(false);mAllAppsInfoPref.setVisible(false);mSeeAllPref.setVisible(false);}private void displayRecentApps() {if (mRecentAppsCategory != null) {final Map<String, Preference> existedAppPreferences = new ArrayMap<>();final int prefCount = mRecentAppsCategory.getPreferenceCount();android.util.Log.d("xin.wang", "<- prefCount -> : " + prefCount);for (int i = 0; i < prefCount; i++) {final Preference pref = mRecentAppsCategory.getPreference(i);final String key = pref.getKey();// android.util.Log.d("xin.wang", "for each key -> : " + key);if (!TextUtils.equals(key, KEY_SEE_ALL)) {existedAppPreferences.put(key, pref);}android.util.Log.d("xin.wang", "<- Map<String,Preference> -> " + existedAppPreferences);}int showAppsCount = 0;android.util.Log.d("xin.wang", "List<UsageStats> mRecentApps -> : " + mRecentApps);for (UsageStats stat : mRecentApps) {final String pkgName = stat.getPackageName();final ApplicationsState.AppEntry appEntry =mApplicationsState.getEntry(pkgName, mUserId);if (appEntry == null) {continue;}boolean rebindPref = true;Preference pref = existedAppPreferences.remove(pkgName);if (pref == null) {pref = new AppPreference(mContext);rebindPref = false;}android.util.Log.d("xin.wang", "pkgName -> : " + pkgName + "<- appEntry.label -> : " + appEntry.label + "<- pref -> " + pref);pref.setKey(pkgName);pref.setTitle(appEntry.label);pref.setIcon(Utils.getBadgedIcon(mContext, appEntry.info));pref.setSummary(StringUtil.formatRelativeTime(mContext,System.currentTimeMillis() - stat.getLastTimeUsed(), false,RelativeDateTimeFormatter.Style.SHORT));pref.setOrder(showAppsCount++);pref.setOnPreferenceClickListener(preference -> {AppInfoBase.startAppInfoFragment(AppInfoDashboardFragment.class,R.string.application_info_label, pkgName, appEntry.info.uid,mHost, 1001 /*RequestCode*/, getMetricsCategory());return true;});if (!rebindPref) {mRecentAppsCategory.addPreference(pref);}}// Remove unused preferences from pref category.for (Preference unusedPref : existedAppPreferences.values()) {mRecentAppsCategory.removePreference(unusedPref);}}}
}

进入超父类AppCounter.java

doInBackground方法进行计算总数量,该计算方法,通过遍历用户和应用双重遍历进行计算,所以算出来的数量double,所以在doInBackground(Void... params)中,只获取第一个用户,在进行遍历应用

/** Copyright (C) 2016 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.applications;import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.AsyncTask;
import android.os.UserHandle;
import android.os.UserManager;import java.util.List;public abstract class AppCounter extends AsyncTask<Void, Void, Integer> {protected final PackageManager mPm;protected final UserManager mUm;public AppCounter(Context context, PackageManager packageManager) {mPm = packageManager;mUm = (UserManager) context.getSystemService(Context.USER_SERVICE);}@Overrideprotected Integer doInBackground(Void... params) {//int count = 0;//int testNum = 0;//int testNum2 = 0;//android.util.Log.d("xin.wang", "doInBackground:UserInfo-> " + testNum);UserInfo user = mUm.getProfiles(UserHandle.myUserId()).get(0);final List<ApplicationInfo> list =mPm.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS| (user.isAdmin() ? PackageManager.MATCH_ANY_USER : 0),user.id);for (ApplicationInfo info : list) {//testNum2 ++;//android.util.Log.d("xin.wang", "doInBackground: ApplicationInfo -> " + testNum2);if (includeInCount(info)) {count++;//android.util.Log.d("xin.wang", "doInBackground: includeInCount -> " + count);}}/*for (UserInfo user : mUm.getProfiles(UserHandle.myUserId())) {testNum ++ ;android.util.Log.d("xin.wang", "doInBackground:UserInfo-> " + testNum);final List<ApplicationInfo> list =mPm.getInstalledApplicationsAsUser(PackageManager.GET_DISABLED_COMPONENTS| PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS| (user.isAdmin() ? PackageManager.MATCH_ANY_USER : 0),user.id);for (ApplicationInfo info : list) {testNum2 ++;android.util.Log.d("xin.wang", "doInBackground: ApplicationInfo -> " + testNum2);if (includeInCount(info)) {count++;android.util.Log.d("xin.wang", "doInBackground: includeInCount -> " + count);}}}*/return count;}@Overrideprotected void onPostExecute(Integer count) {onCountComplete(count);}void executeInForeground() {onPostExecute(doInBackground());}protected abstract void onCountComplete(int num);protected abstract boolean includeInCount(ApplicationInfo info);
}

4、进入所有应用

该界面的方法ManageApplications.java类来显示应用图标和名字

该类有两个内部类适配器

FilterSpinnerAdapter-> SettingsSpinnerAdapter的适配器

ApplicationsAdapter-> RecyclerView的适配器

createHeader()在该方法中创建头部SpinnerHeader,关闭头部的时候只显示一个FILTER_APPS_PERSONAL的应用

 @VisibleForTestingvoid createHeader() {final Activity activity = getActivity();final FrameLayout pinnedHeader = mRootView.findViewById(R.id.pinned_header);mSpinnerHeader = activity.getLayoutInflater().inflate(R.layout.manage_apps_filter_spinner, pinnedHeader, false);mFilterSpinner = mSpinnerHeader.findViewById(R.id.filter_spinner);mFilterAdapter = new FilterSpinnerAdapter(this);mFilterSpinner.setAdapter(mFilterAdapter);mFilterSpinner.setOnItemSelectedListener(this);mFilterSpinner.setVisibility(View.GONE);pinnedHeader.addView(mSpinnerHeader, 0);final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance();final int filterType = appFilterRegistry.getDefaultFilterType(mListType);android.util.Log.d("xin.wang", "createHeader:-> filterType -> " + mListType + "<- filterType -> " + filterType); //filterType = 4 -> FILTER_APPS_ALLandroid.util.Log.d("xin.wang", "createHeader:->mFilterOptions.size()-> " + mFilterAdapter.getCount());//mFilterAdapter.enableFilter(filterType);    //filterType = 4 -> FILTER_APPS_ALLif (mListType == LIST_TYPE_MAIN) {if (UserManager.get(getActivity()).getUserProfiles().size() > 1 && !mIsWorkOnly&& !mIsPersonalOnly) {mFilterAdapter.enableFilter(FILTER_APPS_PERSONAL);//mFilterAdapter.enableFilter(FILTER_APPS_WORK);}}if (mListType == LIST_TYPE_NOTIFICATION) {mFilterAdapter.enableFilter(FILTER_APPS_RECENT);mFilterAdapter.enableFilter(FILTER_APPS_FREQUENT);mFilterAdapter.enableFilter(FILTER_APPS_BLOCKED);mFilterAdapter.enableFilter(FILTER_APPS_ALL);}if (mListType == LIST_TYPE_HIGH_POWER) {mFilterAdapter.enableFilter(FILTER_APPS_POWER_ALLOWLIST_ALL);}setCompositeFilter();}
/** Copyright (C) 2006 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.applications.manageapplications;import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BLOCKED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_DISABLED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ENABLED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_FREQUENT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_INSTANT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_PERSONAL;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_ALLOWLIST;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_ALLOWLIST_ALL;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_RECENT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WORK;
import static com.android.settings.search.actionbar.SearchMenuController.MENU_SEARCH;import android.annotation.Nullable;
import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.app.usage.IUsageStatsManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.LoggingOnly;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.preference.PreferenceFrameLayout;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Filter;
import android.widget.FrameLayout;
import android.widget.SearchView;
import android.widget.Spinner;import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import com.android.internal.compat.IPlatformCompat;
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.Settings.GamesStorageActivity;
import com.android.settings.Settings.HighPowerApplicationsActivity;
import com.android.settings.Settings.ManageExternalSourcesActivity;
import com.android.settings.Settings.OverlaySettingsActivity;
import com.android.settings.Settings.StorageUseActivity;
import com.android.settings.Settings.UsageAccessSettingsActivity;
import com.android.settings.Settings.WriteSettingsActivity;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateManageExternalStorageBridge;
import com.android.settings.applications.AppStateMediaManagementAppsBridge;
import com.android.settings.applications.AppStateNotificationBridge;
import com.android.settings.applications.AppStateNotificationBridge.NotificationsSentState;
import com.android.settings.applications.AppStateOverlayBridge;
import com.android.settings.applications.AppStatePowerBridge;
import com.android.settings.applications.AppStateUsageBridge;
import com.android.settings.applications.AppStateUsageBridge.UsageState;
import com.android.settings.applications.AppStateWriteSettingsBridge;
import com.android.settings.applications.AppStorageSettings;
import com.android.settings.applications.UsageAccessDetails;
import com.android.settings.applications.appinfo.AlarmsAndRemindersDetails;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.appinfo.DrawOverlayDetails;
import com.android.settings.applications.appinfo.ExternalSourcesDetails;
import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
import com.android.settings.applications.appinfo.MediaManagementAppsDetails;
import com.android.settings.applications.appinfo.WriteSettingsDetails;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.fuelgauge.HighPowerDetail;
import com.android.settings.notification.ConfigureNotificationSettings;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.notification.app.AppNotificationSettings;
import com.android.settings.widget.LoadingViewController;
import com.android.settings.wifi.AppStateChangeWifiStateBridge;
import com.android.settings.wifi.ChangeWifiStateDetails;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
import com.android.settingslib.applications.ApplicationsState.VolumeFilter;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.settingsspinner.SettingsSpinnerAdapter;import com.google.android.material.appbar.AppBarLayout;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.HashSet;/*** Activity to pick an application that will be used to display installation information and* options to uninstall/delete user data for system applications. This activity* can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE* intent.*/
public class ManageApplications extends InstrumentedFragmentimplements View.OnClickListener, OnItemSelectedListener, SearchView.OnQueryTextListener,MenuItem.OnActionExpandListener {static final String TAG = "ManageApplications";static final boolean DEBUG = Build.IS_DEBUGGABLE;// Intent extras.public static final String EXTRA_CLASSNAME = "classname";// Used for storage only.public static final String EXTRA_VOLUME_UUID = "volumeUuid";public static final String EXTRA_VOLUME_NAME = "volumeName";public static final String EXTRA_STORAGE_TYPE = "storageType";public static final String EXTRA_WORK_ID = "workId";private static final String EXTRA_SORT_ORDER = "sortOrder";private static final String EXTRA_SHOW_SYSTEM = "showSystem";private static final String EXTRA_HAS_ENTRIES = "hasEntries";private static final String EXTRA_HAS_BRIDGE = "hasBridge";private static final String EXTRA_FILTER_TYPE = "filterType";@VisibleForTestingstatic final String EXTRA_EXPAND_SEARCH_VIEW = "expand_search_view";// attributes used as keys when passing values to AppInfoDashboardFragment activitypublic static final String APP_CHG = "chg";// constant value that can be used to check return code from sub activity.private static final int INSTALLED_APP_DETAILS = 1;private static final int ADVANCED_SETTINGS = 2;public static final int SIZE_TOTAL = 0;public static final int SIZE_INTERNAL = 1;public static final int SIZE_EXTERNAL = 2;// Storage types. Used to determine what the extra item in the list of preferences is.public static final int STORAGE_TYPE_DEFAULT = 0; // Show all apps that are not categorized.public static final int STORAGE_TYPE_LEGACY = 1;  // Show apps even if they can be categorized./*** Intents with action {@code android.settings.MANAGE_APP_OVERLAY_PERMISSION}* and data URI scheme {@code package} don't go to the app-specific screen for managing the* permission anymore. Instead, they redirect to this screen for managing all the apps that have* requested such permission.*/@ChangeId@LoggingOnlyprivate static final long CHANGE_RESTRICT_SAW_INTENT = 135920175L;// sort order@VisibleForTestingint mSortOrder = R.id.sort_order_alpha;// whether showing system apps.private boolean mShowSystem;private ApplicationsState mApplicationsState;public int mListType;private AppFilterItem mFilter;private ApplicationsAdapter mApplications;private View mLoadingContainer;private SearchView mSearchView;// Size resource used for packages whose size computation failed for some reasonCharSequence mInvalidSizeStr;private String mCurrentPkgName;private int mCurrentUid;private Menu mOptionsMenu;public static final int LIST_TYPE_MAIN = 0;public static final int LIST_TYPE_NOTIFICATION = 1;public static final int LIST_TYPE_STORAGE = 3;public static final int LIST_TYPE_USAGE_ACCESS = 4;public static final int LIST_TYPE_HIGH_POWER = 5;public static final int LIST_TYPE_OVERLAY = 6;public static final int LIST_TYPE_WRITE_SETTINGS = 7;public static final int LIST_TYPE_MANAGE_SOURCES = 8;public static final int LIST_TYPE_GAMES = 9;public static final int LIST_TYPE_WIFI_ACCESS = 10;public static final int LIST_MANAGE_EXTERNAL_STORAGE = 11;public static final int LIST_TYPE_ALARMS_AND_REMINDERS = 12;public static final int LIST_TYPE_MEDIA_MANAGEMENT_APPS = 13;// List types that should show instant apps.public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(LIST_TYPE_MAIN,LIST_TYPE_STORAGE));@VisibleForTestingView mSpinnerHeader;@VisibleForTestingFilterSpinnerAdapter mFilterAdapter;@VisibleForTestingRecyclerView mRecyclerView;// Whether or not search view is expanded.@VisibleForTestingboolean mExpandSearch;private View mRootView;private Spinner mFilterSpinner;private IUsageStatsManager mUsageStatsManager;private UserManager mUserManager;private NotificationBackend mNotificationBackend;private ResetAppsHelper mResetAppsHelper;private String mVolumeUuid;private int mStorageType;private boolean mIsWorkOnly;private int mWorkUserId;private boolean mIsPersonalOnly;private View mEmptyView;private int mFilterType;private AppBarLayout mAppBarLayout;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setHasOptionsMenu(true);final Activity activity = getActivity();mUserManager = activity.getSystemService(UserManager.class);mApplicationsState = ApplicationsState.getInstance(activity.getApplication());Intent intent = activity.getIntent();Bundle args = getArguments();int screenTitle = intent.getIntExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.all_apps);String className = args != null ? args.getString(EXTRA_CLASSNAME) : null;if (className == null) {className = intent.getComponent().getClassName();}if (className.equals(StorageUseActivity.class.getName())) {if (args != null && args.containsKey(EXTRA_VOLUME_UUID)) {mVolumeUuid = args.getString(EXTRA_VOLUME_UUID);mStorageType = args.getInt(EXTRA_STORAGE_TYPE, STORAGE_TYPE_DEFAULT);mListType = LIST_TYPE_STORAGE;} else {// No volume selected, display a normal list, sorted by size.mListType = LIST_TYPE_MAIN;}mSortOrder = R.id.sort_order_size;} else if (className.equals(UsageAccessSettingsActivity.class.getName())) {mListType = LIST_TYPE_USAGE_ACCESS;screenTitle = R.string.usage_access;} else if (className.equals(HighPowerApplicationsActivity.class.getName())) {mListType = LIST_TYPE_HIGH_POWER;// Default to showing system.mShowSystem = true;screenTitle = R.string.high_power_apps;} else if (className.equals(OverlaySettingsActivity.class.getName())) {mListType = LIST_TYPE_OVERLAY;screenTitle = R.string.system_alert_window_settings;reportIfRestrictedSawIntent(intent);} else if (className.equals(WriteSettingsActivity.class.getName())) {mListType = LIST_TYPE_WRITE_SETTINGS;screenTitle = R.string.write_settings;} else if (className.equals(ManageExternalSourcesActivity.class.getName())) {mListType = LIST_TYPE_MANAGE_SOURCES;screenTitle = R.string.install_other_apps;} else if (className.equals(GamesStorageActivity.class.getName())) {mListType = LIST_TYPE_GAMES;mSortOrder = R.id.sort_order_size;} else if (className.equals(Settings.ChangeWifiStateActivity.class.getName())) {mListType = LIST_TYPE_WIFI_ACCESS;screenTitle = R.string.change_wifi_state_title;} else if (className.equals(Settings.ManageExternalStorageActivity.class.getName())) {mListType = LIST_MANAGE_EXTERNAL_STORAGE;screenTitle = R.string.manage_external_storage_title;}  else if (className.equals(Settings.MediaManagementAppsActivity.class.getName())) {mListType = LIST_TYPE_MEDIA_MANAGEMENT_APPS;screenTitle = R.string.media_management_apps_title;} else if (className.equals(Settings.AlarmsAndRemindersActivity.class.getName())) {mListType = LIST_TYPE_ALARMS_AND_REMINDERS;screenTitle = R.string.alarms_and_reminders_title;} else if (className.equals(Settings.NotificationAppListActivity.class.getName())) {mListType = LIST_TYPE_NOTIFICATION;mUsageStatsManager = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(Context.USAGE_STATS_SERVICE));mNotificationBackend = new NotificationBackend();mSortOrder = R.id.sort_order_recent_notification;screenTitle = R.string.app_notifications_title;} else {if (screenTitle == -1) {screenTitle = R.string.all_apps;}mListType = LIST_TYPE_MAIN;}final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance();mFilter = appFilterRegistry.get(appFilterRegistry.getDefaultFilterType(mListType));mIsPersonalOnly = args != null ? args.getInt(ProfileSelectFragment.EXTRA_PROFILE)== ProfileSelectFragment.ProfileType.PERSONAL : false;mIsWorkOnly = args != null ? args.getInt(ProfileSelectFragment.EXTRA_PROFILE)== ProfileSelectFragment.ProfileType.WORK : false;mWorkUserId = args != null ? args.getInt(EXTRA_WORK_ID) : UserHandle.myUserId();if (mIsWorkOnly && mWorkUserId == UserHandle.myUserId()) {mWorkUserId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId());}mExpandSearch = activity.getIntent().getBooleanExtra(EXTRA_EXPAND_SEARCH_VIEW, false);if (savedInstanceState != null) {mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder);mShowSystem = savedInstanceState.getBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);mFilterType =savedInstanceState.getInt(EXTRA_FILTER_TYPE, AppFilterRegistry.FILTER_APPS_ALL);mExpandSearch = savedInstanceState.getBoolean(EXTRA_EXPAND_SEARCH_VIEW);}mInvalidSizeStr = activity.getText(R.string.invalid_size_value);mResetAppsHelper = new ResetAppsHelper(activity);if (screenTitle > 0) {activity.setTitle(screenTitle);}}private void reportIfRestrictedSawIntent(Intent intent) {try {Uri data = intent.getData();if (data == null || !TextUtils.equals("package", data.getScheme())) {// Not a restricted intentreturn;}IBinder activityToken = getActivity().getActivityToken();int callingUid = ActivityManager.getService().getLaunchedFromUid(activityToken);if (callingUid == -1) {Log.w(TAG, "Error obtaining calling uid");return;}IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));if (platformCompat == null) {Log.w(TAG, "Error obtaining IPlatformCompat service");return;}platformCompat.reportChangeByUid(CHANGE_RESTRICT_SAW_INTENT, callingUid);} catch (RemoteException e) {Log.w(TAG, "Error reporting SAW intent restriction", e);}}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {if (mListType == LIST_TYPE_OVERLAY && !Utils.isSystemAlertWindowEnabled(getContext())) {mRootView = inflater.inflate(R.layout.manage_applications_apps_unsupported, null);setHasOptionsMenu(false);return mRootView;}mRootView = inflater.inflate(R.layout.manage_applications_apps, null);mLoadingContainer = mRootView.findViewById(R.id.loading_container);mEmptyView = mRootView.findViewById(android.R.id.empty);mRecyclerView = mRootView.findViewById(R.id.apps_list);mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter,savedInstanceState);if (savedInstanceState != null) {mApplications.mHasReceivedLoadEntries =savedInstanceState.getBoolean(EXTRA_HAS_ENTRIES, false);mApplications.mHasReceivedBridgeCallback =savedInstanceState.getBoolean(EXTRA_HAS_BRIDGE, false);}mRecyclerView.setItemAnimator(null);mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false /* reverseLayout */));mRecyclerView.setAdapter(mApplications);android.util.Log.d("xin.wang", "onCreateView:mRecyclerView.setAdapter-> " + Thread.currentThread().getName());// We have to do this now because PreferenceFrameLayout looks at it// only when the view is added.if (container instanceof PreferenceFrameLayout) {((PreferenceFrameLayout.LayoutParams) mRootView.getLayoutParams()).removeBorders = true;}createHeader();mResetAppsHelper.onRestoreInstanceState(savedInstanceState);mAppBarLayout = getActivity().findViewById(R.id.app_bar);disableToolBarScrollableBehavior();return mRootView;}@VisibleForTestingvoid createHeader() {final Activity activity = getActivity();final FrameLayout pinnedHeader = mRootView.findViewById(R.id.pinned_header);mSpinnerHeader = activity.getLayoutInflater().inflate(R.layout.manage_apps_filter_spinner, pinnedHeader, false);mFilterSpinner = mSpinnerHeader.findViewById(R.id.filter_spinner);mFilterAdapter = new FilterSpinnerAdapter(this);mFilterSpinner.setAdapter(mFilterAdapter);mFilterSpinner.setOnItemSelectedListener(this);mFilterSpinner.setVisibility(View.GONE);pinnedHeader.addView(mSpinnerHeader, 0);final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance();final int filterType = appFilterRegistry.getDefaultFilterType(mListType);android.util.Log.d("xin.wang", "createHeader:-> filterType -> " + mListType + "<- filterType -> " + filterType); //filterType = 4 -> FILTER_APPS_ALLandroid.util.Log.d("xin.wang", "createHeader:->mFilterOptions.size()-> " + mFilterAdapter.getCount());//mFilterAdapter.enableFilter(filterType);    //filterType = 4 -> FILTER_APPS_ALLif (mListType == LIST_TYPE_MAIN) {if (UserManager.get(getActivity()).getUserProfiles().size() > 1 && !mIsWorkOnly&& !mIsPersonalOnly) {mFilterAdapter.enableFilter(FILTER_APPS_PERSONAL);//mFilterAdapter.enableFilter(FILTER_APPS_WORK);}}if (mListType == LIST_TYPE_NOTIFICATION) {mFilterAdapter.enableFilter(FILTER_APPS_RECENT);mFilterAdapter.enableFilter(FILTER_APPS_FREQUENT);mFilterAdapter.enableFilter(FILTER_APPS_BLOCKED);mFilterAdapter.enableFilter(FILTER_APPS_ALL);}if (mListType == LIST_TYPE_HIGH_POWER) {mFilterAdapter.enableFilter(FILTER_APPS_POWER_ALLOWLIST_ALL);}setCompositeFilter();}@VisibleForTesting@Nullablestatic AppFilter getCompositeFilter(int listType, int storageType, String volumeUuid) {AppFilter filter = new VolumeFilter(volumeUuid);if (listType == LIST_TYPE_STORAGE) {if (storageType == STORAGE_TYPE_DEFAULT) {filter = new CompoundFilter(ApplicationsState.FILTER_APPS_EXCEPT_GAMES, filter);}return filter;}if (listType == LIST_TYPE_GAMES) {return new CompoundFilter(ApplicationsState.FILTER_GAMES, filter);}return null;}@Overridepublic int getMetricsCategory() {switch (mListType) {case LIST_TYPE_MAIN:return SettingsEnums.MANAGE_APPLICATIONS;case LIST_TYPE_NOTIFICATION:return SettingsEnums.MANAGE_APPLICATIONS_NOTIFICATIONS;case LIST_TYPE_STORAGE:return SettingsEnums.APPLICATIONS_STORAGE_APPS;case LIST_TYPE_GAMES:return SettingsEnums.APPLICATIONS_STORAGE_GAMES;case LIST_TYPE_USAGE_ACCESS:return SettingsEnums.USAGE_ACCESS;case LIST_TYPE_HIGH_POWER:return SettingsEnums.APPLICATIONS_HIGH_POWER_APPS;case LIST_TYPE_OVERLAY:return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;case LIST_TYPE_WRITE_SETTINGS:return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;case LIST_TYPE_MANAGE_SOURCES:return SettingsEnums.MANAGE_EXTERNAL_SOURCES;case LIST_TYPE_WIFI_ACCESS:return SettingsEnums.CONFIGURE_WIFI;case LIST_MANAGE_EXTERNAL_STORAGE:return SettingsEnums.MANAGE_EXTERNAL_STORAGE;case LIST_TYPE_ALARMS_AND_REMINDERS:return SettingsEnums.ALARMS_AND_REMINDERS;case LIST_TYPE_MEDIA_MANAGEMENT_APPS:return SettingsEnums.MEDIA_MANAGEMENT_APPS;default:return SettingsEnums.PAGE_UNKNOWN;}}@Overridepublic void onStart() {super.onStart();updateView();if (mApplications != null) {mApplications.resume(mSortOrder);mApplications.updateLoading();}}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);mResetAppsHelper.onSaveInstanceState(outState);outState.putInt(EXTRA_SORT_ORDER, mSortOrder);outState.putInt(EXTRA_FILTER_TYPE, mFilter.getFilterType());outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);//add bug 1702049:NullPointerException on a null object referenceif (mApplications != null) {outState.putBoolean(EXTRA_HAS_ENTRIES, mApplications.mHasReceivedLoadEntries);outState.putBoolean(EXTRA_HAS_BRIDGE, mApplications.mHasReceivedBridgeCallback);if (mSearchView != null) {outState.putBoolean(EXTRA_EXPAND_SEARCH_VIEW, !mSearchView.isIconified());}mApplications.onSaveInstanceState(outState);}}@Overridepublic void onStop() {super.onStop();if (mApplications != null) {mApplications.pause();}mResetAppsHelper.stop();}@Overridepublic void onDestroyView() {super.onDestroyView();if (mApplications != null) {mApplications.release();}mRootView = null;}@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {if (mListType == LIST_TYPE_NOTIFICATION) {mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid);} else if (mListType == LIST_TYPE_HIGH_POWER || mListType == LIST_TYPE_OVERLAY|| mListType == LIST_TYPE_WRITE_SETTINGS) {mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid);} else {mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid));}}}private void setCompositeFilter() {AppFilter compositeFilter = getCompositeFilter(mListType, mStorageType, mVolumeUuid);if (compositeFilter == null) {compositeFilter = mFilter.getFilter();}if (mIsWorkOnly) {compositeFilter = new CompoundFilter(compositeFilter, ApplicationsState.FILTER_WORK);}if (mIsPersonalOnly) {compositeFilter = new CompoundFilter(compositeFilter,ApplicationsState.FILTER_PERSONAL);}mApplications.setCompositeFilter(compositeFilter);}// utility method used to start sub activityprivate void startApplicationDetailsActivity() {switch (mListType) {case LIST_TYPE_NOTIFICATION:startAppInfoFragment(AppNotificationSettings.class, R.string.notifications_title);break;case LIST_TYPE_USAGE_ACCESS:startAppInfoFragment(UsageAccessDetails.class, R.string.usage_access);break;case LIST_TYPE_STORAGE:startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings);break;case LIST_TYPE_HIGH_POWER:HighPowerDetail.show(this, mCurrentUid, mCurrentPkgName, INSTALLED_APP_DETAILS);break;case LIST_TYPE_OVERLAY:startAppInfoFragment(DrawOverlayDetails.class, R.string.overlay_settings);break;case LIST_TYPE_WRITE_SETTINGS:startAppInfoFragment(WriteSettingsDetails.class, R.string.write_system_settings);break;case LIST_TYPE_MANAGE_SOURCES:startAppInfoFragment(ExternalSourcesDetails.class, R.string.install_other_apps);break;case LIST_TYPE_GAMES:startAppInfoFragment(AppStorageSettings.class, R.string.game_storage_settings);break;case LIST_TYPE_WIFI_ACCESS:startAppInfoFragment(ChangeWifiStateDetails.class,R.string.change_wifi_state_title);break;case LIST_MANAGE_EXTERNAL_STORAGE:startAppInfoFragment(ManageExternalStorageDetails.class,R.string.manage_external_storage_title);break;case LIST_TYPE_ALARMS_AND_REMINDERS:startAppInfoFragment(AlarmsAndRemindersDetails.class,R.string.alarms_and_reminders_label);break;case LIST_TYPE_MEDIA_MANAGEMENT_APPS:startAppInfoFragment(MediaManagementAppsDetails.class,R.string.media_management_apps_title);break;// TODO: Figure out if there is a way where we can spin up the profile's settings// process ahead of time, to avoid a long load of data when user clicks on a managed// app. Maybe when they load the list of apps that contains managed profile apps.default:startAppInfoFragment(AppInfoDashboardFragment.class, R.string.application_info_label);break;}}private void startAppInfoFragment(Class<?> fragment, int titleRes) {AppInfoBase.startAppInfoFragment(fragment, titleRes, mCurrentPkgName, mCurrentUid, this,INSTALLED_APP_DETAILS, getMetricsCategory());}@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {final Activity activity = getActivity();if (activity == null) {return;}mOptionsMenu = menu;inflater.inflate(R.menu.manage_apps, menu);final MenuItem searchMenuItem = menu.findItem(R.id.search_app_list_menu);if (searchMenuItem != null) {searchMenuItem.setOnActionExpandListener(this);mSearchView = (SearchView) searchMenuItem.getActionView();mSearchView.setQueryHint(getText(R.string.search_settings));mSearchView.setOnQueryTextListener(this);if (mExpandSearch) {searchMenuItem.expandActionView();}}updateOptionsMenu();}@Overridepublic boolean onMenuItemActionExpand(MenuItem item) {// To prevent a large space on tool bar.mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);// To prevent user can expand the collapsing tool bar view.ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);return true;}@Overridepublic boolean onMenuItemActionCollapse(MenuItem item) {// We keep the collapsed status after user cancel the search function.mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);ViewCompat.setNestedScrollingEnabled(mRecyclerView, true);return true;}@Overridepublic void onPrepareOptionsMenu(Menu menu) {updateOptionsMenu();}@Overridepublic void onDestroyOptionsMenu() {mOptionsMenu = null;}@StringResint getHelpResource() {switch (mListType) {case LIST_TYPE_NOTIFICATION:return R.string.help_uri_notifications;case LIST_TYPE_USAGE_ACCESS:return R.string.help_url_usage_access;case LIST_TYPE_STORAGE:return R.string.help_uri_apps_storage;case LIST_TYPE_HIGH_POWER:return R.string.help_uri_apps_high_power;case LIST_TYPE_OVERLAY:return R.string.help_uri_apps_overlay;case LIST_TYPE_WRITE_SETTINGS:return R.string.help_uri_apps_write_settings;case LIST_TYPE_MANAGE_SOURCES:return R.string.help_uri_apps_manage_sources;case LIST_TYPE_GAMES:return R.string.help_uri_apps_overlay;case LIST_TYPE_WIFI_ACCESS:return R.string.help_uri_apps_wifi_access;case LIST_MANAGE_EXTERNAL_STORAGE:return R.string.help_uri_manage_external_storage;case LIST_TYPE_ALARMS_AND_REMINDERS:return R.string.help_uri_alarms_and_reminders;case LIST_TYPE_MEDIA_MANAGEMENT_APPS:return R.string.help_uri_media_management_apps;default:case LIST_TYPE_MAIN:return R.string.help_uri_apps;}}void updateOptionsMenu() {if (mOptionsMenu == null) {return;}mOptionsMenu.findItem(R.id.advanced).setVisible(false);mOptionsMenu.findItem(R.id.sort_order_alpha).setVisible(mListType == LIST_TYPE_STORAGE&& mSortOrder != R.id.sort_order_alpha);mOptionsMenu.findItem(R.id.sort_order_size).setVisible(mListType == LIST_TYPE_STORAGE&& mSortOrder != R.id.sort_order_size);mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem&& mListType != LIST_TYPE_HIGH_POWER && wheatherShowSystemOption());mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem&& mListType != LIST_TYPE_HIGH_POWER && wheatherShowSystemOption());mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN);// Hide notification menu items, because sorting happens when filteringmOptionsMenu.findItem(R.id.sort_order_recent_notification).setVisible(false);mOptionsMenu.findItem(R.id.sort_order_frequent_notification).setVisible(false);final MenuItem searchItem = mOptionsMenu.findItem(MENU_SEARCH);if (searchItem != null) {searchItem.setVisible(false);}}//hide the optionsmenu of hide-system and show-system in the work interfaceprivate boolean wheatherShowSystemOption() {boolean hasManageProfile = false;List<UserInfo> users = mUserManager.getUsers();android.util.Log.d("xin.wang", "wheatherShowSystemOption: " + users + "<- users.size->" + users.size());for(UserInfo user : users){if (user.isManagedProfile()) {hasManageProfile = true;break;}}if (mIsWorkOnly && !mIsPersonalOnly) {if (!hasManageProfile) {return false;}}return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {int menuId = item.getItemId();int i = item.getItemId();if (i == R.id.sort_order_alpha || i == R.id.sort_order_size) {if (mApplications != null) {mApplications.rebuild(menuId);}} else if (i == R.id.show_system || i == R.id.hide_system) {mShowSystem = !mShowSystem;mApplications.rebuild();} else if (i == R.id.reset_app_preferences) {mResetAppsHelper.buildResetDialog();return true;} else if (i == R.id.advanced) {if (mListType == LIST_TYPE_NOTIFICATION) {new SubSettingLauncher(getContext()).setDestination(ConfigureNotificationSettings.class.getName()).setTitleRes(R.string.configure_notification_settings).setSourceMetricsCategory(getMetricsCategory()).setResultListener(this, ADVANCED_SETTINGS).launch();} else {Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS);startActivityForResult(intent, ADVANCED_SETTINGS);}return true;} else {// Handle the home buttonreturn false;}updateOptionsMenu();return true;}@Overridepublic void onClick(View view) {if (mApplications == null) {return;}final int position = mRecyclerView.getChildAdapterPosition(view);if (position == RecyclerView.NO_POSITION) {Log.w(TAG, "Cannot find position for child, skipping onClick handling");return;}if (mApplications.getApplicationCount() > position) {ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);mCurrentPkgName = entry.info.packageName;mCurrentUid = entry.info.uid;startApplicationDetailsActivity();// We disable the scrolling ability in onMenuItemActionCollapse, we should recover it// if user selects any app item.ViewCompat.setNestedScrollingEnabled(mRecyclerView, true);}}@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {mFilter = mFilterAdapter.getFilter(position);setCompositeFilter();mApplications.setFilter(mFilter);if (DEBUG) {Log.d(TAG, "Selecting filter " + getContext().getText(mFilter.getTitle()));}}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}@Overridepublic boolean onQueryTextSubmit(String query) {return false;}@Overridepublic boolean onQueryTextChange(String newText) {mApplications.filterSearch(newText);return false;}public void updateView() {updateOptionsMenu();final Activity host = getActivity();if (host != null) {host.invalidateOptionsMenu();}}public void setHasDisabled(boolean hasDisabledApps) {if (mListType != LIST_TYPE_MAIN) {return;}mFilterAdapter.setFilterEnabled(FILTER_APPS_ENABLED, hasDisabledApps);mFilterAdapter.setFilterEnabled(FILTER_APPS_DISABLED, hasDisabledApps);}public void setHasInstant(boolean haveInstantApps) {if (LIST_TYPES_WITH_INSTANT.contains(mListType)) {mFilterAdapter.setFilterEnabled(FILTER_APPS_INSTANT, haveInstantApps);}}private void disableToolBarScrollableBehavior() {final CoordinatorLayout.LayoutParams params =(CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {@Overridepublic boolean canDrag(@NonNull AppBarLayout appBarLayout) {return false;}});params.setBehavior(behavior);}static class FilterSpinnerAdapter extends SettingsSpinnerAdapter<CharSequence> {private final ManageApplications mManageApplications;private final Context mContext;// Use ArrayAdapter for view logic, but have our own list for managing// the options available.private final ArrayList<AppFilterItem> mFilterOptions = new ArrayList<>();public FilterSpinnerAdapter(ManageApplications manageApplications) {super(manageApplications.getContext());mContext = manageApplications.getContext();mManageApplications = manageApplications;}public AppFilterItem getFilter(int position) {return mFilterOptions.get(position);}public void setFilterEnabled(@AppFilterRegistry.FilterType int filter, boolean enabled) {if (enabled) {enableFilter(filter);} else {disableFilter(filter);}}public void enableFilter(@AppFilterRegistry.FilterType int filterType) {final AppFilterItem filter = AppFilterRegistry.getInstance().get(filterType);if (mFilterOptions.contains(filter)) {return;}if (DEBUG) {Log.d(TAG, "Enabling filter " + mContext.getText(filter.getTitle()));}mFilterOptions.add(filter);Collections.sort(mFilterOptions);updateFilterView(mFilterOptions.size() > 1);notifyDataSetChanged();if (mFilterOptions.size() == 1) {if (DEBUG) {Log.d(TAG, "Auto selecting filter " + filter + " " + mContext.getText(filter.getTitle()));}mManageApplications.mFilterSpinner.setSelection(0);mManageApplications.onItemSelected(null, null, 0, 0);}if (mFilterOptions.size() > 1) {final AppFilterItem previousFilter = AppFilterRegistry.getInstance().get(mManageApplications.mFilterType);final int index = mFilterOptions.indexOf(previousFilter);if (index != -1) {android.util.Log.d("xin.wang", "enableFilter: previousFilter -> " + previousFilter + "<- index -> " + index);mManageApplications.mFilterSpinner.setSelection(index);mManageApplications.onItemSelected(null, null, index, 0);}}}public void disableFilter(@AppFilterRegistry.FilterType int filterType) {final AppFilterItem filter = AppFilterRegistry.getInstance().get(filterType);if (!mFilterOptions.remove(filter)) {return;}if (DEBUG) {Log.d(TAG, "Disabling filter " + filter + " " + mContext.getText(filter.getTitle()));}Collections.sort(mFilterOptions);updateFilterView(mFilterOptions.size() > 1);notifyDataSetChanged();if (mManageApplications.mFilter == filter) {if (mFilterOptions.size() > 0) {if (DEBUG) {Log.d(TAG, "Auto selecting filter " + mFilterOptions.get(0)+ mContext.getText(mFilterOptions.get(0).getTitle()));}android.util.Log.d("xin.wang", "disableFilter: Auto selecting filter -> " + mContext.getText(mFilterOptions.get(0).getTitle()));mManageApplications.mFilterSpinner.setSelection(0);mManageApplications.onItemSelected(null, null, 0, 0);}}}@Overridepublic int getCount() {android.util.Log.d("xin.wang", "getCount: mFilterOptions.size()->" + mFilterOptions.size());return mFilterOptions.size();}@Overridepublic CharSequence getItem(int position) {return mContext.getText(mFilterOptions.get(position).getTitle());}@VisibleForTestingvoid updateFilterView(boolean hasFilter) {// If we need to add a floating filter in this screen, we should have an extra top// padding for putting floating filter view. Otherwise, the content of list will be// overlapped by floating filter.if (hasFilter) {mManageApplications.mSpinnerHeader.setVisibility(View.VISIBLE);} else {mManageApplications.mSpinnerHeader.setVisibility(View.GONE);}}}static class ApplicationsAdapter extends RecyclerView.Adapter<ApplicationViewHolder>implements ApplicationsState.Callbacks, AppStateBaseBridge.Callback {private static final String STATE_LAST_SCROLL_INDEX = "state_last_scroll_index";private static final int VIEW_TYPE_APP = 0;private static final int VIEW_TYPE_EXTRA_VIEW = 1;private final ApplicationsState mState;private final ApplicationsState.Session mSession;private final ManageApplications mManageApplications;private final Context mContext;private final AppStateBaseBridge mExtraInfoBridge;private final LoadingViewController mLoadingViewController;private final IconDrawableFactory mIconDrawableFactory;private AppFilterItem mAppFilter;private ArrayList<ApplicationsState.AppEntry> mEntries;private ArrayList<ApplicationsState.AppEntry> mOriginalEntries;private boolean mResumed;private int mLastSortMode = -1;private int mWhichSize = SIZE_TOTAL;private AppFilter mCompositeFilter;private boolean mHasReceivedLoadEntries;private boolean mHasReceivedBridgeCallback;private SearchFilter mSearchFilter;private PowerAllowlistBackend mBackend;private HashSet<String> mSupportAppClone;// This is to remember and restore the last scroll position when this// fragment is paused. We need this special handling because app entries are added gradually// when we rebuild the list after the user made some changes, like uninstalling an app.private int mLastIndex = -1;@VisibleForTestingOnScrollListener mOnScrollListener;private RecyclerView mRecyclerView;public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications,AppFilterItem appFilter, Bundle savedInstanceState) {setHasStableIds(true);mState = state;mSession = state.newSession(this);mManageApplications = manageApplications;mLoadingViewController = new LoadingViewController(mManageApplications.mLoadingContainer,mManageApplications.mRecyclerView,mManageApplications.mEmptyView);mContext = manageApplications.getActivity();mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);mAppFilter = appFilter;mBackend = PowerAllowlistBackend.getInstance(mContext);String[] supportApps = mContext.getResources().getStringArray(com.unisoc.internal.R.array.support_app_clone);mSupportAppClone = new HashSet<String>(Arrays.asList(supportApps));android.util.Log.d("xin.wang", "ApplicationsAdapter -> mSupportAppClone -> : " + mSupportAppClone);if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {mExtraInfoBridge = new AppStateNotificationBridge(mContext, mState, this,manageApplications.mUsageStatsManager,manageApplications.mUserManager,manageApplications.mNotificationBackend);} else if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) {mExtraInfoBridge = new AppStateUsageBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_HIGH_POWER) {mBackend.refreshList();mExtraInfoBridge = new AppStatePowerBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_OVERLAY) {mExtraInfoBridge = new AppStateOverlayBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_WRITE_SETTINGS) {mExtraInfoBridge = new AppStateWriteSettingsBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_MANAGE_SOURCES) {mExtraInfoBridge = new AppStateInstallAppsBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_WIFI_ACCESS) {mExtraInfoBridge = new AppStateChangeWifiStateBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_MANAGE_EXTERNAL_STORAGE) {mExtraInfoBridge = new AppStateManageExternalStorageBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_ALARMS_AND_REMINDERS) {mExtraInfoBridge = new AppStateAlarmsAndRemindersBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_MEDIA_MANAGEMENT_APPS) {mExtraInfoBridge = new AppStateMediaManagementAppsBridge(mContext, mState, this);} else {mExtraInfoBridge = null;}if (savedInstanceState != null) {mLastIndex = savedInstanceState.getInt(STATE_LAST_SCROLL_INDEX);}}@Overridepublic void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {super.onAttachedToRecyclerView(recyclerView);mRecyclerView = recyclerView;mOnScrollListener = new OnScrollListener(this);mRecyclerView.addOnScrollListener(mOnScrollListener);}@Overridepublic void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {super.onDetachedFromRecyclerView(recyclerView);mRecyclerView.removeOnScrollListener(mOnScrollListener);mOnScrollListener = null;mRecyclerView = null;}public void setCompositeFilter(AppFilter compositeFilter) {mCompositeFilter = compositeFilter;rebuild();}public void setFilter(AppFilterItem appFilter) {mAppFilter = appFilter;// Notification filters require resorting the listif (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {if (FILTER_APPS_FREQUENT == appFilter.getFilterType()) {rebuild(R.id.sort_order_frequent_notification);} else if (FILTER_APPS_RECENT == appFilter.getFilterType()) {rebuild(R.id.sort_order_recent_notification);} else if (FILTER_APPS_BLOCKED == appFilter.getFilterType()) {rebuild(R.id.sort_order_alpha);} else {rebuild(R.id.sort_order_alpha);}} else {rebuild();}}public void resume(int sort) {if (DEBUG) Log.i(TAG, "Resume!  mResumed=" + mResumed);if (!mResumed) {mResumed = true;mSession.onResume();mLastSortMode = sort;if (mExtraInfoBridge != null) {mExtraInfoBridge.resume();}rebuild();} else {rebuild(sort);}}public void pause() {if (mResumed) {mResumed = false;mSession.onPause();if (mExtraInfoBridge != null) {mExtraInfoBridge.pause();}}}public void onSaveInstanceState(Bundle outState) {// Record the current scroll position before pausing.final LinearLayoutManager layoutManager =(LinearLayoutManager) mManageApplications.mRecyclerView.getLayoutManager();outState.putInt(STATE_LAST_SCROLL_INDEX, layoutManager.findFirstVisibleItemPosition());}public void release() {mSession.onDestroy();if (mExtraInfoBridge != null) {mExtraInfoBridge.release();}}public void rebuild(int sort) {if (sort == mLastSortMode) {return;}mManageApplications.mSortOrder = sort;mLastSortMode = sort;rebuild();}@Overridepublic ApplicationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {final View view;if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {view = ApplicationViewHolder.newView(parent, true /* twoTarget */);} else {view = ApplicationViewHolder.newView(parent, false /* twoTarget */);}return new ApplicationViewHolder(view);}@Overridepublic int getItemViewType(int position) {return VIEW_TYPE_APP;}public void rebuild() {if (!mHasReceivedLoadEntries|| (mExtraInfoBridge != null && !mHasReceivedBridgeCallback)) {// Don't rebuild the list until all the app entries are loaded.if (DEBUG) {Log.d(TAG, "Not rebuilding until all the app entries loaded."+ " !mHasReceivedLoadEntries=" + !mHasReceivedLoadEntries+ " !mExtraInfoBridgeNull=" + (mExtraInfoBridge != null)+ " !mHasReceivedBridgeCallback=" + !mHasReceivedBridgeCallback);}return;}ApplicationsState.AppFilter filterObj;Comparator<AppEntry> comparatorObj;boolean emulated = Environment.isExternalStorageEmulated();if (emulated) {mWhichSize = SIZE_TOTAL;} else {mWhichSize = SIZE_INTERNAL;}filterObj = mAppFilter.getFilter();if (mCompositeFilter != null) {filterObj = new CompoundFilter(filterObj, mCompositeFilter);}if (!mManageApplications.mShowSystem) {if (LIST_TYPES_WITH_INSTANT.contains(mManageApplications.mListType)) {filterObj = new CompoundFilter(filterObj,ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT);} else {filterObj = new CompoundFilter(filterObj,ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER);}}if (mLastSortMode == R.id.sort_order_size) {switch (mWhichSize) {case SIZE_INTERNAL:comparatorObj = ApplicationsState.INTERNAL_SIZE_COMPARATOR;break;case SIZE_EXTERNAL:comparatorObj = ApplicationsState.EXTERNAL_SIZE_COMPARATOR;break;default:comparatorObj = ApplicationsState.SIZE_COMPARATOR;break;}} else if (mLastSortMode == R.id.sort_order_recent_notification) {comparatorObj = AppStateNotificationBridge.RECENT_NOTIFICATION_COMPARATOR;} else if (mLastSortMode == R.id.sort_order_frequent_notification) {comparatorObj = AppStateNotificationBridge.FREQUENCY_NOTIFICATION_COMPARATOR;} else {comparatorObj = ApplicationsState.ALPHA_COMPARATOR;}final AppFilter finalFilterObj = new CompoundFilter(filterObj,ApplicationsState.FILTER_NOT_HIDE);ThreadUtils.postOnBackgroundThread(() -> {mSession.rebuild(finalFilterObj, comparatorObj, false);});}@VisibleForTestingvoid filterSearch(String query) {if (mSearchFilter == null) {mSearchFilter = new SearchFilter();}// If we haven't load apps list completely, don't filter anything.if (mOriginalEntries == null) {Log.w(TAG, "Apps haven't loaded completely yet, so nothing can be filtered");return;}mSearchFilter.filter(query);}private static boolean packageNameEquals(PackageItemInfo info1, PackageItemInfo info2) {if (info1 == null || info2 == null) {return false;}if (info1.packageName == null || info2.packageName == null) {return false;}return info1.packageName.equals(info2.packageName);}private ArrayList<ApplicationsState.AppEntry> removeDuplicateIgnoringUser(ArrayList<ApplicationsState.AppEntry> entries) {int size = entries.size();// returnList will not have more entries than entriesArrayList<ApplicationsState.AppEntry> returnEntries = new ArrayList<>(size);// assume appinfo of same package but different users are grouped togetherPackageItemInfo lastInfo = null;for (int i = 0; i < size; i++) {AppEntry appEntry = entries.get(i);PackageItemInfo info = appEntry.info;if (!packageNameEquals(lastInfo, appEntry.info)) {returnEntries.add(appEntry);}lastInfo = info;}returnEntries.trimToSize();return returnEntries;}@Overridepublic void onRebuildComplete(ArrayList<AppEntry> entries) {//android.util.Log.d("xin.wang", "onRebuildComplete:-> entries-> " + entries);android.util.Log.d("xin.wang", "哈哈哈onRebuildComplete:-> entries-> " + entries.size());if (DEBUG) {Log.d(TAG, "onRebuildComplete size=" + entries.size());}final int filterType = mAppFilter.getFilterType();if (filterType == FILTER_APPS_POWER_ALLOWLIST|| filterType == FILTER_APPS_POWER_ALLOWLIST_ALL) {entries = removeDuplicateIgnoringUser(entries);android.util.Log.d("xin.wang", "onRebuildComplete: entries -> " + entries.size());}//only show the cloned third-party apps in the interface of workif (mManageApplications.mIsWorkOnly && !mManageApplications.mIsPersonalOnly) {ArrayList<ApplicationsState.AppEntry> cloneEntries = new ArrayList();int cloneNum = 0;for (ApplicationsState.AppEntry entry : entries) {cloneNum ++;android.util.Log.d("xin.wang", "哈哈哈onRebuildComplete: cloneNum -> " + cloneNum);int userId = UserHandle.getUserId(entry.info.uid);UserInfo userInfo = mManageApplications.mUserManager.getUserInfo(userId);boolean isManagedProfile = userInfo.isManagedProfile();if (isManagedProfile) {cloneEntries.add(entry);android.util.Log.d("xin.wang", "isManagedProfile: -> cloneEntries " + cloneEntries + "<- cloneEntries.size() -> " + cloneEntries.size());continue;}boolean isCloneProfile = userInfo.isCloneProfile();boolean contains = mSupportAppClone.contains(entry.info.packageName);android.util.Log.d("xin.wang", "onRebuildComplete: isCloneProfile -> " + isCloneProfile + "<- contains -> " + contains);if (mSupportAppClone.contains(entry.info.packageName) && isCloneProfile) {android.util.Log.d("xin.wang", "onRebuildComplete:mSupportAppClone-> " + mSupportAppClone + "<- entry.info.packageName->" + entry.info.packageName);cloneEntries.add(entry);android.util.Log.d("xin.wang", "mSupportAppClone.contains(entry.info.packageName): ->  cloneEntries " + cloneEntries + "<- cloneEntries.size() -> " + cloneEntries.size());}}mEntries = cloneEntries;android.util.Log.d("xin.wang", "onRebuildComplete:cloneEntries ->  " + cloneEntries + "<- cloneEntries.size() ->  " + cloneEntries.size());mOriginalEntries = cloneEntries;} else {mEntries = entries;android.util.Log.d("xin.wang", "哈哈哈onRebuildComplete: mEntries -> " + mEntries.size());mOriginalEntries = entries;}notifyDataSetChanged();if (getItemCount() == 0) {mLoadingViewController.showEmpty(false /* animate */);} else {mLoadingViewController.showContent(false /* animate */);if (mManageApplications.mSearchView != null&& mManageApplications.mSearchView.isVisibleToUser()) {final CharSequence query = mManageApplications.mSearchView.getQuery();if (!TextUtils.isEmpty(query)) {filterSearch(query.toString());}}}// Restore the last scroll position if the number of entries added so far is bigger than// it.if (mLastIndex != -1 && getItemCount() > mLastIndex) {mManageApplications.mRecyclerView.getLayoutManager().scrollToPosition(mLastIndex);mLastIndex = -1;}if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) {// No enabled or disabled filters for usage access.return;}mManageApplications.setHasDisabled(mState.haveDisabledApps());mManageApplications.setHasInstant(mState.haveInstantApps());}@VisibleForTestingvoid updateLoading() {final boolean appLoaded = mHasReceivedLoadEntries && mSession.getAllApps().size() != 0;if (appLoaded) {mLoadingViewController.showContent(false /* animate */);} else {mLoadingViewController.showLoadingViewDelayed();}}@Overridepublic void onExtraInfoUpdated() {mHasReceivedBridgeCallback = true;rebuild();}@Overridepublic void onRunningStateChanged(boolean running) {mManageApplications.getActivity().setProgressBarIndeterminateVisibility(running);}@Overridepublic void onPackageListChanged() {rebuild();}@Overridepublic void onPackageIconChanged() {// We ensure icons are loaded when their item is displayed, so// don't care about icons loaded in the background.}@Overridepublic void onLoadEntriesCompleted() {mHasReceivedLoadEntries = true;// We may have been skipping rebuilds until this came in, trigger one now.rebuild();}@Overridepublic void onPackageSizeChanged(String packageName) {if (mEntries == null) {return;}final int size = mEntries.size();for (int i = 0; i < size; i++) {final AppEntry entry = mEntries.get(i);android.util.Log.d("xin.wang", "onPackageSizeChanged: -> entry -> " + entry.info.packageName + "<- size -> " + size + "<- mEntries -> " + mEntries);final ApplicationInfo info = entry.info;if (info == null && !TextUtils.equals(packageName, info.packageName)) {continue;}if (TextUtils.equals(mManageApplications.mCurrentPkgName, info.packageName)) {// We got the size information for the last app the// user viewed, and are sorting by size...  they may// have cleared data, so we immediately want to resort// the list with the new size to reflect it to the user.rebuild();return;} else {mOnScrollListener.postNotifyItemChange(i);}}}@Overridepublic void onLauncherInfoChanged() {if (!mManageApplications.mShowSystem) {rebuild();}}@Overridepublic void onAllSizesComputed() {if (mLastSortMode == R.id.sort_order_size) {rebuild();}}@Overridepublic int getItemCount() {if (mEntries == null) {return 0;}android.util.Log.d("xin.wang", "getItemCount: " + mEntries.size());return mEntries.size();}public int getApplicationCount() {return mEntries != null ? mEntries.size() : 0;}public AppEntry getAppEntry(int position) {return mEntries.get(position);}@Overridepublic long getItemId(int position) {if (position == mEntries.size()) {return -1;}return mEntries.get(position).id;}public boolean isEnabled(int position) {if (getItemViewType(position) == VIEW_TYPE_EXTRA_VIEW|| mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {return true;}ApplicationsState.AppEntry entry = mEntries.get(position);return !mBackend.isSysAllowlisted(entry.info.packageName)&& !mBackend.isDefaultActiveApp(entry.info.packageName);}@Overridepublic void onBindViewHolder(ApplicationViewHolder holder, int position) {// Bind the data efficiently with the holderfinal ApplicationsState.AppEntry entry = mEntries.get(position);android.util.Log.d("xin.wang", "onBindViewHolder: ApplicationsState.AppEntry -> " + entry + "<- entry -> ");synchronized (entry) {mState.ensureLabelDescription(entry);holder.setTitle(entry.label, entry.labelDescription);android.util.Log.d("xin.wang", "onBindViewHolder -> entry.label -> : " + entry.label + "<- entry.labelDescription -> " + entry.labelDescription);mState.ensureIcon(entry);holder.setIcon(entry.icon);updateSummary(holder, entry);updateSwitch(holder, entry);holder.updateDisableView(entry.info);}holder.setEnabled(isEnabled(position));holder.itemView.setOnClickListener(mManageApplications);}private void updateSummary(ApplicationViewHolder holder, AppEntry entry) {switch (mManageApplications.mListType) {case LIST_TYPE_NOTIFICATION:if (entry.extraInfo != null&& entry.extraInfo instanceof NotificationsSentState) {holder.setSummary(AppStateNotificationBridge.getSummary(mContext,(NotificationsSentState) entry.extraInfo, mLastSortMode));} else {holder.setSummary(null);}break;case LIST_TYPE_USAGE_ACCESS:if (entry.extraInfo != null&& entry.extraInfo instanceof PermissionState) {holder.setSummary((new UsageState((PermissionState) entry.extraInfo)).isPermissible()? R.string.app_permission_summary_allowed: R.string.app_permission_summary_not_allowed);} else {holder.setSummary(null);}break;case LIST_TYPE_HIGH_POWER:holder.setSummary(HighPowerDetail.getSummary(mContext, entry));break;case LIST_TYPE_OVERLAY:holder.setSummary(DrawOverlayDetails.getSummary(mContext, entry));break;case LIST_TYPE_WRITE_SETTINGS:holder.setSummary(WriteSettingsDetails.getSummary(mContext, entry));break;case LIST_TYPE_MANAGE_SOURCES:holder.setSummary(ExternalSourcesDetails.getPreferenceSummary(mContext, entry));break;case LIST_TYPE_WIFI_ACCESS:holder.setSummary(ChangeWifiStateDetails.getSummary(mContext, entry));break;case LIST_MANAGE_EXTERNAL_STORAGE:holder.setSummary(ManageExternalStorageDetails.getSummary(mContext, entry));break;case LIST_TYPE_ALARMS_AND_REMINDERS:holder.setSummary(AlarmsAndRemindersDetails.getSummary(mContext, entry));break;case LIST_TYPE_MEDIA_MANAGEMENT_APPS:holder.setSummary(MediaManagementAppsDetails.getSummary(mContext, entry));break;default:holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);break;}}private void updateSwitch(ApplicationViewHolder holder, AppEntry entry) {switch (mManageApplications.mListType) {case LIST_TYPE_NOTIFICATION:holder.updateSwitch(((AppStateNotificationBridge) mExtraInfoBridge).getSwitchOnCheckedListener(entry),AppStateNotificationBridge.enableSwitch(entry),AppStateNotificationBridge.checkSwitch(entry));if (entry.extraInfo != null&& entry.extraInfo instanceof NotificationsSentState) {holder.setSummary(AppStateNotificationBridge.getSummary(mContext,(NotificationsSentState) entry.extraInfo, mLastSortMode));} else {holder.setSummary(null);}break;}}public static class OnScrollListener extends RecyclerView.OnScrollListener {private int mScrollState = SCROLL_STATE_IDLE;private boolean mDelayNotifyDataChange;private ApplicationsAdapter mAdapter;public OnScrollListener(ApplicationsAdapter adapter) {mAdapter = adapter;}@Overridepublic void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {mScrollState = newState;if (mScrollState == SCROLL_STATE_IDLE && mDelayNotifyDataChange) {mDelayNotifyDataChange = false;mAdapter.notifyDataSetChanged();}}public void postNotifyItemChange(int index) {if (mScrollState == SCROLL_STATE_IDLE) {mAdapter.notifyItemChanged(index);} else {mDelayNotifyDataChange = true;}}}/*** An array filter that constrains the content of the array adapter with a substring.* Item that does not contains the specified substring will be removed from the list.</p>*/private class SearchFilter extends Filter {@WorkerThread@Overrideprotected FilterResults performFiltering(CharSequence query) {final ArrayList<ApplicationsState.AppEntry> matchedEntries;if (TextUtils.isEmpty(query)) {matchedEntries = mOriginalEntries;} else {matchedEntries = new ArrayList<>();for (ApplicationsState.AppEntry entry : mOriginalEntries) {if (entry.label.toLowerCase().contains(query.toString().toLowerCase())) {matchedEntries.add(entry);}}}final FilterResults results = new FilterResults();results.values = matchedEntries;results.count = matchedEntries.size();return results;}@Overrideprotected void publishResults(CharSequence constraint, FilterResults results) {mEntries = (ArrayList<ApplicationsState.AppEntry>) results.values;notifyDataSetChanged();}}}
}
/** Copyright (C) 2006 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.applications.manageapplications;import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ALL;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_BLOCKED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_DISABLED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_ENABLED;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_FREQUENT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_INSTANT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_PERSONAL;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_ALLOWLIST;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_POWER_ALLOWLIST_ALL;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_RECENT;
import static com.android.settings.applications.manageapplications.AppFilterRegistry.FILTER_APPS_WORK;
import static com.android.settings.search.actionbar.SearchMenuController.MENU_SEARCH;import android.annotation.Nullable;
import android.annotation.StringRes;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.settings.SettingsEnums;
import android.app.usage.IUsageStatsManager;
import android.compat.annotation.ChangeId;
import android.compat.annotation.LoggingOnly;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.preference.PreferenceFrameLayout;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Filter;
import android.widget.FrameLayout;
import android.widget.SearchView;
import android.widget.Spinner;import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;import com.android.internal.compat.IPlatformCompat;
import com.android.settings.R;
import com.android.settings.Settings;
import com.android.settings.Settings.GamesStorageActivity;
import com.android.settings.Settings.HighPowerApplicationsActivity;
import com.android.settings.Settings.ManageExternalSourcesActivity;
import com.android.settings.Settings.OverlaySettingsActivity;
import com.android.settings.Settings.StorageUseActivity;
import com.android.settings.Settings.UsageAccessSettingsActivity;
import com.android.settings.Settings.WriteSettingsActivity;
import com.android.settings.SettingsActivity;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateManageExternalStorageBridge;
import com.android.settings.applications.AppStateMediaManagementAppsBridge;
import com.android.settings.applications.AppStateNotificationBridge;
import com.android.settings.applications.AppStateNotificationBridge.NotificationsSentState;
import com.android.settings.applications.AppStateOverlayBridge;
import com.android.settings.applications.AppStatePowerBridge;
import com.android.settings.applications.AppStateUsageBridge;
import com.android.settings.applications.AppStateUsageBridge.UsageState;
import com.android.settings.applications.AppStateWriteSettingsBridge;
import com.android.settings.applications.AppStorageSettings;
import com.android.settings.applications.UsageAccessDetails;
import com.android.settings.applications.appinfo.AlarmsAndRemindersDetails;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
import com.android.settings.applications.appinfo.DrawOverlayDetails;
import com.android.settings.applications.appinfo.ExternalSourcesDetails;
import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
import com.android.settings.applications.appinfo.MediaManagementAppsDetails;
import com.android.settings.applications.appinfo.WriteSettingsDetails;
import com.android.settings.core.InstrumentedFragment;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
import com.android.settings.fuelgauge.HighPowerDetail;
import com.android.settings.notification.ConfigureNotificationSettings;
import com.android.settings.notification.NotificationBackend;
import com.android.settings.notification.app.AppNotificationSettings;
import com.android.settings.widget.LoadingViewController;
import com.android.settings.wifi.AppStateChangeWifiStateBridge;
import com.android.settings.wifi.ChangeWifiStateDetails;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
import com.android.settingslib.applications.ApplicationsState.CompoundFilter;
import com.android.settingslib.applications.ApplicationsState.VolumeFilter;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
import com.android.settingslib.utils.ThreadUtils;
import com.android.settingslib.widget.settingsspinner.SettingsSpinnerAdapter;import com.google.android.material.appbar.AppBarLayout;import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.HashSet;/*** Activity to pick an application that will be used to display installation information and* options to uninstall/delete user data for system applications. This activity* can be launched through Settings or via the ACTION_MANAGE_PACKAGE_STORAGE* intent.*/
public class ManageApplications extends InstrumentedFragmentimplements View.OnClickListener, OnItemSelectedListener, SearchView.OnQueryTextListener,MenuItem.OnActionExpandListener {static final String TAG = "ManageApplications";static final boolean DEBUG = Build.IS_DEBUGGABLE;// Intent extras.public static final String EXTRA_CLASSNAME = "classname";// Used for storage only.public static final String EXTRA_VOLUME_UUID = "volumeUuid";public static final String EXTRA_VOLUME_NAME = "volumeName";public static final String EXTRA_STORAGE_TYPE = "storageType";public static final String EXTRA_WORK_ID = "workId";private static final String EXTRA_SORT_ORDER = "sortOrder";private static final String EXTRA_SHOW_SYSTEM = "showSystem";private static final String EXTRA_HAS_ENTRIES = "hasEntries";private static final String EXTRA_HAS_BRIDGE = "hasBridge";private static final String EXTRA_FILTER_TYPE = "filterType";@VisibleForTestingstatic final String EXTRA_EXPAND_SEARCH_VIEW = "expand_search_view";// attributes used as keys when passing values to AppInfoDashboardFragment activitypublic static final String APP_CHG = "chg";// constant value that can be used to check return code from sub activity.private static final int INSTALLED_APP_DETAILS = 1;private static final int ADVANCED_SETTINGS = 2;public static final int SIZE_TOTAL = 0;public static final int SIZE_INTERNAL = 1;public static final int SIZE_EXTERNAL = 2;// Storage types. Used to determine what the extra item in the list of preferences is.public static final int STORAGE_TYPE_DEFAULT = 0; // Show all apps that are not categorized.public static final int STORAGE_TYPE_LEGACY = 1;  // Show apps even if they can be categorized./*** Intents with action {@code android.settings.MANAGE_APP_OVERLAY_PERMISSION}* and data URI scheme {@code package} don't go to the app-specific screen for managing the* permission anymore. Instead, they redirect to this screen for managing all the apps that have* requested such permission.*/@ChangeId@LoggingOnlyprivate static final long CHANGE_RESTRICT_SAW_INTENT = 135920175L;// sort order@VisibleForTestingint mSortOrder = R.id.sort_order_alpha;// whether showing system apps.private boolean mShowSystem;private ApplicationsState mApplicationsState;public int mListType;private AppFilterItem mFilter;private ApplicationsAdapter mApplications;private View mLoadingContainer;private SearchView mSearchView;// Size resource used for packages whose size computation failed for some reasonCharSequence mInvalidSizeStr;private String mCurrentPkgName;private int mCurrentUid;private Menu mOptionsMenu;public static final int LIST_TYPE_MAIN = 0;public static final int LIST_TYPE_NOTIFICATION = 1;public static final int LIST_TYPE_STORAGE = 3;public static final int LIST_TYPE_USAGE_ACCESS = 4;public static final int LIST_TYPE_HIGH_POWER = 5;public static final int LIST_TYPE_OVERLAY = 6;public static final int LIST_TYPE_WRITE_SETTINGS = 7;public static final int LIST_TYPE_MANAGE_SOURCES = 8;public static final int LIST_TYPE_GAMES = 9;public static final int LIST_TYPE_WIFI_ACCESS = 10;public static final int LIST_MANAGE_EXTERNAL_STORAGE = 11;public static final int LIST_TYPE_ALARMS_AND_REMINDERS = 12;public static final int LIST_TYPE_MEDIA_MANAGEMENT_APPS = 13;// List types that should show instant apps.public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(LIST_TYPE_MAIN,LIST_TYPE_STORAGE));@VisibleForTestingView mSpinnerHeader;@VisibleForTestingFilterSpinnerAdapter mFilterAdapter;@VisibleForTestingRecyclerView mRecyclerView;// Whether or not search view is expanded.@VisibleForTestingboolean mExpandSearch;private View mRootView;private Spinner mFilterSpinner;private IUsageStatsManager mUsageStatsManager;private UserManager mUserManager;private NotificationBackend mNotificationBackend;private ResetAppsHelper mResetAppsHelper;private String mVolumeUuid;private int mStorageType;private boolean mIsWorkOnly;private int mWorkUserId;private boolean mIsPersonalOnly;private View mEmptyView;private int mFilterType;private AppBarLayout mAppBarLayout;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setHasOptionsMenu(true);final Activity activity = getActivity();mUserManager = activity.getSystemService(UserManager.class);mApplicationsState = ApplicationsState.getInstance(activity.getApplication());Intent intent = activity.getIntent();Bundle args = getArguments();int screenTitle = intent.getIntExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, R.string.all_apps);String className = args != null ? args.getString(EXTRA_CLASSNAME) : null;if (className == null) {className = intent.getComponent().getClassName();}if (className.equals(StorageUseActivity.class.getName())) {if (args != null && args.containsKey(EXTRA_VOLUME_UUID)) {mVolumeUuid = args.getString(EXTRA_VOLUME_UUID);mStorageType = args.getInt(EXTRA_STORAGE_TYPE, STORAGE_TYPE_DEFAULT);mListType = LIST_TYPE_STORAGE;} else {// No volume selected, display a normal list, sorted by size.mListType = LIST_TYPE_MAIN;}mSortOrder = R.id.sort_order_size;} else if (className.equals(UsageAccessSettingsActivity.class.getName())) {mListType = LIST_TYPE_USAGE_ACCESS;screenTitle = R.string.usage_access;} else if (className.equals(HighPowerApplicationsActivity.class.getName())) {mListType = LIST_TYPE_HIGH_POWER;// Default to showing system.mShowSystem = true;screenTitle = R.string.high_power_apps;} else if (className.equals(OverlaySettingsActivity.class.getName())) {mListType = LIST_TYPE_OVERLAY;screenTitle = R.string.system_alert_window_settings;reportIfRestrictedSawIntent(intent);} else if (className.equals(WriteSettingsActivity.class.getName())) {mListType = LIST_TYPE_WRITE_SETTINGS;screenTitle = R.string.write_settings;} else if (className.equals(ManageExternalSourcesActivity.class.getName())) {mListType = LIST_TYPE_MANAGE_SOURCES;screenTitle = R.string.install_other_apps;} else if (className.equals(GamesStorageActivity.class.getName())) {mListType = LIST_TYPE_GAMES;mSortOrder = R.id.sort_order_size;} else if (className.equals(Settings.ChangeWifiStateActivity.class.getName())) {mListType = LIST_TYPE_WIFI_ACCESS;screenTitle = R.string.change_wifi_state_title;} else if (className.equals(Settings.ManageExternalStorageActivity.class.getName())) {mListType = LIST_MANAGE_EXTERNAL_STORAGE;screenTitle = R.string.manage_external_storage_title;}  else if (className.equals(Settings.MediaManagementAppsActivity.class.getName())) {mListType = LIST_TYPE_MEDIA_MANAGEMENT_APPS;screenTitle = R.string.media_management_apps_title;} else if (className.equals(Settings.AlarmsAndRemindersActivity.class.getName())) {mListType = LIST_TYPE_ALARMS_AND_REMINDERS;screenTitle = R.string.alarms_and_reminders_title;} else if (className.equals(Settings.NotificationAppListActivity.class.getName())) {mListType = LIST_TYPE_NOTIFICATION;mUsageStatsManager = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(Context.USAGE_STATS_SERVICE));mNotificationBackend = new NotificationBackend();mSortOrder = R.id.sort_order_recent_notification;screenTitle = R.string.app_notifications_title;} else {if (screenTitle == -1) {screenTitle = R.string.all_apps;}mListType = LIST_TYPE_MAIN;}final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance();mFilter = appFilterRegistry.get(appFilterRegistry.getDefaultFilterType(mListType));mIsPersonalOnly = args != null ? args.getInt(ProfileSelectFragment.EXTRA_PROFILE)== ProfileSelectFragment.ProfileType.PERSONAL : false;mIsWorkOnly = args != null ? args.getInt(ProfileSelectFragment.EXTRA_PROFILE)== ProfileSelectFragment.ProfileType.WORK : false;mWorkUserId = args != null ? args.getInt(EXTRA_WORK_ID) : UserHandle.myUserId();if (mIsWorkOnly && mWorkUserId == UserHandle.myUserId()) {mWorkUserId = Utils.getManagedProfileId(mUserManager, UserHandle.myUserId());}mExpandSearch = activity.getIntent().getBooleanExtra(EXTRA_EXPAND_SEARCH_VIEW, false);if (savedInstanceState != null) {mSortOrder = savedInstanceState.getInt(EXTRA_SORT_ORDER, mSortOrder);mShowSystem = savedInstanceState.getBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);mFilterType =savedInstanceState.getInt(EXTRA_FILTER_TYPE, AppFilterRegistry.FILTER_APPS_ALL);mExpandSearch = savedInstanceState.getBoolean(EXTRA_EXPAND_SEARCH_VIEW);}mInvalidSizeStr = activity.getText(R.string.invalid_size_value);mResetAppsHelper = new ResetAppsHelper(activity);if (screenTitle > 0) {activity.setTitle(screenTitle);}}private void reportIfRestrictedSawIntent(Intent intent) {try {Uri data = intent.getData();if (data == null || !TextUtils.equals("package", data.getScheme())) {// Not a restricted intentreturn;}IBinder activityToken = getActivity().getActivityToken();int callingUid = ActivityManager.getService().getLaunchedFromUid(activityToken);if (callingUid == -1) {Log.w(TAG, "Error obtaining calling uid");return;}IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));if (platformCompat == null) {Log.w(TAG, "Error obtaining IPlatformCompat service");return;}platformCompat.reportChangeByUid(CHANGE_RESTRICT_SAW_INTENT, callingUid);} catch (RemoteException e) {Log.w(TAG, "Error reporting SAW intent restriction", e);}}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {if (mListType == LIST_TYPE_OVERLAY && !Utils.isSystemAlertWindowEnabled(getContext())) {mRootView = inflater.inflate(R.layout.manage_applications_apps_unsupported, null);setHasOptionsMenu(false);return mRootView;}mRootView = inflater.inflate(R.layout.manage_applications_apps, null);mLoadingContainer = mRootView.findViewById(R.id.loading_container);mEmptyView = mRootView.findViewById(android.R.id.empty);mRecyclerView = mRootView.findViewById(R.id.apps_list);mApplications = new ApplicationsAdapter(mApplicationsState, this, mFilter,savedInstanceState);if (savedInstanceState != null) {mApplications.mHasReceivedLoadEntries =savedInstanceState.getBoolean(EXTRA_HAS_ENTRIES, false);mApplications.mHasReceivedBridgeCallback =savedInstanceState.getBoolean(EXTRA_HAS_BRIDGE, false);}mRecyclerView.setItemAnimator(null);mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false /* reverseLayout */));mRecyclerView.setAdapter(mApplications);android.util.Log.d("xin.wang", "onCreateView:mRecyclerView.setAdapter-> " + Thread.currentThread().getName());// We have to do this now because PreferenceFrameLayout looks at it// only when the view is added.if (container instanceof PreferenceFrameLayout) {((PreferenceFrameLayout.LayoutParams) mRootView.getLayoutParams()).removeBorders = true;}createHeader();mResetAppsHelper.onRestoreInstanceState(savedInstanceState);mAppBarLayout = getActivity().findViewById(R.id.app_bar);disableToolBarScrollableBehavior();return mRootView;}@VisibleForTestingvoid createHeader() {final Activity activity = getActivity();final FrameLayout pinnedHeader = mRootView.findViewById(R.id.pinned_header);mSpinnerHeader = activity.getLayoutInflater().inflate(R.layout.manage_apps_filter_spinner, pinnedHeader, false);mFilterSpinner = mSpinnerHeader.findViewById(R.id.filter_spinner);mFilterAdapter = new FilterSpinnerAdapter(this);mFilterSpinner.setAdapter(mFilterAdapter);mFilterSpinner.setOnItemSelectedListener(this);mFilterSpinner.setVisibility(View.GONE);pinnedHeader.addView(mSpinnerHeader, 0);final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance();final int filterType = appFilterRegistry.getDefaultFilterType(mListType);android.util.Log.d("xin.wang", "createHeader:-> filterType -> " + mListType + "<- filterType -> " + filterType); //filterType = 4 -> FILTER_APPS_ALLandroid.util.Log.d("xin.wang", "createHeader:->mFilterOptions.size()-> " + mFilterAdapter.getCount());//mFilterAdapter.enableFilter(filterType);    //filterType = 4 -> FILTER_APPS_ALLif (mListType == LIST_TYPE_MAIN) {if (UserManager.get(getActivity()).getUserProfiles().size() > 1 && !mIsWorkOnly&& !mIsPersonalOnly) {mFilterAdapter.enableFilter(FILTER_APPS_PERSONAL);//mFilterAdapter.enableFilter(FILTER_APPS_WORK);}}if (mListType == LIST_TYPE_NOTIFICATION) {mFilterAdapter.enableFilter(FILTER_APPS_RECENT);mFilterAdapter.enableFilter(FILTER_APPS_FREQUENT);mFilterAdapter.enableFilter(FILTER_APPS_BLOCKED);mFilterAdapter.enableFilter(FILTER_APPS_ALL);}if (mListType == LIST_TYPE_HIGH_POWER) {mFilterAdapter.enableFilter(FILTER_APPS_POWER_ALLOWLIST_ALL);}setCompositeFilter();}@VisibleForTesting@Nullablestatic AppFilter getCompositeFilter(int listType, int storageType, String volumeUuid) {AppFilter filter = new VolumeFilter(volumeUuid);if (listType == LIST_TYPE_STORAGE) {if (storageType == STORAGE_TYPE_DEFAULT) {filter = new CompoundFilter(ApplicationsState.FILTER_APPS_EXCEPT_GAMES, filter);}return filter;}if (listType == LIST_TYPE_GAMES) {return new CompoundFilter(ApplicationsState.FILTER_GAMES, filter);}return null;}@Overridepublic int getMetricsCategory() {switch (mListType) {case LIST_TYPE_MAIN:return SettingsEnums.MANAGE_APPLICATIONS;case LIST_TYPE_NOTIFICATION:return SettingsEnums.MANAGE_APPLICATIONS_NOTIFICATIONS;case LIST_TYPE_STORAGE:return SettingsEnums.APPLICATIONS_STORAGE_APPS;case LIST_TYPE_GAMES:return SettingsEnums.APPLICATIONS_STORAGE_GAMES;case LIST_TYPE_USAGE_ACCESS:return SettingsEnums.USAGE_ACCESS;case LIST_TYPE_HIGH_POWER:return SettingsEnums.APPLICATIONS_HIGH_POWER_APPS;case LIST_TYPE_OVERLAY:return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;case LIST_TYPE_WRITE_SETTINGS:return SettingsEnums.SYSTEM_ALERT_WINDOW_APPS;case LIST_TYPE_MANAGE_SOURCES:return SettingsEnums.MANAGE_EXTERNAL_SOURCES;case LIST_TYPE_WIFI_ACCESS:return SettingsEnums.CONFIGURE_WIFI;case LIST_MANAGE_EXTERNAL_STORAGE:return SettingsEnums.MANAGE_EXTERNAL_STORAGE;case LIST_TYPE_ALARMS_AND_REMINDERS:return SettingsEnums.ALARMS_AND_REMINDERS;case LIST_TYPE_MEDIA_MANAGEMENT_APPS:return SettingsEnums.MEDIA_MANAGEMENT_APPS;default:return SettingsEnums.PAGE_UNKNOWN;}}@Overridepublic void onStart() {super.onStart();updateView();if (mApplications != null) {mApplications.resume(mSortOrder);mApplications.updateLoading();}}@Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);mResetAppsHelper.onSaveInstanceState(outState);outState.putInt(EXTRA_SORT_ORDER, mSortOrder);outState.putInt(EXTRA_FILTER_TYPE, mFilter.getFilterType());outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);//add bug 1702049:NullPointerException on a null object referenceif (mApplications != null) {outState.putBoolean(EXTRA_HAS_ENTRIES, mApplications.mHasReceivedLoadEntries);outState.putBoolean(EXTRA_HAS_BRIDGE, mApplications.mHasReceivedBridgeCallback);if (mSearchView != null) {outState.putBoolean(EXTRA_EXPAND_SEARCH_VIEW, !mSearchView.isIconified());}mApplications.onSaveInstanceState(outState);}}@Overridepublic void onStop() {super.onStop();if (mApplications != null) {mApplications.pause();}mResetAppsHelper.stop();}@Overridepublic void onDestroyView() {super.onDestroyView();if (mApplications != null) {mApplications.release();}mRootView = null;}@Overridepublic void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) {if (mListType == LIST_TYPE_NOTIFICATION) {mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid);} else if (mListType == LIST_TYPE_HIGH_POWER || mListType == LIST_TYPE_OVERLAY|| mListType == LIST_TYPE_WRITE_SETTINGS) {mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid);} else {mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid));}}}private void setCompositeFilter() {AppFilter compositeFilter = getCompositeFilter(mListType, mStorageType, mVolumeUuid);if (compositeFilter == null) {compositeFilter = mFilter.getFilter();}if (mIsWorkOnly) {compositeFilter = new CompoundFilter(compositeFilter, ApplicationsState.FILTER_WORK);}if (mIsPersonalOnly) {compositeFilter = new CompoundFilter(compositeFilter,ApplicationsState.FILTER_PERSONAL);}mApplications.setCompositeFilter(compositeFilter);}// utility method used to start sub activityprivate void startApplicationDetailsActivity() {switch (mListType) {case LIST_TYPE_NOTIFICATION:startAppInfoFragment(AppNotificationSettings.class, R.string.notifications_title);break;case LIST_TYPE_USAGE_ACCESS:startAppInfoFragment(UsageAccessDetails.class, R.string.usage_access);break;case LIST_TYPE_STORAGE:startAppInfoFragment(AppStorageSettings.class, R.string.storage_settings);break;case LIST_TYPE_HIGH_POWER:HighPowerDetail.show(this, mCurrentUid, mCurrentPkgName, INSTALLED_APP_DETAILS);break;case LIST_TYPE_OVERLAY:startAppInfoFragment(DrawOverlayDetails.class, R.string.overlay_settings);break;case LIST_TYPE_WRITE_SETTINGS:startAppInfoFragment(WriteSettingsDetails.class, R.string.write_system_settings);break;case LIST_TYPE_MANAGE_SOURCES:startAppInfoFragment(ExternalSourcesDetails.class, R.string.install_other_apps);break;case LIST_TYPE_GAMES:startAppInfoFragment(AppStorageSettings.class, R.string.game_storage_settings);break;case LIST_TYPE_WIFI_ACCESS:startAppInfoFragment(ChangeWifiStateDetails.class,R.string.change_wifi_state_title);break;case LIST_MANAGE_EXTERNAL_STORAGE:startAppInfoFragment(ManageExternalStorageDetails.class,R.string.manage_external_storage_title);break;case LIST_TYPE_ALARMS_AND_REMINDERS:startAppInfoFragment(AlarmsAndRemindersDetails.class,R.string.alarms_and_reminders_label);break;case LIST_TYPE_MEDIA_MANAGEMENT_APPS:startAppInfoFragment(MediaManagementAppsDetails.class,R.string.media_management_apps_title);break;// TODO: Figure out if there is a way where we can spin up the profile's settings// process ahead of time, to avoid a long load of data when user clicks on a managed// app. Maybe when they load the list of apps that contains managed profile apps.default:startAppInfoFragment(AppInfoDashboardFragment.class, R.string.application_info_label);break;}}private void startAppInfoFragment(Class<?> fragment, int titleRes) {AppInfoBase.startAppInfoFragment(fragment, titleRes, mCurrentPkgName, mCurrentUid, this,INSTALLED_APP_DETAILS, getMetricsCategory());}@Overridepublic void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {final Activity activity = getActivity();if (activity == null) {return;}mOptionsMenu = menu;inflater.inflate(R.menu.manage_apps, menu);final MenuItem searchMenuItem = menu.findItem(R.id.search_app_list_menu);if (searchMenuItem != null) {searchMenuItem.setOnActionExpandListener(this);mSearchView = (SearchView) searchMenuItem.getActionView();mSearchView.setQueryHint(getText(R.string.search_settings));mSearchView.setOnQueryTextListener(this);if (mExpandSearch) {searchMenuItem.expandActionView();}}updateOptionsMenu();}@Overridepublic boolean onMenuItemActionExpand(MenuItem item) {// To prevent a large space on tool bar.mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);// To prevent user can expand the collapsing tool bar view.ViewCompat.setNestedScrollingEnabled(mRecyclerView, false);return true;}@Overridepublic boolean onMenuItemActionCollapse(MenuItem item) {// We keep the collapsed status after user cancel the search function.mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);ViewCompat.setNestedScrollingEnabled(mRecyclerView, true);return true;}@Overridepublic void onPrepareOptionsMenu(Menu menu) {updateOptionsMenu();}@Overridepublic void onDestroyOptionsMenu() {mOptionsMenu = null;}@StringResint getHelpResource() {switch (mListType) {case LIST_TYPE_NOTIFICATION:return R.string.help_uri_notifications;case LIST_TYPE_USAGE_ACCESS:return R.string.help_url_usage_access;case LIST_TYPE_STORAGE:return R.string.help_uri_apps_storage;case LIST_TYPE_HIGH_POWER:return R.string.help_uri_apps_high_power;case LIST_TYPE_OVERLAY:return R.string.help_uri_apps_overlay;case LIST_TYPE_WRITE_SETTINGS:return R.string.help_uri_apps_write_settings;case LIST_TYPE_MANAGE_SOURCES:return R.string.help_uri_apps_manage_sources;case LIST_TYPE_GAMES:return R.string.help_uri_apps_overlay;case LIST_TYPE_WIFI_ACCESS:return R.string.help_uri_apps_wifi_access;case LIST_MANAGE_EXTERNAL_STORAGE:return R.string.help_uri_manage_external_storage;case LIST_TYPE_ALARMS_AND_REMINDERS:return R.string.help_uri_alarms_and_reminders;case LIST_TYPE_MEDIA_MANAGEMENT_APPS:return R.string.help_uri_media_management_apps;default:case LIST_TYPE_MAIN:return R.string.help_uri_apps;}}void updateOptionsMenu() {if (mOptionsMenu == null) {return;}mOptionsMenu.findItem(R.id.advanced).setVisible(false);mOptionsMenu.findItem(R.id.sort_order_alpha).setVisible(mListType == LIST_TYPE_STORAGE&& mSortOrder != R.id.sort_order_alpha);mOptionsMenu.findItem(R.id.sort_order_size).setVisible(mListType == LIST_TYPE_STORAGE&& mSortOrder != R.id.sort_order_size);mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem&& mListType != LIST_TYPE_HIGH_POWER && wheatherShowSystemOption());mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem&& mListType != LIST_TYPE_HIGH_POWER && wheatherShowSystemOption());mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN);// Hide notification menu items, because sorting happens when filteringmOptionsMenu.findItem(R.id.sort_order_recent_notification).setVisible(false);mOptionsMenu.findItem(R.id.sort_order_frequent_notification).setVisible(false);final MenuItem searchItem = mOptionsMenu.findItem(MENU_SEARCH);if (searchItem != null) {searchItem.setVisible(false);}}//hide the optionsmenu of hide-system and show-system in the work interfaceprivate boolean wheatherShowSystemOption() {boolean hasManageProfile = false;List<UserInfo> users = mUserManager.getUsers();android.util.Log.d("xin.wang", "wheatherShowSystemOption: " + users + "<- users.size->" + users.size());for(UserInfo user : users){if (user.isManagedProfile()) {hasManageProfile = true;break;}}if (mIsWorkOnly && !mIsPersonalOnly) {if (!hasManageProfile) {return false;}}return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {int menuId = item.getItemId();int i = item.getItemId();if (i == R.id.sort_order_alpha || i == R.id.sort_order_size) {if (mApplications != null) {mApplications.rebuild(menuId);}} else if (i == R.id.show_system || i == R.id.hide_system) {mShowSystem = !mShowSystem;mApplications.rebuild();} else if (i == R.id.reset_app_preferences) {mResetAppsHelper.buildResetDialog();return true;} else if (i == R.id.advanced) {if (mListType == LIST_TYPE_NOTIFICATION) {new SubSettingLauncher(getContext()).setDestination(ConfigureNotificationSettings.class.getName()).setTitleRes(R.string.configure_notification_settings).setSourceMetricsCategory(getMetricsCategory()).setResultListener(this, ADVANCED_SETTINGS).launch();} else {Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS);startActivityForResult(intent, ADVANCED_SETTINGS);}return true;} else {// Handle the home buttonreturn false;}updateOptionsMenu();return true;}@Overridepublic void onClick(View view) {if (mApplications == null) {return;}final int position = mRecyclerView.getChildAdapterPosition(view);if (position == RecyclerView.NO_POSITION) {Log.w(TAG, "Cannot find position for child, skipping onClick handling");return;}if (mApplications.getApplicationCount() > position) {ApplicationsState.AppEntry entry = mApplications.getAppEntry(position);mCurrentPkgName = entry.info.packageName;mCurrentUid = entry.info.uid;startApplicationDetailsActivity();// We disable the scrolling ability in onMenuItemActionCollapse, we should recover it// if user selects any app item.ViewCompat.setNestedScrollingEnabled(mRecyclerView, true);}}@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {mFilter = mFilterAdapter.getFilter(position);setCompositeFilter();mApplications.setFilter(mFilter);if (DEBUG) {Log.d(TAG, "Selecting filter " + getContext().getText(mFilter.getTitle()));}}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}@Overridepublic boolean onQueryTextSubmit(String query) {return false;}@Overridepublic boolean onQueryTextChange(String newText) {mApplications.filterSearch(newText);return false;}public void updateView() {updateOptionsMenu();final Activity host = getActivity();if (host != null) {host.invalidateOptionsMenu();}}public void setHasDisabled(boolean hasDisabledApps) {if (mListType != LIST_TYPE_MAIN) {return;}mFilterAdapter.setFilterEnabled(FILTER_APPS_ENABLED, hasDisabledApps);mFilterAdapter.setFilterEnabled(FILTER_APPS_DISABLED, hasDisabledApps);}public void setHasInstant(boolean haveInstantApps) {if (LIST_TYPES_WITH_INSTANT.contains(mListType)) {mFilterAdapter.setFilterEnabled(FILTER_APPS_INSTANT, haveInstantApps);}}private void disableToolBarScrollableBehavior() {final CoordinatorLayout.LayoutParams params =(CoordinatorLayout.LayoutParams) mAppBarLayout.getLayoutParams();final AppBarLayout.Behavior behavior = new AppBarLayout.Behavior();behavior.setDragCallback(new AppBarLayout.Behavior.DragCallback() {@Overridepublic boolean canDrag(@NonNull AppBarLayout appBarLayout) {return false;}});params.setBehavior(behavior);}static class FilterSpinnerAdapter extends SettingsSpinnerAdapter<CharSequence> {private final ManageApplications mManageApplications;private final Context mContext;// Use ArrayAdapter for view logic, but have our own list for managing// the options available.private final ArrayList<AppFilterItem> mFilterOptions = new ArrayList<>();public FilterSpinnerAdapter(ManageApplications manageApplications) {super(manageApplications.getContext());mContext = manageApplications.getContext();mManageApplications = manageApplications;}public AppFilterItem getFilter(int position) {return mFilterOptions.get(position);}public void setFilterEnabled(@AppFilterRegistry.FilterType int filter, boolean enabled) {if (enabled) {enableFilter(filter);} else {disableFilter(filter);}}public void enableFilter(@AppFilterRegistry.FilterType int filterType) {final AppFilterItem filter = AppFilterRegistry.getInstance().get(filterType);if (mFilterOptions.contains(filter)) {return;}if (DEBUG) {Log.d(TAG, "Enabling filter " + mContext.getText(filter.getTitle()));}mFilterOptions.add(filter);Collections.sort(mFilterOptions);updateFilterView(mFilterOptions.size() > 1);notifyDataSetChanged();if (mFilterOptions.size() == 1) {if (DEBUG) {Log.d(TAG, "Auto selecting filter " + filter + " " + mContext.getText(filter.getTitle()));}mManageApplications.mFilterSpinner.setSelection(0);mManageApplications.onItemSelected(null, null, 0, 0);}if (mFilterOptions.size() > 1) {final AppFilterItem previousFilter = AppFilterRegistry.getInstance().get(mManageApplications.mFilterType);final int index = mFilterOptions.indexOf(previousFilter);if (index != -1) {android.util.Log.d("xin.wang", "enableFilter: previousFilter -> " + previousFilter + "<- index -> " + index);mManageApplications.mFilterSpinner.setSelection(index);mManageApplications.onItemSelected(null, null, index, 0);}}}public void disableFilter(@AppFilterRegistry.FilterType int filterType) {final AppFilterItem filter = AppFilterRegistry.getInstance().get(filterType);if (!mFilterOptions.remove(filter)) {return;}if (DEBUG) {Log.d(TAG, "Disabling filter " + filter + " " + mContext.getText(filter.getTitle()));}Collections.sort(mFilterOptions);updateFilterView(mFilterOptions.size() > 1);notifyDataSetChanged();if (mManageApplications.mFilter == filter) {if (mFilterOptions.size() > 0) {if (DEBUG) {Log.d(TAG, "Auto selecting filter " + mFilterOptions.get(0)+ mContext.getText(mFilterOptions.get(0).getTitle()));}android.util.Log.d("xin.wang", "disableFilter: Auto selecting filter -> " + mContext.getText(mFilterOptions.get(0).getTitle()));mManageApplications.mFilterSpinner.setSelection(0);mManageApplications.onItemSelected(null, null, 0, 0);}}}@Overridepublic int getCount() {android.util.Log.d("xin.wang", "getCount: mFilterOptions.size()->" + mFilterOptions.size());return mFilterOptions.size();}@Overridepublic CharSequence getItem(int position) {return mContext.getText(mFilterOptions.get(position).getTitle());}@VisibleForTestingvoid updateFilterView(boolean hasFilter) {// If we need to add a floating filter in this screen, we should have an extra top// padding for putting floating filter view. Otherwise, the content of list will be// overlapped by floating filter.if (hasFilter) {mManageApplications.mSpinnerHeader.setVisibility(View.VISIBLE);} else {mManageApplications.mSpinnerHeader.setVisibility(View.GONE);}}}static class ApplicationsAdapter extends RecyclerView.Adapter<ApplicationViewHolder>implements ApplicationsState.Callbacks, AppStateBaseBridge.Callback {private static final String STATE_LAST_SCROLL_INDEX = "state_last_scroll_index";private static final int VIEW_TYPE_APP = 0;private static final int VIEW_TYPE_EXTRA_VIEW = 1;private final ApplicationsState mState;private final ApplicationsState.Session mSession;private final ManageApplications mManageApplications;private final Context mContext;private final AppStateBaseBridge mExtraInfoBridge;private final LoadingViewController mLoadingViewController;private final IconDrawableFactory mIconDrawableFactory;private AppFilterItem mAppFilter;private ArrayList<ApplicationsState.AppEntry> mEntries;private ArrayList<ApplicationsState.AppEntry> mOriginalEntries;private boolean mResumed;private int mLastSortMode = -1;private int mWhichSize = SIZE_TOTAL;private AppFilter mCompositeFilter;private boolean mHasReceivedLoadEntries;private boolean mHasReceivedBridgeCallback;private SearchFilter mSearchFilter;private PowerAllowlistBackend mBackend;private HashSet<String> mSupportAppClone;// This is to remember and restore the last scroll position when this// fragment is paused. We need this special handling because app entries are added gradually// when we rebuild the list after the user made some changes, like uninstalling an app.private int mLastIndex = -1;@VisibleForTestingOnScrollListener mOnScrollListener;private RecyclerView mRecyclerView;public ApplicationsAdapter(ApplicationsState state, ManageApplications manageApplications,AppFilterItem appFilter, Bundle savedInstanceState) {setHasStableIds(true);mState = state;mSession = state.newSession(this);mManageApplications = manageApplications;mLoadingViewController = new LoadingViewController(mManageApplications.mLoadingContainer,mManageApplications.mRecyclerView,mManageApplications.mEmptyView);mContext = manageApplications.getActivity();mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);mAppFilter = appFilter;mBackend = PowerAllowlistBackend.getInstance(mContext);String[] supportApps = mContext.getResources().getStringArray(com.unisoc.internal.R.array.support_app_clone);mSupportAppClone = new HashSet<String>(Arrays.asList(supportApps));android.util.Log.d("xin.wang", "ApplicationsAdapter -> mSupportAppClone -> : " + mSupportAppClone);if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {mExtraInfoBridge = new AppStateNotificationBridge(mContext, mState, this,manageApplications.mUsageStatsManager,manageApplications.mUserManager,manageApplications.mNotificationBackend);} else if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) {mExtraInfoBridge = new AppStateUsageBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_HIGH_POWER) {mBackend.refreshList();mExtraInfoBridge = new AppStatePowerBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_OVERLAY) {mExtraInfoBridge = new AppStateOverlayBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_WRITE_SETTINGS) {mExtraInfoBridge = new AppStateWriteSettingsBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_MANAGE_SOURCES) {mExtraInfoBridge = new AppStateInstallAppsBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_WIFI_ACCESS) {mExtraInfoBridge = new AppStateChangeWifiStateBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_MANAGE_EXTERNAL_STORAGE) {mExtraInfoBridge = new AppStateManageExternalStorageBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_ALARMS_AND_REMINDERS) {mExtraInfoBridge = new AppStateAlarmsAndRemindersBridge(mContext, mState, this);} else if (mManageApplications.mListType == LIST_TYPE_MEDIA_MANAGEMENT_APPS) {mExtraInfoBridge = new AppStateMediaManagementAppsBridge(mContext, mState, this);} else {mExtraInfoBridge = null;}if (savedInstanceState != null) {mLastIndex = savedInstanceState.getInt(STATE_LAST_SCROLL_INDEX);}}@Overridepublic void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {super.onAttachedToRecyclerView(recyclerView);mRecyclerView = recyclerView;mOnScrollListener = new OnScrollListener(this);mRecyclerView.addOnScrollListener(mOnScrollListener);}@Overridepublic void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {super.onDetachedFromRecyclerView(recyclerView);mRecyclerView.removeOnScrollListener(mOnScrollListener);mOnScrollListener = null;mRecyclerView = null;}public void setCompositeFilter(AppFilter compositeFilter) {mCompositeFilter = compositeFilter;rebuild();}public void setFilter(AppFilterItem appFilter) {mAppFilter = appFilter;// Notification filters require resorting the listif (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {if (FILTER_APPS_FREQUENT == appFilter.getFilterType()) {rebuild(R.id.sort_order_frequent_notification);} else if (FILTER_APPS_RECENT == appFilter.getFilterType()) {rebuild(R.id.sort_order_recent_notification);} else if (FILTER_APPS_BLOCKED == appFilter.getFilterType()) {rebuild(R.id.sort_order_alpha);} else {rebuild(R.id.sort_order_alpha);}} else {rebuild();}}public void resume(int sort) {if (DEBUG) Log.i(TAG, "Resume!  mResumed=" + mResumed);if (!mResumed) {mResumed = true;mSession.onResume();mLastSortMode = sort;if (mExtraInfoBridge != null) {mExtraInfoBridge.resume();}rebuild();} else {rebuild(sort);}}public void pause() {if (mResumed) {mResumed = false;mSession.onPause();if (mExtraInfoBridge != null) {mExtraInfoBridge.pause();}}}public void onSaveInstanceState(Bundle outState) {// Record the current scroll position before pausing.final LinearLayoutManager layoutManager =(LinearLayoutManager) mManageApplications.mRecyclerView.getLayoutManager();outState.putInt(STATE_LAST_SCROLL_INDEX, layoutManager.findFirstVisibleItemPosition());}public void release() {mSession.onDestroy();if (mExtraInfoBridge != null) {mExtraInfoBridge.release();}}public void rebuild(int sort) {if (sort == mLastSortMode) {return;}mManageApplications.mSortOrder = sort;mLastSortMode = sort;rebuild();}@Overridepublic ApplicationViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {final View view;if (mManageApplications.mListType == LIST_TYPE_NOTIFICATION) {view = ApplicationViewHolder.newView(parent, true /* twoTarget */);} else {view = ApplicationViewHolder.newView(parent, false /* twoTarget */);}return new ApplicationViewHolder(view);}@Overridepublic int getItemViewType(int position) {return VIEW_TYPE_APP;}public void rebuild() {if (!mHasReceivedLoadEntries|| (mExtraInfoBridge != null && !mHasReceivedBridgeCallback)) {// Don't rebuild the list until all the app entries are loaded.if (DEBUG) {Log.d(TAG, "Not rebuilding until all the app entries loaded."+ " !mHasReceivedLoadEntries=" + !mHasReceivedLoadEntries+ " !mExtraInfoBridgeNull=" + (mExtraInfoBridge != null)+ " !mHasReceivedBridgeCallback=" + !mHasReceivedBridgeCallback);}return;}ApplicationsState.AppFilter filterObj;Comparator<AppEntry> comparatorObj;boolean emulated = Environment.isExternalStorageEmulated();if (emulated) {mWhichSize = SIZE_TOTAL;} else {mWhichSize = SIZE_INTERNAL;}filterObj = mAppFilter.getFilter();if (mCompositeFilter != null) {filterObj = new CompoundFilter(filterObj, mCompositeFilter);}if (!mManageApplications.mShowSystem) {if (LIST_TYPES_WITH_INSTANT.contains(mManageApplications.mListType)) {filterObj = new CompoundFilter(filterObj,ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER_AND_INSTANT);} else {filterObj = new CompoundFilter(filterObj,ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER);}}if (mLastSortMode == R.id.sort_order_size) {switch (mWhichSize) {case SIZE_INTERNAL:comparatorObj = ApplicationsState.INTERNAL_SIZE_COMPARATOR;break;case SIZE_EXTERNAL:comparatorObj = ApplicationsState.EXTERNAL_SIZE_COMPARATOR;break;default:comparatorObj = ApplicationsState.SIZE_COMPARATOR;break;}} else if (mLastSortMode == R.id.sort_order_recent_notification) {comparatorObj = AppStateNotificationBridge.RECENT_NOTIFICATION_COMPARATOR;} else if (mLastSortMode == R.id.sort_order_frequent_notification) {comparatorObj = AppStateNotificationBridge.FREQUENCY_NOTIFICATION_COMPARATOR;} else {comparatorObj = ApplicationsState.ALPHA_COMPARATOR;}final AppFilter finalFilterObj = new CompoundFilter(filterObj,ApplicationsState.FILTER_NOT_HIDE);ThreadUtils.postOnBackgroundThread(() -> {mSession.rebuild(finalFilterObj, comparatorObj, false);});}@VisibleForTestingvoid filterSearch(String query) {if (mSearchFilter == null) {mSearchFilter = new SearchFilter();}// If we haven't load apps list completely, don't filter anything.if (mOriginalEntries == null) {Log.w(TAG, "Apps haven't loaded completely yet, so nothing can be filtered");return;}mSearchFilter.filter(query);}private static boolean packageNameEquals(PackageItemInfo info1, PackageItemInfo info2) {if (info1 == null || info2 == null) {return false;}if (info1.packageName == null || info2.packageName == null) {return false;}return info1.packageName.equals(info2.packageName);}private ArrayList<ApplicationsState.AppEntry> removeDuplicateIgnoringUser(ArrayList<ApplicationsState.AppEntry> entries) {int size = entries.size();// returnList will not have more entries than entriesArrayList<ApplicationsState.AppEntry> returnEntries = new ArrayList<>(size);// assume appinfo of same package but different users are grouped togetherPackageItemInfo lastInfo = null;for (int i = 0; i < size; i++) {AppEntry appEntry = entries.get(i);PackageItemInfo info = appEntry.info;if (!packageNameEquals(lastInfo, appEntry.info)) {returnEntries.add(appEntry);}lastInfo = info;}returnEntries.trimToSize();return returnEntries;}@Overridepublic void onRebuildComplete(ArrayList<AppEntry> entries) {//android.util.Log.d("xin.wang", "onRebuildComplete:-> entries-> " + entries);android.util.Log.d("xin.wang", "哈哈哈onRebuildComplete:-> entries-> " + entries.size());if (DEBUG) {Log.d(TAG, "onRebuildComplete size=" + entries.size());}final int filterType = mAppFilter.getFilterType();if (filterType == FILTER_APPS_POWER_ALLOWLIST|| filterType == FILTER_APPS_POWER_ALLOWLIST_ALL) {entries = removeDuplicateIgnoringUser(entries);android.util.Log.d("xin.wang", "onRebuildComplete: entries -> " + entries.size());}//only show the cloned third-party apps in the interface of workif (mManageApplications.mIsWorkOnly && !mManageApplications.mIsPersonalOnly) {ArrayList<ApplicationsState.AppEntry> cloneEntries = new ArrayList();int cloneNum = 0;for (ApplicationsState.AppEntry entry : entries) {cloneNum ++;android.util.Log.d("xin.wang", "哈哈哈onRebuildComplete: cloneNum -> " + cloneNum);int userId = UserHandle.getUserId(entry.info.uid);UserInfo userInfo = mManageApplications.mUserManager.getUserInfo(userId);boolean isManagedProfile = userInfo.isManagedProfile();if (isManagedProfile) {cloneEntries.add(entry);android.util.Log.d("xin.wang", "isManagedProfile: -> cloneEntries " + cloneEntries + "<- cloneEntries.size() -> " + cloneEntries.size());continue;}boolean isCloneProfile = userInfo.isCloneProfile();boolean contains = mSupportAppClone.contains(entry.info.packageName);android.util.Log.d("xin.wang", "onRebuildComplete: isCloneProfile -> " + isCloneProfile + "<- contains -> " + contains);if (mSupportAppClone.contains(entry.info.packageName) && isCloneProfile) {android.util.Log.d("xin.wang", "onRebuildComplete:mSupportAppClone-> " + mSupportAppClone + "<- entry.info.packageName->" + entry.info.packageName);cloneEntries.add(entry);android.util.Log.d("xin.wang", "mSupportAppClone.contains(entry.info.packageName): ->  cloneEntries " + cloneEntries + "<- cloneEntries.size() -> " + cloneEntries.size());}}mEntries = cloneEntries;android.util.Log.d("xin.wang", "onRebuildComplete:cloneEntries ->  " + cloneEntries + "<- cloneEntries.size() ->  " + cloneEntries.size());mOriginalEntries = cloneEntries;} else {mEntries = entries;android.util.Log.d("xin.wang", "哈哈哈onRebuildComplete: mEntries -> " + mEntries.size());mOriginalEntries = entries;}notifyDataSetChanged();if (getItemCount() == 0) {mLoadingViewController.showEmpty(false /* animate */);} else {mLoadingViewController.showContent(false /* animate */);if (mManageApplications.mSearchView != null&& mManageApplications.mSearchView.isVisibleToUser()) {final CharSequence query = mManageApplications.mSearchView.getQuery();if (!TextUtils.isEmpty(query)) {filterSearch(query.toString());}}}// Restore the last scroll position if the number of entries added so far is bigger than// it.if (mLastIndex != -1 && getItemCount() > mLastIndex) {mManageApplications.mRecyclerView.getLayoutManager().scrollToPosition(mLastIndex);mLastIndex = -1;}if (mManageApplications.mListType == LIST_TYPE_USAGE_ACCESS) {// No enabled or disabled filters for usage access.return;}mManageApplications.setHasDisabled(mState.haveDisabledApps());mManageApplications.setHasInstant(mState.haveInstantApps());}@VisibleForTestingvoid updateLoading() {final boolean appLoaded = mHasReceivedLoadEntries && mSession.getAllApps().size() != 0;if (appLoaded) {mLoadingViewController.showContent(false /* animate */);} else {mLoadingViewController.showLoadingViewDelayed();}}@Overridepublic void onExtraInfoUpdated() {mHasReceivedBridgeCallback = true;rebuild();}@Overridepublic void onRunningStateChanged(boolean running) {mManageApplications.getActivity().setProgressBarIndeterminateVisibility(running);}@Overridepublic void onPackageListChanged() {rebuild();}@Overridepublic void onPackageIconChanged() {// We ensure icons are loaded when their item is displayed, so// don't care about icons loaded in the background.}@Overridepublic void onLoadEntriesCompleted() {mHasReceivedLoadEntries = true;// We may have been skipping rebuilds until this came in, trigger one now.rebuild();}@Overridepublic void onPackageSizeChanged(String packageName) {if (mEntries == null) {return;}final int size = mEntries.size();for (int i = 0; i < size; i++) {final AppEntry entry = mEntries.get(i);android.util.Log.d("xin.wang", "onPackageSizeChanged: -> entry -> " + entry.info.packageName + "<- size -> " + size + "<- mEntries -> " + mEntries);final ApplicationInfo info = entry.info;if (info == null && !TextUtils.equals(packageName, info.packageName)) {continue;}if (TextUtils.equals(mManageApplications.mCurrentPkgName, info.packageName)) {// We got the size information for the last app the// user viewed, and are sorting by size...  they may// have cleared data, so we immediately want to resort// the list with the new size to reflect it to the user.rebuild();return;} else {mOnScrollListener.postNotifyItemChange(i);}}}@Overridepublic void onLauncherInfoChanged() {if (!mManageApplications.mShowSystem) {rebuild();}}@Overridepublic void onAllSizesComputed() {if (mLastSortMode == R.id.sort_order_size) {rebuild();}}@Overridepublic int getItemCount() {if (mEntries == null) {return 0;}android.util.Log.d("xin.wang", "getItemCount: " + mEntries.size());return mEntries.size();}public int getApplicationCount() {return mEntries != null ? mEntries.size() : 0;}public AppEntry getAppEntry(int position) {return mEntries.get(position);}@Overridepublic long getItemId(int position) {if (position == mEntries.size()) {return -1;}return mEntries.get(position).id;}public boolean isEnabled(int position) {if (getItemViewType(position) == VIEW_TYPE_EXTRA_VIEW|| mManageApplications.mListType != LIST_TYPE_HIGH_POWER) {return true;}ApplicationsState.AppEntry entry = mEntries.get(position);return !mBackend.isSysAllowlisted(entry.info.packageName)&& !mBackend.isDefaultActiveApp(entry.info.packageName);}@Overridepublic void onBindViewHolder(ApplicationViewHolder holder, int position) {// Bind the data efficiently with the holderfinal ApplicationsState.AppEntry entry = mEntries.get(position);android.util.Log.d("xin.wang", "onBindViewHolder: ApplicationsState.AppEntry -> " + entry + "<- entry -> ");synchronized (entry) {mState.ensureLabelDescription(entry);holder.setTitle(entry.label, entry.labelDescription);android.util.Log.d("xin.wang", "onBindViewHolder -> entry.label -> : " + entry.label + "<- entry.labelDescription -> " + entry.labelDescription);mState.ensureIcon(entry);holder.setIcon(entry.icon);updateSummary(holder, entry);updateSwitch(holder, entry);holder.updateDisableView(entry.info);}holder.setEnabled(isEnabled(position));holder.itemView.setOnClickListener(mManageApplications);}private void updateSummary(ApplicationViewHolder holder, AppEntry entry) {switch (mManageApplications.mListType) {case LIST_TYPE_NOTIFICATION:if (entry.extraInfo != null&& entry.extraInfo instanceof NotificationsSentState) {holder.setSummary(AppStateNotificationBridge.getSummary(mContext,(NotificationsSentState) entry.extraInfo, mLastSortMode));} else {holder.setSummary(null);}break;case LIST_TYPE_USAGE_ACCESS:if (entry.extraInfo != null&& entry.extraInfo instanceof PermissionState) {holder.setSummary((new UsageState((PermissionState) entry.extraInfo)).isPermissible()? R.string.app_permission_summary_allowed: R.string.app_permission_summary_not_allowed);} else {holder.setSummary(null);}break;case LIST_TYPE_HIGH_POWER:holder.setSummary(HighPowerDetail.getSummary(mContext, entry));break;case LIST_TYPE_OVERLAY:holder.setSummary(DrawOverlayDetails.getSummary(mContext, entry));break;case LIST_TYPE_WRITE_SETTINGS:holder.setSummary(WriteSettingsDetails.getSummary(mContext, entry));break;case LIST_TYPE_MANAGE_SOURCES:holder.setSummary(ExternalSourcesDetails.getPreferenceSummary(mContext, entry));break;case LIST_TYPE_WIFI_ACCESS:holder.setSummary(ChangeWifiStateDetails.getSummary(mContext, entry));break;case LIST_MANAGE_EXTERNAL_STORAGE:holder.setSummary(ManageExternalStorageDetails.getSummary(mContext, entry));break;case LIST_TYPE_ALARMS_AND_REMINDERS:holder.setSummary(AlarmsAndRemindersDetails.getSummary(mContext, entry));break;case LIST_TYPE_MEDIA_MANAGEMENT_APPS:holder.setSummary(MediaManagementAppsDetails.getSummary(mContext, entry));break;default:holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);break;}}private void updateSwitch(ApplicationViewHolder holder, AppEntry entry) {switch (mManageApplications.mListType) {case LIST_TYPE_NOTIFICATION:holder.updateSwitch(((AppStateNotificationBridge) mExtraInfoBridge).getSwitchOnCheckedListener(entry),AppStateNotificationBridge.enableSwitch(entry),AppStateNotificationBridge.checkSwitch(entry));if (entry.extraInfo != null&& entry.extraInfo instanceof NotificationsSentState) {holder.setSummary(AppStateNotificationBridge.getSummary(mContext,(NotificationsSentState) entry.extraInfo, mLastSortMode));} else {holder.setSummary(null);}break;}}public static class OnScrollListener extends RecyclerView.OnScrollListener {private int mScrollState = SCROLL_STATE_IDLE;private boolean mDelayNotifyDataChange;private ApplicationsAdapter mAdapter;public OnScrollListener(ApplicationsAdapter adapter) {mAdapter = adapter;}@Overridepublic void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {mScrollState = newState;if (mScrollState == SCROLL_STATE_IDLE && mDelayNotifyDataChange) {mDelayNotifyDataChange = false;mAdapter.notifyDataSetChanged();}}public void postNotifyItemChange(int index) {if (mScrollState == SCROLL_STATE_IDLE) {mAdapter.notifyItemChanged(index);} else {mDelayNotifyDataChange = true;}}}/*** An array filter that constrains the content of the array adapter with a substring.* Item that does not contains the specified substring will be removed from the list.</p>*/private class SearchFilter extends Filter {@WorkerThread@Overrideprotected FilterResults performFiltering(CharSequence query) {final ArrayList<ApplicationsState.AppEntry> matchedEntries;if (TextUtils.isEmpty(query)) {matchedEntries = mOriginalEntries;} else {matchedEntries = new ArrayList<>();for (ApplicationsState.AppEntry entry : mOriginalEntries) {if (entry.label.toLowerCase().contains(query.toString().toLowerCase())) {matchedEntries.add(entry);}}}final FilterResults results = new FilterResults();results.values = matchedEntries;results.count = matchedEntries.size();return results;}@Overrideprotected void publishResults(CharSequence constraint, FilterResults results) {mEntries = (ArrayList<ApplicationsState.AppEntry>) results.values;notifyDataSetChanged();}}}
}

5、开启手机分身后所有应用的显示

个人区域存放所有应用

工作区域显示双开的应用

实现的逻辑类ProfileSelectManageApplications

/** Copyright (C) 2019 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.dashboard.profileselector;import android.os.Bundle;import androidx.fragment.app.Fragment;import com.android.settings.applications.manageapplications.ManageApplications;/*** Application Setting page for personal/managed profile.*/
public class ProfileSelectManageApplications extends ProfileSelectFragment {@Overridepublic Fragment[] getFragments() {final Bundle workOnly = getArguments() != null ? getArguments().deepCopy() : new Bundle();workOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.WORK);final Fragment workFragment = new ManageApplications();workFragment.setArguments(workOnly);final Bundle personalOnly = getArguments() != null ? getArguments() : new Bundle();personalOnly.putInt(EXTRA_PROFILE, ProfileSelectFragment.ProfileType.PERSONAL);final Fragment personalFragment = new ManageApplications();personalFragment.setArguments(personalOnly);return new Fragment[]{personalFragment, //0workFragment};}
}

【应用分身】下载支持应用分身的应用(QQ),开启应用分身,返回桌面,会出现所有应用的分身。(Unisoc)相关推荐

  1. 王者荣耀战力查询小程序源码下载-支持安卓ios微信和QQ战力查询支持打包成APP

    王者荣耀战力查询小程序源码下载-支持安卓ios微信和QQ战力查询支持打包成APP 该源码没有后台的也无需后台的,所以也就没有什么服务器和域名的烦恼和费用了 使用方法用HBuilder X软件打开文件然 ...

  2. python迅雷远程下载页面_【教程】Chrome浏览器添加迅雷下载支持

    2019年4月28日更新: 目前官方最新版本的迅雷X已经实现自动安装Chrome扩展,无需手动安装. 请仍在使用老版本迅雷的雷友升级到官方最新版本的迅雷X. 以下内容已经过期 最近一段时间,Googl ...

  3. 云开发表情包制作神器微信小程序源码下载,支持各种自定义

    该款小程序是一个表情包制作 内容毕竟丰富,另外自定义制作方面也是特别的自由 支持自主上传图片,自定义文章,另外拥有多种素材模板以供选择 这是一款云开发的小程序,但是安装还是挺简单的 搭建教程: 首先使 ...

  4. 【小程序源码】云开发表情包制作神器微信小程序源码下载,支持各种自定义

    该款小程序是一个表情包制作 内容毕竟丰富,另外自定义制作方面也是特别的自由 支持自主上传图片,自定义文章,另外拥有多种素材模板以供选择 这是一款云开发的小程序,但是安装还是挺简单的 搭建教程: 首先使 ...

  5. 宝宝起名神器微信小程序源码下载支持多种流量主模式

    2022年马上到了,还不知道怎么给虎宝宝取名字嚒 那么这款小程序源码就可以帮到你了 这款小程序支持输入姓氏自动起名,不满意还可以点击换一换来找到满意的 支持起两个字或者三个字的名字 另外小编也给该款小 ...

  6. 小程序源码:全新动态视频壁纸下载支持多种分类短视频另外也有静态壁纸

    这是一款主打动态视频壁纸的一款微信小程序源码 当然啦,里面也是有静态壁纸的 其实这款小程序也可以说是短视频小程序都可以 该款小程序全采集,另外支持多种流量主 大家应该知道小编之前也发过一款动态壁纸的小 ...

  7. 全新实用工具证件照制作微信小程序源码下载支持多种证件生成与制作

    这是一款证件照制作的微信小程序,里面也支持直接微信公众号版本生成安装 支持多种尺寸制作 支持相册上传于直接相机拍摄 支持多种类型的证件制作如,职业证件,公务员证件,身份证等各种类型 支持电子照存档等等 ...

  8. 微软Project Server 2016正式版下载:支持项目组合管理-搜狐

    微软Project Server 2016正式版下载:支持项目组合管理-搜狐 微软Project Server 2016正式版下载:支持项目组合管理-搜狐 posted on 2016-06-13 1 ...

  9. 全新动态视频壁纸微信小程序源码下载支持多种分类短视频另外也有静态壁纸

    这是一款主打动态视频壁纸的一款微信小程序源码 当然啦,里面也是有静态壁纸的 其实这款小程序也可以说是短视频小程序都可以 该款小程序全采集, 大家应该知道小编之前也发过一款动态壁纸的小程序 不过那款是没 ...

最新文章

  1. Linux-CentOS 7 增加root分区容量
  2. C++描述杭电OJ 2012. 素数判定 ||
  3. linux gdb打印内存命令,gdb中查看内存方法总结
  4. Windows Internet Explorer 8 简体中文正式版发布!
  5. linux ip地址本地缓存,ip-address – 如何解析组织的IP地址(使用缓存)
  6. 阿里与百度的网盘中场大战
  7. ffmpeg 结合 ASS字幕制作+特效制作
  8. G480改装固态硬盘、光驱变机械硬盘以及装系统(下)
  9. Bandicam v5.2.1.1860 班迪录屏绿色便携版
  10. 华为android贡献度,从EMUI的6次里程碑事件,看华为对安卓生态的贡献
  11. C4D模型工具—反转法线
  12. MySQL实战第二十二讲-MySQL有哪些“饮鸩止渴”提高性能的方法?
  13. git简明教程 - 协作篇
  14. python 安装失败 errorcode 2203_win10系统安装软件出现the error code is 2203错误怎么办...
  15. java进阶--深入理解Java自动装箱拆箱机制(Autoboxing and unboxing)
  16. 喜欢计算机专业的理由英语,计算机专业的英文自我介绍
  17. DOM4j解析XMl中碰到的问题解决
  18. OPENCV study
  19. 7-文件IO-阻塞与非阻塞IO
  20. 联想小新锐7000安装win10和ubuntu18.04双系统踩坑

热门文章

  1. 厦门理工学院计算机考研难吗,厦门理工学院考研难吗
  2. 程序员现在严重内卷化了!
  3. python电力系统分析_ESP32-S2-Saola-1开发板电路分析
  4. Flash&Flex大全资料大全(转自zrong's blog)
  5. ASS字幕 中的阴影 如何去除,三秒解决
  6. 在OpenHarmony 开发者大会2023,听见百业同鸣
  7. 【R实验.6】基本统计分析
  8. 基于PB实现窗口计算器
  9. CVE-2012-0002
  10. sqli-labs第十六关