563 lines
25 KiB
Java
563 lines
25 KiB
Java
package com.ttstd.dialer.manager;
|
||
|
||
import android.annotation.SuppressLint;
|
||
import android.app.usage.StorageStats;
|
||
import android.app.usage.StorageStatsManager;
|
||
import android.content.ComponentName;
|
||
import android.content.Context;
|
||
import android.content.pm.PackageInfo;
|
||
import android.content.pm.PackageManager;
|
||
import android.content.pm.ResolveInfo;
|
||
import android.os.Build;
|
||
import android.os.UserHandle;
|
||
import android.util.Log;
|
||
|
||
import com.tencent.mmkv.MMKV;
|
||
import com.ttstd.dialer.bean.ApkInstalledInfo;
|
||
import com.ttstd.dialer.config.CommonConfig;
|
||
import com.ttstd.dialer.config.LiveDataAction;
|
||
import com.ttstd.dialer.db.app.AppInfo;
|
||
import com.ttstd.dialer.db.app.AppRepository;
|
||
import com.ttstd.dialer.gson.GsonUtils;
|
||
import com.ttstd.dialer.livedata.LiveDataBus;
|
||
import com.ttstd.dialer.utils.ApkUtils;
|
||
import com.ttstd.dialer.utils.HashUtils;
|
||
import com.ttstd.dialer.utils.Logger;
|
||
|
||
import java.io.File;
|
||
import java.text.Collator;
|
||
import java.util.ArrayList;
|
||
import java.util.Collections;
|
||
import java.util.Comparator;
|
||
import java.util.HashSet;
|
||
import java.util.LinkedList;
|
||
import java.util.List;
|
||
import java.util.Locale;
|
||
import java.util.Objects;
|
||
import java.util.Set;
|
||
import java.util.UUID;
|
||
import java.util.concurrent.CompletableFuture;
|
||
import java.util.concurrent.CopyOnWriteArraySet;
|
||
import java.util.concurrent.ExecutorService;
|
||
import java.util.concurrent.Executors;
|
||
import java.util.function.Function;
|
||
import java.util.function.IntConsumer;
|
||
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 static final String STEP_FIRST_INIT = "首次初始化应用数据";
|
||
private static final String STEP_REMOVE_UNINSTALLED = "移除未安装应用";
|
||
private static final String STEP_ADD_NEW_APPS = "添加新安装应用";
|
||
private static final String STEP_UPDATE_POSITION = "更新应用位置";
|
||
private static final int TOTAL_STEPS_NORMAL = 3; // 正常流程总步骤
|
||
private static final int TOTAL_STEPS_FIRST = 2; // 首次初始化总步骤
|
||
|
||
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
|
||
|
||
@SuppressLint("StaticFieldLeak")
|
||
private static volatile AppManager INSTANCE;
|
||
private Context mContext;
|
||
private PackageManager mPackageManager;
|
||
|
||
private AppRepository mAppRepository;
|
||
|
||
private Set<ProgressCallback> 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) {
|
||
if (progressCallback != null) {
|
||
mProgressCallbacks.add(progressCallback);
|
||
}
|
||
}
|
||
|
||
public void removeProgressCallback(ProgressCallback progressCallback) {
|
||
mProgressCallbacks.remove(progressCallback);
|
||
}
|
||
|
||
public static final List<String> DEFAULT_APP_PACKAGES = new ArrayList<String>() {{
|
||
this.add("com.android.dialer");
|
||
this.add("com.android.contacts");
|
||
this.add("com.android.messaging");
|
||
this.add("com.android.settings");
|
||
this.add("com.android.camera2");
|
||
|
||
this.add("com.tencent.mm");
|
||
this.add("com.jiangjia.gif");
|
||
this.add("com.ss.android.ugc.aweme");
|
||
}};
|
||
|
||
public static final Set<String> DEFAULT_DIALER_PACKAGE = new HashSet<String>() {{
|
||
this.add("com.android.dialer");
|
||
}};
|
||
|
||
public static final Set<String> DEFAULT_CONTACT_PACKAGE = new HashSet<String>() {{
|
||
this.add("com.android.contacts");
|
||
}};
|
||
|
||
public static final Set<String> DEFAULT_MESSAGE_PACKAGE = new HashSet<String>() {{
|
||
this.add("com.android.messaging");
|
||
}};
|
||
|
||
public static final Set<String> DEFAULT_SETTINGS_PACKAGE = new HashSet<String>() {{
|
||
this.add("com.android.settings");
|
||
}};
|
||
|
||
|
||
public static void init(Context context) {
|
||
if (INSTANCE == null) {
|
||
synchronized (AppManager.class) {
|
||
if (INSTANCE == null) {
|
||
INSTANCE = new AppManager(context);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
public static AppManager getInstance() {
|
||
if (INSTANCE == null) {
|
||
throw new IllegalStateException("You must first initialize the AppManager");
|
||
}
|
||
return INSTANCE;
|
||
}
|
||
|
||
private AppManager(Context context) {
|
||
this.mContext = context.getApplicationContext();
|
||
this.mAppRepository = new AppRepository(context);
|
||
this.mPackageManager = mContext.getPackageManager();
|
||
executeAppListProcessing();
|
||
}
|
||
|
||
// 通知进度回调
|
||
private void notifyProgress(String step, int current, int total) {
|
||
mProgressCallbacks.forEach(callback -> callback.onProgress(step, current, total));
|
||
}
|
||
|
||
// 通知完成回调
|
||
private void notifyCompleted(boolean success, String message) {
|
||
mProgressCallbacks.forEach(callback -> callback.onCompleted(success, message));
|
||
}
|
||
|
||
// 异步执行应用列表处理流程
|
||
public void executeAppListProcessing() {
|
||
CompletableFuture
|
||
.supplyAsync(this::getAllDesktopSortApps, ASYNC_EXECUTOR)
|
||
.thenComposeAsync(desktopApps -> {
|
||
// 根据应用列表是否为空,选择不同处理流程
|
||
if (desktopApps.isEmpty()) {
|
||
// 首次初始化流程:首次数据加载 -> 更新位置
|
||
return processFirstTimeApps()
|
||
.thenComposeAsync(unused -> {
|
||
notifyProgress(STEP_UPDATE_POSITION, 2, TOTAL_STEPS_FIRST);
|
||
return updatePosition();
|
||
}, ASYNC_EXECUTOR);
|
||
} else {
|
||
// 正常流程:移除未安装 -> 添加新应用 -> 更新位置
|
||
return processUninstalledApps(desktopApps)
|
||
.thenComposeAsync(unused -> {
|
||
notifyProgress(STEP_ADD_NEW_APPS, 2, TOTAL_STEPS_NORMAL);
|
||
return processNewApps();
|
||
}, ASYNC_EXECUTOR)
|
||
.thenComposeAsync(unused -> {
|
||
notifyProgress(STEP_UPDATE_POSITION, 3, TOTAL_STEPS_NORMAL);
|
||
return updatePosition();
|
||
}, ASYNC_EXECUTOR);
|
||
}
|
||
}, ASYNC_EXECUTOR)
|
||
.thenRun(() -> notifyCompleted(true, "应用列表处理完成"))
|
||
.exceptionally(throwable -> {
|
||
Logger.e(TAG, "异步处理失败", throwable);
|
||
notifyCompleted(false, "处理失败: " + throwable.getMessage());
|
||
return null;
|
||
});
|
||
}
|
||
|
||
// 第一步:获取所有桌面应用(空值安全处理)
|
||
private List<AppInfo> getAllDesktopSortApps() {
|
||
try {
|
||
List<AppInfo> result = mAppRepository.getAllApp();
|
||
return result != null ? result : Collections.emptyList();
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "获取桌面应用列表失败", e);
|
||
return Collections.emptyList();
|
||
}
|
||
}
|
||
|
||
// 首次初始化应用数据(针对首次获取为空的场景)
|
||
private CompletableFuture<Void> processFirstTimeApps() {
|
||
return CompletableFuture.runAsync(() -> {
|
||
notifyProgress(STEP_FIRST_INIT, 1, TOTAL_STEPS_FIRST);
|
||
Logger.i(TAG, "进入首次应用数据初始化流程");
|
||
|
||
try {
|
||
// 获取所有可启动应用
|
||
List<ResolveInfo> allLauncherApps = ApkUtils.getAllLauncherResolveInfo(mContext);
|
||
if (allLauncherApps.isEmpty()) {
|
||
Logger.w(TAG, "未获取到任何可启动应用,无法完成首次初始化");
|
||
return;
|
||
}
|
||
|
||
List<AppInfo> allFirstApps = allLauncherApps.stream()
|
||
.filter(Objects::nonNull)
|
||
.map(this::resolveInfoToDesktopApp)
|
||
.filter(Objects::nonNull)
|
||
.sorted((o1, o2) -> Boolean.compare(ApkUtils.isSystemApp(mContext, o2.getPackageName()), ApkUtils.isSystemApp(mContext, o1.getPackageName())))
|
||
.sorted(getAppComparator())
|
||
.collect(Collectors.toList());
|
||
|
||
final int[] hotseatCounter = {0};
|
||
IntStream.range(0, allFirstApps.size())
|
||
.forEach(new IntConsumer() {
|
||
@Override
|
||
public void accept(int index) {
|
||
AppInfo appInfo = allFirstApps.get(index);
|
||
if (DEFAULT_APP_PACKAGES.contains(appInfo.getPackageName())) {
|
||
appInfo.setOutside(1);
|
||
} else {
|
||
appInfo.setOutside(0);
|
||
}
|
||
|
||
if (DEFAULT_DIALER_PACKAGE.contains(appInfo.getPackageName())) {
|
||
appInfo.setHotseat(1);
|
||
appInfo.setHotseatPosition(hotseatCounter[0]++);
|
||
} else if (DEFAULT_CONTACT_PACKAGE.contains(appInfo.getPackageName())) {
|
||
appInfo.setHotseat(1);
|
||
appInfo.setHotseatPosition(hotseatCounter[0]++);
|
||
} else if (DEFAULT_MESSAGE_PACKAGE.contains(appInfo.getPackageName())) {
|
||
appInfo.setHotseat(1);
|
||
appInfo.setHotseatPosition(hotseatCounter[0]++);
|
||
} else if (DEFAULT_SETTINGS_PACKAGE.contains(appInfo.getPackageName())) {
|
||
appInfo.setHotseat(1);
|
||
appInfo.setHotseatPosition(hotseatCounter[0]++);
|
||
} else {
|
||
appInfo.setHotseat(0);
|
||
appInfo.setHotseatPosition(0);
|
||
}
|
||
|
||
appInfo.setPosition(index);
|
||
}
|
||
});
|
||
|
||
// 批量插入首次数据
|
||
allFirstApps.forEach(app -> {
|
||
try {
|
||
mAppRepository.insert(app);
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "首次初始化插入应用失败: " + app.getPackageName(), e);
|
||
}
|
||
});
|
||
|
||
Logger.i(TAG, "首次初始化完成,插入默认应用: " + allFirstApps.size() + " 个");
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "首次应用数据初始化失败", e);
|
||
throw new RuntimeException("首次初始化失败", e); // 抛出异常触发回调
|
||
}
|
||
}, ASYNC_EXECUTOR);
|
||
}
|
||
|
||
// 处理未安装的应用(删除操作)
|
||
private CompletableFuture<Void> processUninstalledApps(List<AppInfo> appInfos) {
|
||
return CompletableFuture.runAsync(() -> {
|
||
notifyProgress(STEP_REMOVE_UNINSTALLED, 1, TOTAL_STEPS_NORMAL);
|
||
if (appInfos.isEmpty()) {
|
||
Logger.w(TAG, "桌面应用列表为空,跳过删除处理");
|
||
return;
|
||
}
|
||
|
||
List<Integer> ids = appInfos.stream()
|
||
.filter(Objects::nonNull)
|
||
.filter(app -> !ApkUtils.isInstalled(mContext, app.getPackageName()))
|
||
.map(app -> {
|
||
try {
|
||
return mAppRepository.getIdByPackageAndClass(app.getPackageName(), app.getClassName());
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "获取应用ID失败: " + app.getPackageName(), e);
|
||
return -1;
|
||
}
|
||
})
|
||
.filter(id -> id > 0)
|
||
.collect(Collectors.toList());
|
||
|
||
if (!ids.isEmpty()) {
|
||
ids.forEach(id -> {
|
||
try {
|
||
mAppRepository.deleteById(id);
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "删除应用失败, ID: " + id, e);
|
||
}
|
||
});
|
||
Logger.i(TAG, "成功删除 " + ids.size() + " 个未安装应用");
|
||
}
|
||
}, ASYNC_EXECUTOR);
|
||
}
|
||
|
||
// 处理新安装的应用(插入操作)- 非首次场景
|
||
private CompletableFuture<Void> processNewApps() {
|
||
return CompletableFuture.runAsync(() -> {
|
||
try {
|
||
List<ResolveInfo> resolveInfos = ApkUtils.getAllLauncherResolveInfo(mContext);
|
||
if (resolveInfos.isEmpty()) {
|
||
Logger.w(TAG, "未获取到启动器应用列表,跳过新应用处理");
|
||
return;
|
||
}
|
||
|
||
List<AppInfo> newApps = resolveInfos.stream()
|
||
.filter(Objects::nonNull)
|
||
.map(this::resolveInfoToDesktopApp)
|
||
.filter(Objects::nonNull)
|
||
.filter(app -> ApkUtils.isInstalled(mContext, app.getPackageName()))
|
||
.filter(app -> !isAppExists(app)) // 过滤已存在的应用
|
||
.sorted(getAppComparator())
|
||
.collect(Collectors.toList());
|
||
|
||
if (!newApps.isEmpty()) {
|
||
newApps.forEach(app -> app.setPosition(mAppRepository.getTotalCount()));
|
||
newApps.forEach(app -> {
|
||
try {
|
||
mAppRepository.insert(app);
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "插入新应用失败: " + app.getPackageName(), e);
|
||
}
|
||
});
|
||
Logger.i(TAG, "成功插入 " + newApps.size() + " 个新应用");
|
||
} else {
|
||
Logger.i(TAG, "没有需要插入的新应用");
|
||
}
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "处理新应用时发生异常", e);
|
||
throw new RuntimeException("新应用处理失败", e);
|
||
}
|
||
}, ASYNC_EXECUTOR);
|
||
}
|
||
|
||
// 更新应用位置
|
||
private CompletableFuture<Void> updatePosition() {
|
||
return CompletableFuture.runAsync(() -> {
|
||
try {
|
||
List<AppInfo> appInfos = getAllDesktopSortApps();
|
||
if (appInfos.isEmpty()) {
|
||
Logger.w(TAG, "无应用数据,跳过位置更新");
|
||
return;
|
||
}
|
||
|
||
List<AppInfo> sortedApps = appInfos.stream()
|
||
.filter(Objects::nonNull)
|
||
.sorted(Comparator.comparingInt(AppInfo::getPosition))
|
||
.collect(Collectors.toList());
|
||
|
||
IntStream.range(0, sortedApps.size())
|
||
.forEach(index -> {
|
||
AppInfo app = sortedApps.get(index);
|
||
app.setPosition(index);
|
||
try {
|
||
mAppRepository.update(app);
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "更新应用位置失败: " + app.getPackageName(), e);
|
||
}
|
||
});
|
||
Logger.i(TAG, "成功更新 " + sortedApps.size() + " 个应用的位置");
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "更新应用位置时发生异常", e);
|
||
throw new RuntimeException("位置更新失败", e);
|
||
}
|
||
}, ASYNC_EXECUTOR);
|
||
}
|
||
|
||
// 工具方法:ResolveInfo转换为DesktopSortApp
|
||
private AppInfo resolveInfoToDesktopApp(ResolveInfo resolveInfo) {
|
||
ComponentName component = new ComponentName(
|
||
resolveInfo.activityInfo.packageName,
|
||
resolveInfo.activityInfo.name
|
||
);
|
||
return new AppInfo(mContext, component);
|
||
}
|
||
|
||
// 工具方法:检查应用是否已存在
|
||
private boolean isAppExists(AppInfo app) {
|
||
try {
|
||
return mAppRepository.checkAppInfoExists(app.getPackageName(), app.getClassName()) > 0;
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "检查应用存在性失败: " + app.getPackageName(), e);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 工具方法:获取应用排序器(统一排序逻辑)
|
||
private Comparator<AppInfo> getAppComparator() {
|
||
return Comparator.comparing(AppInfo::getLabel, Collator.getInstance(Locale.CHINESE));
|
||
}
|
||
|
||
public void updateApp(String packageName) {
|
||
boolean isInstalled = ApkUtils.isInstalled(mContext, packageName);
|
||
|
||
if (isInstalled) {
|
||
Logger.i(TAG, "应用已安装: " + packageName + ", 开始更新数据库");
|
||
|
||
List<ResolveInfo> resolveInfos = ApkUtils.getResolveInfoByPackageName(mContext, packageName);
|
||
|
||
if (!resolveInfos.isEmpty()) {
|
||
resolveInfos.stream()
|
||
.map(this::resolveInfoToDesktopApp)
|
||
.filter(Objects::nonNull)
|
||
.forEach(app -> {
|
||
try {
|
||
int existingId = mAppRepository.getIdByPackageAndClass(app.getPackageName(), app.getClassName());
|
||
|
||
if (existingId > 0) {
|
||
// app.setId(existingId);
|
||
// mAppRepository.update(app);
|
||
// Logger.i(TAG, "更新应用信息: " + app.getPackageName());
|
||
} else {
|
||
app.setOutside(1);
|
||
app.setPosition(mAppRepository.getTotalCount());
|
||
mAppRepository.insert(app);
|
||
Logger.i(TAG, "新增应用信息: " + app.getPackageName());
|
||
}
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "处理应用失败: " + app.getPackageName(), e);
|
||
}
|
||
});
|
||
} else {
|
||
Logger.w(TAG, "应用已安装但无可启动的 Launcher Activity");
|
||
}
|
||
} else {
|
||
Logger.i(TAG, "应用未安装或被禁用: " + packageName + ", 开始删除数据库数据");
|
||
|
||
try {
|
||
List<AppInfo> allApps = mAppRepository.getAllApp();
|
||
if (allApps != null) {
|
||
List<Integer> idsToDelete = allApps.stream()
|
||
.filter(app -> packageName.equals(app.getPackageName()))
|
||
.map(AppInfo::getId)
|
||
.filter(id -> id > 0)
|
||
.collect(Collectors.toList());
|
||
|
||
if (!idsToDelete.isEmpty()) {
|
||
idsToDelete.forEach(id -> {
|
||
try {
|
||
mAppRepository.deleteById(id);
|
||
Logger.i(TAG, "删除应用数据库记录, ID: " + id);
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "删除应用记录失败, ID: " + id, e);
|
||
}
|
||
});
|
||
Logger.i(TAG, "成功删除 " + idsToDelete.size() + " 条记录");
|
||
} else {
|
||
Logger.i(TAG, "数据库中未找到该应用的记录");
|
||
}
|
||
}
|
||
} catch (Exception e) {
|
||
Logger.e(TAG, "删除应用记录时发生异常", e);
|
||
}
|
||
}
|
||
|
||
LiveDataBus.get().send(LiveDataAction.ACTION_UPDATE_APPS, TAG);
|
||
}
|
||
|
||
|
||
// 重构getAllApp方法,复用现有处理逻辑
|
||
public void refreshAllApps() {
|
||
CompletableFuture.runAsync(() -> {
|
||
List<AppInfo> allApps = getAllDesktopSortApps();
|
||
if (allApps.isEmpty()) {
|
||
processFirstTimeApps().join();
|
||
} else {
|
||
processUninstalledApps(allApps).join();
|
||
processNewApps().join();
|
||
}
|
||
updatePosition().join();
|
||
}, ASYNC_EXECUTOR);
|
||
}
|
||
|
||
public String getDefaultAppList() {
|
||
List<ResolveInfo> resolveInfos = ApkUtils.getAllLauncherResolveInfo(mContext);
|
||
|
||
List<AppInfo> defaultApps = resolveInfos.stream()
|
||
.filter(ri -> DEFAULT_APP_PACKAGES.contains(ri.activityInfo.packageName))
|
||
.sorted((o1, o2) -> Collator.getInstance(Locale.CHINESE)
|
||
.compare(o1.activityInfo.loadLabel(mPackageManager), o2.activityInfo.loadLabel(mPackageManager)))
|
||
.map(ri -> new ComponentName(ri.activityInfo.packageName, ri.activityInfo.name))
|
||
.map(component -> new AppInfo(mContext, component))
|
||
.sorted((a, b) -> Boolean.compare(
|
||
ApkUtils.isSystemApp(mContext, b.getPackageName()),
|
||
ApkUtils.isSystemApp(mContext, a.getPackageName())))
|
||
.collect(Collectors.toCollection(LinkedList::new));
|
||
|
||
IntStream.range(0, defaultApps.size())
|
||
.forEach(i -> defaultApps.get(i).setPosition(i));
|
||
|
||
return GsonUtils.toJSONString(defaultApps);
|
||
}
|
||
|
||
private static final Set<String> WHITE_SYSTEM_PACKAGES = new HashSet<String>() {{
|
||
// this.add("com.android.luancher3");
|
||
}};
|
||
|
||
public List<ApkInstalledInfo> getApkInstallInfos() {
|
||
StorageStatsManager ssm = mContext.getSystemService(StorageStatsManager.class);
|
||
// 获取所有已安装的应用
|
||
List<PackageInfo> installedApps = mPackageManager.getInstalledPackages(0);
|
||
// 遍历并筛选第三方应用
|
||
List<ApkInstalledInfo> apkInstalledInfos = installedApps.stream().filter(new Predicate<PackageInfo>() {
|
||
@Override
|
||
public boolean test(PackageInfo packageInfo) {
|
||
String packageName = packageInfo.packageName;
|
||
return !ApkUtils.isSystemApp(mContext, packageName) || WHITE_SYSTEM_PACKAGES.contains(packageName);
|
||
}
|
||
}).map(new Function<PackageInfo, ApkInstalledInfo>() {
|
||
@Override
|
||
public ApkInstalledInfo apply(PackageInfo packageInfo) {
|
||
ApkInstalledInfo apkInstalledInfo = new ApkInstalledInfo();
|
||
apkInstalledInfo.setPackageName(packageInfo.packageName);
|
||
apkInstalledInfo.setAppName(packageInfo.applicationInfo.loadLabel(mPackageManager).toString());
|
||
apkInstalledInfo.setVersionName(packageInfo.versionName);
|
||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||
apkInstalledInfo.setVersionCode(packageInfo.getLongVersionCode());
|
||
} else {
|
||
apkInstalledInfo.setVersionCode(packageInfo.versionCode);
|
||
}
|
||
apkInstalledInfo.setInstallTime(packageInfo.firstInstallTime);
|
||
apkInstalledInfo.setLastUpdateTime(packageInfo.lastUpdateTime);
|
||
|
||
try {
|
||
StorageStats stats = ssm.queryStatsForPackage(
|
||
UUID.fromString(packageInfo.applicationInfo.storageUuid.toString()),
|
||
mContext.getPackageName(),
|
||
UserHandle.of(UserHandle.myUserId())
|
||
);
|
||
|
||
long appSize = stats.getAppBytes(); // 应用大小
|
||
Log.e(TAG, "apply: appSize = " + appSize);
|
||
long dataSize = stats.getDataBytes(); // 用户数据
|
||
long cacheSize = stats.getCacheBytes(); // 缓存
|
||
|
||
apkInstalledInfo.setApkSize(appSize);
|
||
apkInstalledInfo.setDataSize(dataSize);
|
||
apkInstalledInfo.setCacheSize(cacheSize);
|
||
} catch (Exception e) {
|
||
Log.e(TAG, "getApkInstallInfos: " + e.getMessage());
|
||
}
|
||
|
||
Log.e(TAG, "apply: " + packageInfo.applicationInfo.publicSourceDir);
|
||
Log.e(TAG, "apply: publicSourceDir = " + new File(packageInfo.applicationInfo.publicSourceDir).length());
|
||
Log.e(TAG, "apply: " + packageInfo.applicationInfo.dataDir);
|
||
apkInstalledInfo.setMd5(HashUtils.getFileMd5(new File(packageInfo.applicationInfo.publicSourceDir)));
|
||
apkInstalledInfo.setSystemApp(ApkUtils.isSystemApp(mContext, packageInfo.packageName));
|
||
return apkInstalledInfo;
|
||
}
|
||
}).collect(Collectors.toList());
|
||
return apkInstalledInfos;
|
||
}
|
||
} |