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.systemui.recents.model;
18 
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.os.Looper;
22 import android.os.UserHandle;
23 import com.android.internal.content.PackageMonitor;
24 import com.android.systemui.recents.misc.SystemServicesProxy;
25 
26 import java.util.HashSet;
27 import java.util.List;
28 
29 /**
30  * The package monitor listens for changes from PackageManager to update the contents of the
31  * Recents list.
32  */
33 public class RecentsPackageMonitor extends PackageMonitor {
34     public interface PackageCallbacks {
onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId)35         public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName,
36                                       int userId);
37     }
38 
39     PackageCallbacks mCb;
40     SystemServicesProxy mSystemServicesProxy;
41 
42     /** Registers the broadcast receivers with the specified callbacks. */
register(Context context, PackageCallbacks cb)43     public void register(Context context, PackageCallbacks cb) {
44         mSystemServicesProxy = new SystemServicesProxy(context);
45         mCb = cb;
46         try {
47             // We register for events from all users, but will cross-reference them with
48             // packages for the current user and any profiles they have
49             register(context, Looper.getMainLooper(), UserHandle.ALL, true);
50         } catch (IllegalStateException e) {
51             e.printStackTrace();
52         }
53     }
54 
55     /** Unregisters the broadcast receivers. */
56     @Override
unregister()57     public void unregister() {
58         try {
59             super.unregister();
60         } catch (IllegalStateException e) {
61             e.printStackTrace();
62         }
63         mSystemServicesProxy = null;
64         mCb = null;
65     }
66 
67     @Override
onPackageRemoved(String packageName, int uid)68     public void onPackageRemoved(String packageName, int uid) {
69         if (mCb == null) return;
70 
71         // Notify callbacks that a package has changed
72         final int eventUserId = getChangingUserId();
73         mCb.onPackagesChanged(this, packageName, eventUserId);
74     }
75 
76     @Override
onPackageChanged(String packageName, int uid, String[] components)77     public boolean onPackageChanged(String packageName, int uid, String[] components) {
78         onPackageModified(packageName);
79         return true;
80     }
81 
82     @Override
onPackageModified(String packageName)83     public void onPackageModified(String packageName) {
84         if (mCb == null) return;
85 
86         // Notify callbacks that a package has changed
87         final int eventUserId = getChangingUserId();
88         mCb.onPackagesChanged(this, packageName, eventUserId);
89     }
90 
91     /**
92      * Computes the components that have been removed as a result of a change in the specified
93      * package.
94      */
computeComponentsRemoved(List<Task.TaskKey> taskKeys, String packageName, int userId)95     public HashSet<ComponentName> computeComponentsRemoved(List<Task.TaskKey> taskKeys,
96             String packageName, int userId) {
97         // Identify all the tasks that should be removed as a result of the package being removed.
98         // Using a set to ensure that we callback once per unique component.
99         HashSet<ComponentName> existingComponents = new HashSet<ComponentName>();
100         HashSet<ComponentName> removedComponents = new HashSet<ComponentName>();
101         for (Task.TaskKey t : taskKeys) {
102             // Skip if this doesn't apply to the current user
103             if (t.userId != userId) continue;
104 
105             ComponentName cn = t.baseIntent.getComponent();
106             if (cn.getPackageName().equals(packageName)) {
107                 if (existingComponents.contains(cn)) {
108                     // If we know that the component still exists in the package, then skip
109                     continue;
110                 }
111                 if (mSystemServicesProxy.getActivityInfo(cn, userId) != null) {
112                     existingComponents.add(cn);
113                 } else {
114                     removedComponents.add(cn);
115                 }
116             }
117         }
118         return removedComponents;
119     }
120 }
121