package com.ttstd.dialer.manager; import android.annotation.SuppressLint; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.util.Log; import com.tencent.mmkv.MMKV; import com.ttstd.dialer.config.CommonConfig; import com.ttstd.dialer.db.app.AppRepository; import com.ttstd.dialer.db.app.DesktopSortApp; import com.ttstd.dialer.gson.GsonUtils; import com.ttstd.dialer.utils.ApkUtils; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.IntStream; public class AppManager { private static final String TAG = "AppManager"; private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); @SuppressLint("StaticFieldLeak") private static AppManager INSTANCE; private Context mContext; private AppRepository mAppRepository; private Set mProgressCallbacks = new CopyOnWriteArraySet<>(); private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); private static final int CORE_POOL_SIZE = Math.max(2, Math.min(CPU_COUNT - 1, 4)); private static final ExecutorService ASYNC_EXECUTOR = Executors.newFixedThreadPool(CORE_POOL_SIZE); public interface ProgressCallback { void onProgress(String step, int current, int total); void onCompleted(boolean success, String message); } public void addProgressCallback(ProgressCallback progressCallback) { mProgressCallbacks.add(progressCallback); } public static final List DEFAULT_APP_PACKAGES = new ArrayList() {{ this.add("com.android.settings"); this.add("com.android.dialer"); this.add("com.android.camera2"); this.add("com.tencent.mm"); this.add("com.jiangjia.gif"); this.add("com.ss.android.ugc.aweme"); }}; public static void init(Context context) { if (INSTANCE == null) { INSTANCE = new AppManager(context); } } public static AppManager getInstance() { if (INSTANCE == null) { throw new IllegalStateException("You must be init AppManager first"); } return INSTANCE; } private AppManager(Context context) { this.mContext = context.getApplicationContext(); this.mAppRepository = new AppRepository(context); executeAppListProcessing(); } // 异步执行方法 public void executeAppListProcessing() { CompletableFuture .supplyAsync(this::getAllDesktopSortApps, ASYNC_EXECUTOR) .thenComposeAsync(desktopSortApps -> { // 判断获取的应用列表是否为空 if (desktopSortApps == null || desktopSortApps.isEmpty()) { Log.i("AppListProcessor", "检测到桌面应用列表为空,直接插入新应用数据"); return processNewApps() .thenComposeAsync(unused -> updatePosition(), ASYNC_EXECUTOR); } else { return processUninstalledApps(desktopSortApps) .thenComposeAsync(unused -> processNewApps(), ASYNC_EXECUTOR) .thenComposeAsync(unused -> updatePosition(), ASYNC_EXECUTOR); } }, ASYNC_EXECUTOR) .thenComposeAsync(unused -> processNewApps(), ASYNC_EXECUTOR) .exceptionally(throwable -> { // 统一异常处理 Log.e("AppListProcessor", "异步处理失败", throwable); return null; }); } // 第一步:获取所有桌面应用(增加空值安全处理) private List getAllDesktopSortApps() { try { List result = mAppRepository.getAllApp(); return result != null ? result : Collections.emptyList(); } catch (Exception e) { Log.e("AppListProcessor", "获取桌面应用列表失败", e); return Collections.emptyList(); } } private Optional> getAllDesktopSortAppsSafe() { try { return Optional.ofNullable(mAppRepository.getAllApp()) .filter(list -> !list.isEmpty()); } catch (Exception e) { Log.e("AppListProcessor", "获取应用列表失败", e); return Optional.empty(); } } // 第二步:处理未安装的应用(删除操作) - 增加空值检查 private CompletableFuture processUninstalledApps(List desktopSortApps) { return CompletableFuture.runAsync(() -> { if (desktopSortApps == null || desktopSortApps.isEmpty()) { Log.w("AppListProcessor", "桌面应用列表为空,跳过删除处理"); return; } List ids = desktopSortApps.stream() .filter(desktopSortApp -> desktopSortApp != null && !ApkUtils.isInstalled(mContext, desktopSortApp.getPackageName())) .map(desktopSortApp -> { try { return mAppRepository.getIdByPackageAndClass( desktopSortApp.getPackageName(), desktopSortApp.getClassName()); } catch (Exception e) { Log.e("AppListProcessor", "获取应用ID失败: " + desktopSortApp.getPackageName(), e); return -1; // 返回无效ID,后续过滤掉 } }) .filter(id -> id > 0) // 过滤掉无效ID .collect(Collectors.toList()); if (!ids.isEmpty()) { ids.forEach(id -> { try { mAppRepository.deleteById(id); } catch (Exception e) { Log.e("AppListProcessor", "删除应用失败, ID: " + id, e); } }); Log.i("AppListProcessor", "成功删除 " + ids.size() + " 个未安装应用"); } }, ASYNC_EXECUTOR); } // 第三步:处理新应用(插入操作) - 增加空值和异常处理 private CompletableFuture processNewApps() { return CompletableFuture.runAsync(() -> { try { List resolveInfos = ApkUtils.getAllLauncherResolveInfo(mContext); if (resolveInfos.isEmpty()) { Log.w("AppListProcessor", "未获取到启动器应用列表"); return; } List appList = resolveInfos.stream() .filter(Objects::nonNull) .map(resolveInfo -> { try { String packageName = resolveInfo.activityInfo.packageName; String className = resolveInfo.activityInfo.name; ComponentName componentName = new ComponentName(packageName, className); return new DesktopSortApp(mContext, componentName); } catch (Exception e) { Log.e("AppListProcessor", "创建DesktopSortApp失败", e); return null; } }) .filter(Objects::nonNull) .sorted(new Comparator() { @Override public int compare(DesktopSortApp o1, DesktopSortApp o2) { return Collator.getInstance(Locale.CHINESE).compare(o1.getLabel(), o2.getLabel()); } }) .collect(Collectors.toList()); List filterApp = appList.stream() .filter(desktopSortApp -> ApkUtils.isInstalled(mContext, desktopSortApp.getPackageName())) .filter(desktopSortApp -> { try { return mAppRepository.checkAppInfoExists( desktopSortApp.getPackageName(), desktopSortApp.getClassName()) <= 0; } catch (Exception e) { Log.e("AppListProcessor", "检查应用存在性失败", e); return false; } }) .collect(Collectors.toList()); if (!filterApp.isEmpty()) { filterApp.forEach(desktopSortApp -> { desktopSortApp.setPosition(mAppRepository.getTotalCount()); try { mAppRepository.insert(desktopSortApp); } catch (Exception e) { Log.e("AppListProcessor", "插入应用失败: " + desktopSortApp.getPackageName(), e); } }); Log.i("AppListProcessor", "成功插入 " + filterApp.size() + " 个新应用"); } else { Log.i("AppListProcessor", "没有需要插入的新应用"); } } catch (Exception e) { Log.e("AppListProcessor", "处理新应用时发生异常", e); } }, ASYNC_EXECUTOR); } // 第四步:更新应用位置(您提供的方法优化) private CompletableFuture updatePosition() { return CompletableFuture.runAsync(() -> { try { List desktopSortApps = getAllDesktopSortApps(); if (desktopSortApps == null || desktopSortApps.isEmpty()) { Log.w("AppListProcessor", "无应用数据,跳过位置更新"); return; } // 使用Lambda简化代码 List sortedApps = desktopSortApps.stream() .filter(Objects::nonNull) .sorted((o1, o2) -> Integer.compare(o1.getPosition(), o2.getPosition())) .collect(Collectors.toList()); // 批量更新位置 IntStream.range(0, sortedApps.size()) .forEach(index -> { DesktopSortApp desktopSortApp = sortedApps.get(index); desktopSortApp.setPosition(index); try { mAppRepository.update(desktopSortApp); } catch (Exception e) { Log.e("AppListProcessor", "更新应用位置失败: " + desktopSortApp.getPackageName(), e); } }); Log.i("AppListProcessor", "成功更新 " + sortedApps.size() + " 个应用的位置"); } catch (Exception e) { Log.e("AppListProcessor", "更新应用位置时发生异常", e); } }, ASYNC_EXECUTOR); } public void updateApp(String packageName) { List resolveInfos = ApkUtils.getResolveInfoByPackageName(mContext, packageName); if (!resolveInfos.isEmpty()) { resolveInfos.stream().map(new Function() { @Override public DesktopSortApp apply(ResolveInfo resolveInfo) { String packageName = resolveInfo.activityInfo.packageName; String className = resolveInfo.activityInfo.name; ComponentName componentName = new ComponentName(packageName, className); return new DesktopSortApp(mContext, componentName); } }).filter(new Predicate() { @Override public boolean test(DesktopSortApp desktopSortApp) { return mAppRepository.checkAppInfoExists(desktopSortApp.getPackageName(), desktopSortApp.getClassName()) <= 0; } }).forEach(new Consumer() { @Override public void accept(DesktopSortApp desktopSortApp) { desktopSortApp.setPosition(mAppRepository.getTotalCount()); mAppRepository.insert(desktopSortApp); } }); } } public void getAllApp() { List desktopSortApps = mAppRepository.getAllApp(); List ids = desktopSortApps.stream().filter(new Predicate() { @Override public boolean test(DesktopSortApp desktopSortApp) { return !ApkUtils.isInstalled(mContext, desktopSortApp.getPackageName()); } }).map(new java.util.function.Function() { @Override public Integer apply(DesktopSortApp desktopSortApp) { return mAppRepository.getIdByPackageAndClass(desktopSortApp.getPackageName(), desktopSortApp.getClassName()); } }).collect(Collectors.toList()); ids.stream().forEach(new Consumer() { @Override public void accept(Integer integer) { mAppRepository.deleteById(integer); } }); List resolveInfos = ApkUtils.getAllLauncherResolveInfo(mContext); List appList = resolveInfos.stream().map(new Function() { @Override public ComponentName apply(ResolveInfo resolveInfo) { String packageName = resolveInfo.activityInfo.packageName; String className = resolveInfo.activityInfo.name; ComponentName componentName = new ComponentName(packageName, className); return componentName; } }).map(new Function() { @Override public DesktopSortApp apply(ComponentName componentName) { DesktopSortApp desktopSortApp = new DesktopSortApp(mContext, componentName); return desktopSortApp; } }).collect(Collectors.toList()); List filterApp = appList.stream().filter(new Predicate() { @Override public boolean test(DesktopSortApp desktopSortApp) { return ApkUtils.isInstalled(mContext, desktopSortApp.getPackageName()); } }).filter(new Predicate() { @Override public boolean test(DesktopSortApp desktopSortApp) { return mAppRepository.checkAppInfoExists(desktopSortApp.getPackageName(), desktopSortApp.getClassName()) > 0; } }).collect(Collectors.toList()); filterApp.stream().forEach(new Consumer() { @Override public void accept(DesktopSortApp desktopSortApp) { mAppRepository.insert(desktopSortApp); } }); } public String getDefaultAppList() { PackageManager packageManager = mContext.getPackageManager(); List resolveInfos = ApkUtils.getAllLauncherResolveInfo(mContext); List filter = resolveInfos.stream().filter(new Predicate() { @Override public boolean test(ResolveInfo resolveInfo) { return DEFAULT_APP_PACKAGES.contains(resolveInfo.activityInfo.packageName); } }).sorted(new Comparator() { @Override public int compare(ResolveInfo o1, ResolveInfo o2) { return Collator.getInstance(Locale.CHINESE).compare(o1.activityInfo.loadLabel(packageManager), o2.activityInfo.loadLabel(packageManager)); } }).collect(Collectors.toList()); List desktopSortApps = filter.stream().map(new Function() { @Override public DesktopSortApp apply(ResolveInfo resolveInfo) { ComponentName componentName = new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name); return new DesktopSortApp(mContext, componentName); } }).sorted(new Comparator() { @Override public int compare(DesktopSortApp o1, DesktopSortApp o2) { return Boolean.compare(ApkUtils.isSystemApp(mContext, o2.getPackageName()), ApkUtils.isSystemApp(mContext, o1.getPackageName())); } }).collect(Collectors.toCollection(LinkedList::new)); for (int i = 0; i < desktopSortApps.size(); i++) { DesktopSortApp desktopSortApp = desktopSortApps.get(i); desktopSortApp.setPosition(i); } return GsonUtils.toJSONString(desktopSortApps); } }