content: package dev.utils.app.info;
  
  import android.content.Intent;
  import android.content.pm.ApplicationInfo;
  import android.content.pm.PackageInfo;
  import android.content.pm.PackageManager;
  import android.content.pm.PermissionGroupInfo;
  import android.content.pm.PermissionInfo;
  import android.content.pm.ResolveInfo;
  import android.os.Build;
  
  import androidx.annotation.RequiresApi;
  
  import java.io.File;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Set;
  
  import dev.utils.DevFinal;
  import dev.utils.LogPrintUtils;
  import dev.utils.app.AppUtils;
  import dev.utils.common.FileUtils;
  import dev.utils.common.ForUtils;
  
  /**
   * detail: APP 信息获取工具类
   * @author Ttt
   * <pre>
   *     Android 11 ( R ) 适配
   *     @see <a href="https://developer.android.com/about/versions/11/privacy/package-visibility"/>
   *     <p></p>
   *     Android 11 ( R ) 需要加该权限 ( 无需申请 ) 才能够获取安装列表
   *     <uses-permission
   *         android:name="android.permission.QUERY_ALL_PACKAGES"
   *         tools:ignore="QueryAllPackagesPermission"/>
   * </pre>
   */
  public final class AppInfoUtils {
  
      private AppInfoUtils() {
      }
  
      // 日志 TAG
      private static final String TAG = AppInfoUtils.class.getSimpleName();
  
      /**
       * 通过 APK 路径 初始化 PackageInfo
       * @param file APK 文件路径
       * @return {@link PackageInfo}
       */
      public static PackageInfo getPackageInfoToFile(final File file) {
          if (!FileUtils.isFileExists(file)) return null;
          return getPackageInfoToPath(file.getAbsolutePath());
      }
  
      /**
       * 通过 APK 路径 初始化 PackageInfo
       * @param apkUri APK 文件路径
       * @return {@link PackageInfo}
       */
      public static PackageInfo getPackageInfoToPath(final String apkUri) {
          PackageManager packageManager = AppUtils.getPackageManager();
          if (packageManager == null) return null;
          try {
              PackageInfo packageInfo = packageManager.getPackageArchiveInfo(
                      apkUri, PackageManager.GET_ACTIVITIES
              );
              // 设置 APK 位置信息
              ApplicationInfo appInfo = packageInfo.applicationInfo;
              // 必须加这两句, 不然下面 icon 获取是 default icon 而不是应用包的 icon
              appInfo.sourceDir       = apkUri;
              appInfo.publicSourceDir = apkUri;
              return packageInfo;
          } catch (Exception e) {
              LogPrintUtils.eTag(TAG, e, "getPackageInfoToPath");
          }
          return null;
      }
  
      /**
       * 获取当前应用 PackageInfo
       * @return {@link PackageInfo}
       */
      public static PackageInfo getPackageInfo() {
          return getPackageInfo(AppUtils.getPackageName());
      }
  
      /**
       * 通过包名 获取 PackageInfo
       * @param packageName 应用包名
       * @return {@link PackageInfo}
       */
      public static PackageInfo getPackageInfo(final String packageName) {
          try {
              // 获取对应的 PackageInfo ( 原始的 PackageInfo 获取 signatures 等于 null, 需要这样获取 )
              return AppUtils.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
          } catch (Exception e) {
              LogPrintUtils.eTag(TAG, e, "getPackageInfo");
          }
          return null;
      }
  
      // =============
      // = 获取基本信息 =
      // =============
  
      /**
       * 通过 APK 路径 获取 AppInfoBean
       * @param file APK 文件路径
       * @return {@link AppInfoBean}
       */
      public static AppInfoBean getAppInfoBeanToFile(final File file) {
          return AppInfoBean.get(getPackageInfoToFile(file));
      }
  
      /**
       * 通过 APK 路径 获取 AppInfoBean
       * @param apkUri APK 文件路径
       * @return {@link AppInfoBean}
       */
      public static AppInfoBean getAppInfoBeanToPath(final String apkUri) {
          return AppInfoBean.get(getPackageInfoToPath(apkUri));
      }
  
      /**
       * 获取当前应用 AppInfoBean
       * @return {@link AppInfoBean}
       */
      public static AppInfoBean getAppInfoBean() {
          return AppInfoBean.get(getPackageInfo());
      }
  
      /**
       * 通过包名 获取 AppInfoBean
       * @param packageName 应用包名
       * @return {@link AppInfoBean}
       */
      public static AppInfoBean getAppInfoBean(final String packageName) {
          return AppInfoBean.get(getPackageInfo(packageName));
      }
  
      // =============
      // = 获取详细信息 =
      // =============
  
      /**
       * 获取 APK 详细信息
       * @param file APK 文件路径
       * @return {@link ApkInfoItem}
       */
      public static ApkInfoItem getApkInfoItem(final File file) {
          if (!FileUtils.isFileExists(file)) return null;
          return getApkInfoItem(file.getAbsolutePath());
      }
  
      /**
       * 获取 APK 详细信息
       * @param apkUri APK 文件路径
       * @return {@link ApkInfoItem}
       */
      public static ApkInfoItem getApkInfoItem(final String apkUri) {
          try {
              return ApkInfoItem.get(getPackageInfoToPath(apkUri));
          } catch (Exception e) {
              LogPrintUtils.eTag(TAG, e, "getApkInfoItem");
              return null;
          }
      }
  
      // =
  
      /**
       * 获取 APP 详细信息
       * @return {@link AppInfoItem}
       */
      public static AppInfoItem getAppInfoItem() {
          try {
              return AppInfoItem.get(getPackageInfo());
          } catch (Exception e) {
              LogPrintUtils.eTag(TAG, e, "getAppInfoItem");
              return null;
          }
      }
  
      /**
       * 获取 APP 详细信息
       * @param packageName 应用包名
       * @return {@link AppInfoItem}
       */
      public static AppInfoItem getAppInfoItem(final String packageName) {
          try {
              return AppInfoItem.get(getPackageInfo(packageName));
          } catch (Exception e) {
              LogPrintUtils.eTag(TAG, e, "getAppInfoItem");
              return null;
          }
      }
  
      // =
  
      /**
       * 获取全部 APP 列表
       * @return APP 列表
       */
      public static List<AppInfoBean> getAppLists() {
          return getAppLists(AppInfoBean.AppType.ALL);
      }
  
      /**
       * 获取 APP 列表
       * @param appType APP 类型
       * @return APP 列表
       */
      public static List<AppInfoBean> getAppLists(final AppInfoBean.AppType appType) {
          // APP 信息
          List<AppInfoBean> listApps = new ArrayList<>();
          // 防止为 null
          if (appType != null) {
              // 管理应用程序包
              PackageManager packageManager = AppUtils.getPackageManager();
              if (packageManager == null) return listApps;
              try {
                  // 获取手机内所有应用
                  List<PackageInfo> packList = packageManager.getInstalledPackages(0);
                  // 判断是否属于添加全部
                  if (appType == AppInfoBean.AppType.ALL) {
                      // 遍历 APP 列表
                      for (int i = 0, len = packList.size(); i < len; i++) {
                          PackageInfo packageInfo = packList.get(i);
                          // 添加符合条件的 APP 应用信息
                          listApps.add(new AppInfoBean(packageInfo, packageManager));
                      }
                  } else {
                      // 遍历 APP 列表
                      for (int i = 0, len = packList.size(); i < len; i++) {
                          PackageInfo packageInfo = packList.get(i);
                          // 获取 APP 类型
                          AppInfoBean.AppType currentAppType = AppInfoBean.getAppType(packageInfo);
                          // 判断类型
                          if (appType.equals(currentAppType)) {
                              // 添加符合条件的 APP 应用信息
                              listApps.add(new AppInfoBean(packageInfo, packageManager));
                          }
                      }
                  }
              } catch (Exception e) {
                  LogPrintUtils.eTag(TAG, e, "getAppLists");
              }
          }
          return listApps;
      }
  
      // =
  
      /**
       * 获取 APP 注册的权限
       * @return APP 注册的权限
       */
      public static List<String> getAppPermissionToList() {
          return new ArrayList<>(getAppPermissionToSet());
      }
  
      /**
       * 获取 APP 注册的权限
       * @return APP 注册的权限
       */
      public static Set<String> getAppPermissionToSet() {
          String[] permissions = getAppPermission();
          // 防止数据为 null
          if (permissions != null && permissions.length != 0) {
              Set<String> permissionSets = new HashSet<>();
              Collections.addAll(permissionSets, permissions);
              return permissionSets;
          }
          return Collections.emptySet();
      }
  
      /**
       * 获取 APP 注册的权限
       * @return APP 注册的权限数组
       */
      public static String[] getAppPermission() {
          return getAppPermission(AppUtils.getPackageName());
      }
  
      /**
       * 获取 APP 注册的权限
       * @param packageName 应用包名
       * @return APP 注册的权限数组
       */
      public static String[] getAppPermission(final String packageName) {
          PackageInfo packageInfo = AppUtils.getPackageInfo(
                  packageName, PackageManager.GET_PERMISSIONS
          );
          if (packageInfo == null) return null;
          try {
              return packageInfo.requestedPermissions;
          } catch (Exception e) {
              LogPrintUtils.eTag(TAG, e, "getAppPermission");
          }
          return null;
      }
  
      /**
       * 打印 APP 注册的权限
       * @param packageName 应用包名
       */
      public static void printAppPermission(final String packageName) {
          PackageManager packageManager = AppUtils.getPackageManager();
          if (packageManager == null) {
              LogPrintUtils.eTag(TAG, "printAppPermission => packageManager is null");
              return;
          }
          StringBuilder builder = new StringBuilder();
          try {
              PackageInfo packageInfo = packageManager.getPackageInfo(
                      packageName, PackageManager.GET_PERMISSIONS
              );
              String[] usesPermissionsArray = packageInfo.requestedPermissions;
              for (String usesPermissionName : usesPermissionsArray) {
                  // 获取每个权限的名字, 如: android.permission.INTERNET
                  // 拼接日志
                  builder.append("usesPermissionName = ").append(usesPermissionName);
                  builder.append(DevFinal.SYMBOL.NEW_LINE);
  
                  // 通过 usesPermissionName 获取该权限的详细信息
                  PermissionInfo permissionInfo = packageManager.getPermissionInfo(
                          usesPermissionName, 0
                  );
  
                  // 获取该权限属于哪个权限组, 如: 网络通信
                  PermissionGroupInfo permissionGroupInfo = packageManager.getPermissionGroupInfo(
                          permissionInfo.group, 0
                  );
                  // 拼接日志
                  builder.append("permissionGroup = ")
                          .append(permissionGroupInfo.loadLabel(packageManager).toString())
                          .append(DevFinal.SYMBOL.NEW_LINE);
  
                  // 获取该权限的标签信息, 比如: 完全的网络访问权限
                  String permissionLabel = permissionInfo.loadLabel(packageManager).toString();
                  // 拼接日志
                  builder.append("permissionLabel = ")
                          .append(permissionLabel)
                          .append(DevFinal.SYMBOL.NEW_LINE);
  
                  // 获取该权限的详细描述信息, 比如: 允许该应用创建网络套接字和使用自定义网络协议
                  // 浏览器和其他某些应用提供了向互联网发送数据的途径, 因此应用无需该权限即可向互联网发送数据
                  String permissionDescription = permissionInfo.loadDescription(packageManager).toString();
                  // 拼接日志
                  builder.append("permissionDescription = ").append(permissionDescription);
                  builder.append(DevFinal.SYMBOL.NEW_LINE);
              }
              // 打印日志
              LogPrintUtils.dTag(TAG, builder.toString());
          } catch (Exception e) {
              LogPrintUtils.eTag(TAG, e, "printAppPermission");
          }
      }
  
      // =
  
      /**
       * 获取所有能够显示在桌面上的应用
       * @return 所有能够显示在桌面上的应用
       */
      @RequiresApi(api = Build.VERSION_CODES.M)
      public static List<ResolveInfo> getAllLauncherIconPackages() {
          try {
              Intent intent = new Intent(Intent.ACTION_MAIN);
              intent.addCategory(Intent.CATEGORY_LAUNCHER);
              // set match_all to prevent any filtering of the results
              return AppUtils.getPackageManager()
                      .queryIntentActivities(intent, PackageManager.MATCH_ALL);
          } catch (Exception e) {
              LogPrintUtils.eTag(TAG, e, "getAllLauncherIconPackages");
          }
          return null;
      }
  
      /**
       * 获取所有能够显示在桌面上的应用包名
       * @return 所有能够显示在桌面上的应用包名
       */
      @RequiresApi(api = Build.VERSION_CODES.M)
      public static List<String> getAllLauncherIconPackageNames() {
          LinkedHashSet<String> names = new LinkedHashSet<>();
          ForUtils.forList((index, value) -> {
              if (value != null) {
                  names.add(value.activityInfo.packageName);
              }
          }, getAllLauncherIconPackages());
          return new ArrayList<>(names);
      }
  }