1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.launcher3.util 18 19 import android.content.Context 20 import android.content.Intent 21 import android.content.pm.ApplicationInfo 22 import android.content.pm.ApplicationInfo.FLAG_EXTERNAL_STORAGE 23 import android.content.pm.ApplicationInfo.FLAG_INSTALLED 24 import android.content.pm.ApplicationInfo.FLAG_SUSPENDED 25 import android.content.pm.ApplicationInfo.FLAG_SYSTEM 26 import android.content.pm.LauncherApps 27 import android.content.pm.PackageManager 28 import android.content.pm.PackageManager.NameNotFoundException 29 import android.os.UserHandle 30 import com.android.launcher3.Flags.enableSupportForArchiving 31 import com.android.launcher3.Utilities.ATLEAST_V 32 import kotlin.LazyThreadSafetyMode.NONE 33 34 /** 35 * A set of utility methods around ApplicationInfo with support for fetching the actual info lazily 36 */ 37 class ApplicationInfoWrapper private constructor(provider: () -> ApplicationInfo?) { 38 39 constructor(appInfo: ApplicationInfo?) : this({ appInfo }) 40 41 constructor( 42 ctx: Context, 43 pkg: String, 44 user: UserHandle, 45 ) : this({ 46 try { 47 ctx.getSystemService(LauncherApps::class.java) 48 ?.getApplicationInfo(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES, user) 49 ?.let { ai -> 50 // its enabled and (either installed or archived) 51 if ( 52 ai.enabled && 53 (ai.flags.and(FLAG_INSTALLED) != 0 || 54 (ATLEAST_V && enableSupportForArchiving() && ai.isArchived)) 55 ) { 56 ai 57 } else { 58 null 59 } 60 } 61 } catch (e: NameNotFoundException) { 62 null 63 } 64 }) 65 66 constructor( 67 ctx: Context, 68 intent: Intent, 69 ) : this( 70 provider@{ 71 try { 72 val pm = ctx.packageManager 73 val packageName: String = 74 intent.component?.packageName 75 ?: intent.getPackage() 76 ?: return@provider pm.resolveActivity( 77 intent, 78 PackageManager.MATCH_DEFAULT_ONLY, 79 ) 80 ?.activityInfo 81 ?.applicationInfo 82 pm.getApplicationInfo(packageName, 0) 83 } catch (e: NameNotFoundException) { 84 null 85 } 86 } 87 ) 88 89 private val appInfo: ApplicationInfo? by lazy(NONE, provider) 90 91 private fun hasFlag(flag: Int) = appInfo?.let { it.flags.and(flag) != 0 } ?: false 92 93 /** 94 * Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't 95 * guarantee that the app is on SD card. 96 */ 97 fun isOnSdCard() = hasFlag(FLAG_EXTERNAL_STORAGE) 98 99 /** Returns whether the target app is installed for a given user */ 100 fun isInstalled() = hasFlag(FLAG_INSTALLED) 101 102 /** 103 * Returns whether the target app is suspended for a given user as per 104 * [android.app.admin.DevicePolicyManager.isPackageSuspended]. 105 */ 106 fun isSuspended() = hasFlag(FLAG_INSTALLED) && hasFlag(FLAG_SUSPENDED) 107 108 /** Returns whether the target app is archived for a given user */ 109 fun isArchived() = ATLEAST_V && enableSupportForArchiving() && appInfo?.isArchived ?: false 110 111 /** Returns whether the target app is a system app */ 112 fun isSystem() = hasFlag(FLAG_SYSTEM) 113 114 fun getInfo(): ApplicationInfo? = appInfo 115 } 116