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
17package com.android.systemui.recents.model;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.os.Looper;
22import android.os.UserHandle;
23import com.android.internal.content.PackageMonitor;
24import com.android.systemui.recents.misc.SystemServicesProxy;
25
26import java.util.HashSet;
27import java.util.List;
28
29/**
30 * The package monitor listens for changes from PackageManager to update the contents of the
31 * Recents list.
32 */
33public class RecentsPackageMonitor extends PackageMonitor {
34    public interface PackageCallbacks {
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. */
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
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
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
77    public boolean onPackageChanged(String packageName, int uid, String[] components) {
78        onPackageModified(packageName);
79        return true;
80    }
81
82    @Override
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     */
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