• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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