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 com.android.internal.content.PackageMonitor;
23import com.android.systemui.recents.misc.SystemServicesProxy;
24
25import java.util.HashSet;
26import java.util.List;
27
28/**
29 * The package monitor listens for changes from PackageManager to update the contents of the Recents
30 * list.
31 */
32public class RecentsPackageMonitor extends PackageMonitor {
33    public interface PackageCallbacks {
34        public void onComponentRemoved(HashSet<ComponentName> cns);
35    }
36
37    PackageCallbacks mCb;
38    List<Task.TaskKey> mTasks;
39    SystemServicesProxy mSystemServicesProxy;
40
41    /** Registers the broadcast receivers with the specified callbacks. */
42    public void register(Context context, PackageCallbacks cb) {
43        mSystemServicesProxy = new SystemServicesProxy(context);
44        mCb = cb;
45        try {
46            register(context, Looper.getMainLooper(), true);
47        } catch (IllegalStateException e) {
48            e.printStackTrace();
49        }
50    }
51
52    /** Unregisters the broadcast receivers. */
53    @Override
54    public void unregister() {
55        try {
56            super.unregister();
57        } catch (IllegalStateException e) {
58            e.printStackTrace();
59        }
60        mSystemServicesProxy = null;
61        mCb = null;
62        mTasks.clear();
63    }
64
65    /** Sets the list of tasks to match against package broadcast changes. */
66    void setTasks(List<Task.TaskKey> tasks) {
67        mTasks = tasks;
68    }
69
70    @Override
71    public void onPackageRemoved(String packageName, int uid) {
72        if (mCb == null) return;
73
74        // Identify all the tasks that should be removed as a result of the package being removed.
75        // Using a set to ensure that we callback once per unique component.
76        HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
77        for (Task.TaskKey t : mTasks) {
78            ComponentName cn = t.baseIntent.getComponent();
79            if (cn.getPackageName().equals(packageName)) {
80                componentsToRemove.add(cn);
81            }
82        }
83        // Notify our callbacks that the components no longer exist
84        mCb.onComponentRemoved(componentsToRemove);
85    }
86
87    @Override
88    public boolean onPackageChanged(String packageName, int uid, String[] components) {
89        onPackageModified(packageName);
90        return true;
91    }
92
93    @Override
94    public void onPackageModified(String packageName) {
95        if (mCb == null) return;
96
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> componentsKnownToExist = new HashSet<ComponentName>();
100        HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>();
101        for (Task.TaskKey t : mTasks) {
102            ComponentName cn = t.baseIntent.getComponent();
103            if (cn.getPackageName().equals(packageName)) {
104                if (componentsKnownToExist.contains(cn)) {
105                    // If we know that the component still exists in the package, then skip
106                    continue;
107                }
108                if (mSystemServicesProxy.getActivityInfo(cn) != null) {
109                    componentsKnownToExist.add(cn);
110                } else {
111                    componentsToRemove.add(cn);
112                }
113            }
114        }
115        // Notify our callbacks that the components no longer exist
116        mCb.onComponentRemoved(componentsToRemove);
117    }
118}
119