• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 package com.android.launcher3.pm;
17 
18 import static com.android.launcher3.pm.InstallSessionHelper.getUserHandle;
19 import static com.android.launcher3.pm.PackageInstallInfo.STATUS_FAILED;
20 import static com.android.launcher3.pm.PackageInstallInfo.STATUS_INSTALLED;
21 import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
22 
23 import android.content.pm.LauncherApps;
24 import android.content.pm.PackageInstaller;
25 import android.content.pm.PackageInstaller.SessionInfo;
26 import android.os.Build;
27 import android.os.UserHandle;
28 import android.util.Log;
29 import android.util.SparseArray;
30 
31 import androidx.annotation.NonNull;
32 import androidx.annotation.Nullable;
33 import androidx.annotation.WorkerThread;
34 
35 import com.android.launcher3.testing.shared.TestProtocol;
36 import com.android.launcher3.util.PackageUserKey;
37 
38 import java.lang.ref.WeakReference;
39 import java.util.Objects;
40 
41 @WorkerThread
42 public class InstallSessionTracker extends PackageInstaller.SessionCallback {
43 
44     // Lazily initialized
45     private SparseArray<PackageUserKey> mActiveSessions = null;
46 
47     @NonNull
48     private final WeakReference<InstallSessionHelper> mWeakHelper;
49 
50     @NonNull
51     private final WeakReference<Callback> mWeakCallback;
52 
53     @NonNull
54     private final PackageInstaller mInstaller;
55 
56     @Nullable
57     private final LauncherApps mLauncherApps;
58 
59 
InstallSessionTracker(@ullable final InstallSessionHelper installerCompat, @Nullable final Callback callback, @NonNull final PackageInstaller installer, @Nullable LauncherApps launcherApps)60     InstallSessionTracker(@Nullable final InstallSessionHelper installerCompat,
61             @Nullable final Callback callback, @NonNull final PackageInstaller installer,
62             @Nullable LauncherApps launcherApps) {
63         mWeakHelper = new WeakReference<>(installerCompat);
64         mWeakCallback = new WeakReference<>(callback);
65         mInstaller = installer;
66         mLauncherApps = launcherApps;
67     }
68 
69     @Override
onCreated(final int sessionId)70     public void onCreated(final int sessionId) {
71         InstallSessionHelper helper = mWeakHelper.get();
72         Callback callback = mWeakCallback.get();
73         if (TestProtocol.sDebugTracing) {
74             Log.d(TestProtocol.MISSING_PROMISE_ICON, "Session created sessionId=" + sessionId
75                     + ", callback=" + callback
76                     + ", helper=" + helper);
77         }
78         if (callback == null || helper == null) {
79             return;
80         }
81         SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
82         if (TestProtocol.sDebugTracing) {
83             Log.d(TestProtocol.MISSING_PROMISE_ICON, "Session created sessionId=" + sessionId
84                     + ", sessionInfo=" + sessionInfo);
85         }
86         if (sessionInfo != null) {
87             callback.onInstallSessionCreated(PackageInstallInfo.fromInstallingState(sessionInfo));
88         }
89 
90         helper.tryQueuePromiseAppIcon(sessionInfo);
91     }
92 
93     @Override
onFinished(final int sessionId, final boolean success)94     public void onFinished(final int sessionId, final boolean success) {
95         InstallSessionHelper helper = mWeakHelper.get();
96         Callback callback = mWeakCallback.get();
97         if (callback == null || helper == null) {
98             return;
99         }
100         // For a finished session, we can't get the session info. So use the
101         // packageName from our local cache.
102         SparseArray<PackageUserKey> activeSessions = getActiveSessionMap(helper);
103         PackageUserKey key = activeSessions.get(sessionId);
104         activeSessions.remove(sessionId);
105 
106         if (key != null && key.mPackageName != null) {
107             String packageName = key.mPackageName;
108             PackageInstallInfo info = PackageInstallInfo.fromState(
109                     success ? STATUS_INSTALLED : STATUS_FAILED,
110                     packageName, key.mUser);
111             callback.onPackageStateChanged(info);
112 
113             if (!success && helper.promiseIconAddedForId(sessionId)) {
114                 callback.onSessionFailure(packageName, key.mUser);
115                 // If it is successful, the id is removed in the the package added flow.
116                 helper.removePromiseIconId(sessionId);
117             }
118         }
119     }
120 
121     @Override
onProgressChanged(final int sessionId, final float progress)122     public void onProgressChanged(final int sessionId, final float progress) {
123         InstallSessionHelper helper = mWeakHelper.get();
124         Callback callback = mWeakCallback.get();
125         if (callback == null || helper == null) {
126             return;
127         }
128         SessionInfo session = helper.getVerifiedSessionInfo(sessionId);
129         if (session != null && session.getAppPackageName() != null) {
130             callback.onPackageStateChanged(PackageInstallInfo.fromInstallingState(session));
131         }
132     }
133 
134     @Override
onActiveChanged(final int sessionId, final boolean active)135     public void onActiveChanged(final int sessionId, final boolean active) { }
136 
137     @Override
onBadgingChanged(final int sessionId)138     public void onBadgingChanged(final int sessionId) {
139         InstallSessionHelper helper = mWeakHelper.get();
140         Callback callback = mWeakCallback.get();
141         if (callback == null || helper == null) {
142             return;
143         }
144         SessionInfo sessionInfo = pushSessionDisplayToLauncher(sessionId, helper, callback);
145         if (sessionInfo != null) {
146             helper.tryQueuePromiseAppIcon(sessionInfo);
147         }
148     }
149 
150     @Nullable
pushSessionDisplayToLauncher(final int sessionId, @NonNull final InstallSessionHelper helper, @NonNull final Callback callback)151     private SessionInfo pushSessionDisplayToLauncher(final int sessionId,
152             @NonNull final InstallSessionHelper helper, @NonNull final Callback callback) {
153         SessionInfo session = helper.getVerifiedSessionInfo(sessionId);
154         if (session != null && session.getAppPackageName() != null) {
155             PackageUserKey key =
156                     new PackageUserKey(session.getAppPackageName(), getUserHandle(session));
157             getActiveSessionMap(helper).put(session.getSessionId(), key);
158             callback.onUpdateSessionDisplay(key, session);
159             return session;
160         }
161         return null;
162     }
163 
164     @NonNull
getActiveSessionMap( @onNull final InstallSessionHelper helper)165     private SparseArray<PackageUserKey> getActiveSessionMap(
166             @NonNull final InstallSessionHelper helper) {
167         if (mActiveSessions == null) {
168             mActiveSessions = new SparseArray<>();
169             helper.getActiveSessions().forEach(
170                     (key, si) -> mActiveSessions.put(si.getSessionId(), key));
171         }
172         return mActiveSessions;
173     }
174 
register()175     void register() {
176         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
177             mInstaller.registerSessionCallback(this, MODEL_EXECUTOR.getHandler());
178         } else {
179             Objects.requireNonNull(mLauncherApps).registerPackageInstallerSessionCallback(
180                     MODEL_EXECUTOR, this);
181         }
182     }
183 
unregister()184     public void unregister() {
185         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
186             mInstaller.unregisterSessionCallback(this);
187         } else {
188             Objects.requireNonNull(mLauncherApps).unregisterPackageInstallerSessionCallback(this);
189         }
190     }
191 
192     public interface Callback {
193 
onSessionFailure(@onNull String packageName, @NonNull UserHandle user)194         void onSessionFailure(@NonNull String packageName, @NonNull UserHandle user);
195 
onUpdateSessionDisplay(@onNull PackageUserKey key, @NonNull SessionInfo info)196         void onUpdateSessionDisplay(@NonNull PackageUserKey key, @NonNull SessionInfo info);
197 
onPackageStateChanged(@onNull PackageInstallInfo info)198         void onPackageStateChanged(@NonNull PackageInstallInfo info);
199 
onInstallSessionCreated(@onNull PackageInstallInfo info)200         void onInstallSessionCreated(@NonNull PackageInstallInfo info);
201     }
202 }
203