1 /* 2 * Copyright (C) 2014 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.compat; 18 19 import android.content.Context; 20 import android.content.pm.ApplicationInfo; 21 import android.content.pm.PackageInstaller; 22 import android.content.pm.PackageInstaller.SessionCallback; 23 import android.content.pm.PackageInstaller.SessionInfo; 24 import android.os.Handler; 25 import android.os.Process; 26 import android.os.UserHandle; 27 import android.text.TextUtils; 28 import android.util.SparseArray; 29 30 import com.android.launcher3.Utilities; 31 import com.android.launcher3.icons.IconCache; 32 import com.android.launcher3.LauncherAppState; 33 import com.android.launcher3.LauncherModel; 34 import com.android.launcher3.config.FeatureFlags; 35 import com.android.launcher3.util.Thunk; 36 37 import java.util.ArrayList; 38 import java.util.HashMap; 39 import java.util.Iterator; 40 import java.util.List; 41 42 public class PackageInstallerCompatVL extends PackageInstallerCompat { 43 44 private static final boolean DEBUG = false; 45 46 @Thunk final SparseArray<String> mActiveSessions = new SparseArray<>(); 47 48 @Thunk final PackageInstaller mInstaller; 49 private final IconCache mCache; 50 private final Handler mWorker; 51 private final Context mAppContext; 52 private final HashMap<String,Boolean> mSessionVerifiedMap = new HashMap<>(); 53 private final LauncherAppsCompat mLauncherApps; 54 PackageInstallerCompatVL(Context context)55 PackageInstallerCompatVL(Context context) { 56 mAppContext = context.getApplicationContext(); 57 mInstaller = context.getPackageManager().getPackageInstaller(); 58 mCache = LauncherAppState.getInstance(context).getIconCache(); 59 mWorker = new Handler(LauncherModel.getWorkerLooper()); 60 mInstaller.registerSessionCallback(mCallback, mWorker); 61 mLauncherApps = LauncherAppsCompat.getInstance(context); 62 } 63 64 @Override updateAndGetActiveSessionCache()65 public HashMap<String, SessionInfo> updateAndGetActiveSessionCache() { 66 HashMap<String, SessionInfo> activePackages = new HashMap<>(); 67 UserHandle user = Process.myUserHandle(); 68 for (SessionInfo info : getAllVerifiedSessions()) { 69 addSessionInfoToCache(info, user); 70 if (info.getAppPackageName() != null) { 71 activePackages.put(info.getAppPackageName(), info); 72 mActiveSessions.put(info.getSessionId(), info.getAppPackageName()); 73 } 74 } 75 return activePackages; 76 } 77 addSessionInfoToCache(SessionInfo info, UserHandle user)78 @Thunk void addSessionInfoToCache(SessionInfo info, UserHandle user) { 79 String packageName = info.getAppPackageName(); 80 if (packageName != null) { 81 mCache.cachePackageInstallInfo(packageName, user, info.getAppIcon(), 82 info.getAppLabel()); 83 } 84 } 85 86 @Override onStop()87 public void onStop() { 88 mInstaller.unregisterSessionCallback(mCallback); 89 } 90 sendUpdate(PackageInstallInfo info)91 @Thunk void sendUpdate(PackageInstallInfo info) { 92 LauncherAppState app = LauncherAppState.getInstanceNoCreate(); 93 if (app != null) { 94 app.getModel().setPackageState(info); 95 } 96 } 97 98 private final SessionCallback mCallback = new SessionCallback() { 99 100 @Override 101 public void onCreated(int sessionId) { 102 SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId); 103 if (FeatureFlags.LAUNCHER3_PROMISE_APPS_IN_ALL_APPS && sessionInfo != null) { 104 LauncherAppState app = LauncherAppState.getInstanceNoCreate(); 105 if (app != null) { 106 app.getModel().onInstallSessionCreated( 107 PackageInstallInfo.fromInstallingState(sessionInfo)); 108 } 109 } 110 } 111 112 @Override 113 public void onFinished(int sessionId, boolean success) { 114 // For a finished session, we can't get the session info. So use the 115 // packageName from our local cache. 116 String packageName = mActiveSessions.get(sessionId); 117 mActiveSessions.remove(sessionId); 118 119 if (packageName != null) { 120 sendUpdate(PackageInstallInfo.fromState( 121 success ? STATUS_INSTALLED : STATUS_FAILED, 122 packageName)); 123 } 124 } 125 126 @Override 127 public void onProgressChanged(int sessionId, float progress) { 128 SessionInfo session = verify(mInstaller.getSessionInfo(sessionId)); 129 if (session != null && session.getAppPackageName() != null) { 130 sendUpdate(PackageInstallInfo.fromInstallingState(session)); 131 } 132 } 133 134 @Override 135 public void onActiveChanged(int sessionId, boolean active) { } 136 137 @Override 138 public void onBadgingChanged(int sessionId) { 139 pushSessionDisplayToLauncher(sessionId); 140 } 141 142 private SessionInfo pushSessionDisplayToLauncher(int sessionId) { 143 SessionInfo session = verify(mInstaller.getSessionInfo(sessionId)); 144 if (session != null && session.getAppPackageName() != null) { 145 mActiveSessions.put(sessionId, session.getAppPackageName()); 146 addSessionInfoToCache(session, Process.myUserHandle()); 147 LauncherAppState app = LauncherAppState.getInstanceNoCreate(); 148 if (app != null) { 149 app.getModel().updateSessionDisplayInfo(session.getAppPackageName()); 150 } 151 return session; 152 } 153 return null; 154 } 155 }; 156 verify(PackageInstaller.SessionInfo sessionInfo)157 private PackageInstaller.SessionInfo verify(PackageInstaller.SessionInfo sessionInfo) { 158 if (sessionInfo == null 159 || sessionInfo.getInstallerPackageName() == null 160 || TextUtils.isEmpty(sessionInfo.getAppPackageName())) { 161 return null; 162 } 163 String pkg = sessionInfo.getInstallerPackageName(); 164 synchronized (mSessionVerifiedMap) { 165 if (!mSessionVerifiedMap.containsKey(pkg)) { 166 LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mAppContext); 167 boolean hasSystemFlag = launcherApps.getApplicationInfo(pkg, 168 ApplicationInfo.FLAG_SYSTEM, Process.myUserHandle()) != null; 169 mSessionVerifiedMap.put(pkg, DEBUG || hasSystemFlag); 170 } 171 } 172 return mSessionVerifiedMap.get(pkg) ? sessionInfo : null; 173 } 174 175 @Override getAllVerifiedSessions()176 public List<SessionInfo> getAllVerifiedSessions() { 177 List<SessionInfo> list = new ArrayList<>(Utilities.ATLEAST_Q 178 ? mLauncherApps.getAllPackageInstallerSessions() 179 : mInstaller.getAllSessions()); 180 Iterator<SessionInfo> it = list.iterator(); 181 while (it.hasNext()) { 182 if (verify(it.next()) == null) { 183 it.remove(); 184 } 185 } 186 return list; 187 } 188 } 189