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