1ed13187a745866483139e2878037e1f8427ce567Kenny Guy/*
2ed13187a745866483139e2878037e1f8427ce567Kenny Guy * Copyright (C) 2014 The Android Open Source Project
3ed13187a745866483139e2878037e1f8427ce567Kenny Guy *
4ed13187a745866483139e2878037e1f8427ce567Kenny Guy * Licensed under the Apache License, Version 2.0 (the "License");
5ed13187a745866483139e2878037e1f8427ce567Kenny Guy * you may not use this file except in compliance with the License.
6ed13187a745866483139e2878037e1f8427ce567Kenny Guy * You may obtain a copy of the License at
7ed13187a745866483139e2878037e1f8427ce567Kenny Guy *
8ed13187a745866483139e2878037e1f8427ce567Kenny Guy *      http://www.apache.org/licenses/LICENSE-2.0
9ed13187a745866483139e2878037e1f8427ce567Kenny Guy *
10ed13187a745866483139e2878037e1f8427ce567Kenny Guy * Unless required by applicable law or agreed to in writing, software
11ed13187a745866483139e2878037e1f8427ce567Kenny Guy * distributed under the License is distributed on an "AS IS" BASIS,
12ed13187a745866483139e2878037e1f8427ce567Kenny Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ed13187a745866483139e2878037e1f8427ce567Kenny Guy * See the License for the specific language governing permissions and
14ed13187a745866483139e2878037e1f8427ce567Kenny Guy * limitations under the License.
15ed13187a745866483139e2878037e1f8427ce567Kenny Guy */
16ed13187a745866483139e2878037e1f8427ce567Kenny Guy
17ed13187a745866483139e2878037e1f8427ce567Kenny Guypackage com.android.launcher3.compat;
18ed13187a745866483139e2878037e1f8427ce567Kenny Guy
19ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.BroadcastReceiver;
20ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.ComponentName;
21ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.Context;
22ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.Intent;
23ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.IntentFilter;
24ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.pm.ActivityInfo;
25ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.pm.PackageManager;
26ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.pm.PackageManager.NameNotFoundException;
27ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.pm.ResolveInfo;
28ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.graphics.Rect;
29f07af7b77de0319355e228e8630824d924522d78Kenny Guyimport android.net.Uri;
30ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.os.Build;
31ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.os.Bundle;
32f07af7b77de0319355e228e8630824d924522d78Kenny Guyimport android.provider.Settings;
33ed13187a745866483139e2878037e1f8427ce567Kenny Guy
349fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyalimport com.android.launcher3.Utilities;
35091440a9cb9d4f42406631004aa484cbb79214caAdam Cohenimport com.android.launcher3.util.Thunk;
36091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen
37ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport java.util.ArrayList;
38ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport java.util.List;
39ed13187a745866483139e2878037e1f8427ce567Kenny Guy
40f07af7b77de0319355e228e8630824d924522d78Kenny Guy/**
41f07af7b77de0319355e228e8630824d924522d78Kenny Guy * Version of {@link LauncherAppsCompat} for devices with API level 16.
42f07af7b77de0319355e228e8630824d924522d78Kenny Guy * Devices Pre-L don't support multiple profiles in one launcher so
43f07af7b77de0319355e228e8630824d924522d78Kenny Guy * user parameters are ignored and all methods operate on the current user.
44f07af7b77de0319355e228e8630824d924522d78Kenny Guy */
45ed13187a745866483139e2878037e1f8427ce567Kenny Guypublic class LauncherAppsCompatV16 extends LauncherAppsCompat {
46ed13187a745866483139e2878037e1f8427ce567Kenny Guy
47ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private PackageManager mPm;
48ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private Context mContext;
49c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    private List<OnAppsChangedCallbackCompat> mCallbacks
50c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy            = new ArrayList<OnAppsChangedCallbackCompat>();
51ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private PackageMonitor mPackageMonitor;
52ed13187a745866483139e2878037e1f8427ce567Kenny Guy
53ed13187a745866483139e2878037e1f8427ce567Kenny Guy    LauncherAppsCompatV16(Context context) {
54ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mPm = context.getPackageManager();
55ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext = context;
56ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mPackageMonitor = new PackageMonitor();
57ed13187a745866483139e2878037e1f8427ce567Kenny Guy   }
58ed13187a745866483139e2878037e1f8427ce567Kenny Guy
59ed13187a745866483139e2878037e1f8427ce567Kenny Guy    public List<LauncherActivityInfoCompat> getActivityList(String packageName,
60ed13187a745866483139e2878037e1f8427ce567Kenny Guy            UserHandleCompat user) {
61ed13187a745866483139e2878037e1f8427ce567Kenny Guy        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
62ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
63ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mainIntent.setPackage(packageName);
64ed13187a745866483139e2878037e1f8427ce567Kenny Guy        List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0);
65ed13187a745866483139e2878037e1f8427ce567Kenny Guy        List<LauncherActivityInfoCompat> list =
66ed13187a745866483139e2878037e1f8427ce567Kenny Guy                new ArrayList<LauncherActivityInfoCompat>(infos.size());
67ed13187a745866483139e2878037e1f8427ce567Kenny Guy        for (ResolveInfo info : infos) {
68ed13187a745866483139e2878037e1f8427ce567Kenny Guy            list.add(new LauncherActivityInfoCompatV16(mContext, info));
69ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
70ed13187a745866483139e2878037e1f8427ce567Kenny Guy        return list;
71ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
72ed13187a745866483139e2878037e1f8427ce567Kenny Guy
73ed13187a745866483139e2878037e1f8427ce567Kenny Guy    public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandleCompat user) {
74ed13187a745866483139e2878037e1f8427ce567Kenny Guy        ResolveInfo info = mPm.resolveActivity(intent, 0);
75ed13187a745866483139e2878037e1f8427ce567Kenny Guy        if (info != null) {
76ed13187a745866483139e2878037e1f8427ce567Kenny Guy            return new LauncherActivityInfoCompatV16(mContext, info);
77ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
78ed13187a745866483139e2878037e1f8427ce567Kenny Guy        return null;
79ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
80ed13187a745866483139e2878037e1f8427ce567Kenny Guy
81c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    public void startActivityForProfile(ComponentName component, UserHandleCompat user,
82c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy            Rect sourceBounds, Bundle opts) {
83ed13187a745866483139e2878037e1f8427ce567Kenny Guy        Intent launchIntent = new Intent(Intent.ACTION_MAIN);
84ed13187a745866483139e2878037e1f8427ce567Kenny Guy        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
85ed13187a745866483139e2878037e1f8427ce567Kenny Guy        launchIntent.setComponent(component);
86ed13187a745866483139e2878037e1f8427ce567Kenny Guy        launchIntent.setSourceBounds(sourceBounds);
87ed13187a745866483139e2878037e1f8427ce567Kenny Guy        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
88ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext.startActivity(launchIntent, opts);
89ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
90ed13187a745866483139e2878037e1f8427ce567Kenny Guy
91f07af7b77de0319355e228e8630824d924522d78Kenny Guy    public void showAppDetailsForProfile(ComponentName component, UserHandleCompat user) {
92f07af7b77de0319355e228e8630824d924522d78Kenny Guy        String packageName = component.getPackageName();
93f07af7b77de0319355e228e8630824d924522d78Kenny Guy        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
94f07af7b77de0319355e228e8630824d924522d78Kenny Guy                Uri.fromParts("package", packageName, null));
95f07af7b77de0319355e228e8630824d924522d78Kenny Guy        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
96f07af7b77de0319355e228e8630824d924522d78Kenny Guy                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
97f07af7b77de0319355e228e8630824d924522d78Kenny Guy        mContext.startActivity(intent, null);
98f07af7b77de0319355e228e8630824d924522d78Kenny Guy    }
99f07af7b77de0319355e228e8630824d924522d78Kenny Guy
100c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    public synchronized void addOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
101c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        if (callback != null && !mCallbacks.contains(callback)) {
102c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy            mCallbacks.add(callback);
103c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy            if (mCallbacks.size() == 1) {
104ed13187a745866483139e2878037e1f8427ce567Kenny Guy                registerForPackageIntents();
105ed13187a745866483139e2878037e1f8427ce567Kenny Guy            }
106ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
107ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
108ed13187a745866483139e2878037e1f8427ce567Kenny Guy
109c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    public synchronized void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
110c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        mCallbacks.remove(callback);
111c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        if (mCallbacks.size() == 0) {
112ed13187a745866483139e2878037e1f8427ce567Kenny Guy            unregisterForPackageIntents();
113ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
114ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
115ed13187a745866483139e2878037e1f8427ce567Kenny Guy
116ed13187a745866483139e2878037e1f8427ce567Kenny Guy    public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) {
1171a745e8f18e54aff152ff51743ae7595adde6927Sunny Goyal        return isAppEnabled(mPm, packageName, 0);
118ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
119ed13187a745866483139e2878037e1f8427ce567Kenny Guy
120ed13187a745866483139e2878037e1f8427ce567Kenny Guy    public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) {
121ed13187a745866483139e2878037e1f8427ce567Kenny Guy        try {
122ed13187a745866483139e2878037e1f8427ce567Kenny Guy            ActivityInfo info = mPm.getActivityInfo(component, 0);
123ed13187a745866483139e2878037e1f8427ce567Kenny Guy            return info != null && info.isEnabled();
124ed13187a745866483139e2878037e1f8427ce567Kenny Guy        } catch (NameNotFoundException e) {
125ed13187a745866483139e2878037e1f8427ce567Kenny Guy            return false;
126ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
127ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
128ed13187a745866483139e2878037e1f8427ce567Kenny Guy
129ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private void unregisterForPackageIntents() {
130ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext.unregisterReceiver(mPackageMonitor);
131ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
132ed13187a745866483139e2878037e1f8427ce567Kenny Guy
133ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private void registerForPackageIntents() {
134ed13187a745866483139e2878037e1f8427ce567Kenny Guy        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
135ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
136ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
137ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addDataScheme("package");
138ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext.registerReceiver(mPackageMonitor, filter);
139ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter = new IntentFilter();
140ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
141ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
142ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext.registerReceiver(mPackageMonitor, filter);
143ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
144ed13187a745866483139e2878037e1f8427ce567Kenny Guy
145091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk synchronized List<OnAppsChangedCallbackCompat> getCallbacks() {
146c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        return new ArrayList<OnAppsChangedCallbackCompat>(mCallbacks);
147ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
148ed13187a745866483139e2878037e1f8427ce567Kenny Guy
149091440a9cb9d4f42406631004aa484cbb79214caAdam Cohen    @Thunk class PackageMonitor extends BroadcastReceiver {
150ed13187a745866483139e2878037e1f8427ce567Kenny Guy        public void onReceive(Context context, Intent intent) {
151ed13187a745866483139e2878037e1f8427ce567Kenny Guy            final String action = intent.getAction();
152ed13187a745866483139e2878037e1f8427ce567Kenny Guy            final UserHandleCompat user = UserHandleCompat.myUserHandle();
153ed13187a745866483139e2878037e1f8427ce567Kenny Guy
154ed13187a745866483139e2878037e1f8427ce567Kenny Guy            if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
155ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)
156ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    || Intent.ACTION_PACKAGE_ADDED.equals(action)) {
157ed13187a745866483139e2878037e1f8427ce567Kenny Guy                final String packageName = intent.getData().getSchemeSpecificPart();
158ed13187a745866483139e2878037e1f8427ce567Kenny Guy                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
159ed13187a745866483139e2878037e1f8427ce567Kenny Guy
160ed13187a745866483139e2878037e1f8427ce567Kenny Guy                if (packageName == null || packageName.length() == 0) {
161ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    // they sent us a bad intent
162ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    return;
163ed13187a745866483139e2878037e1f8427ce567Kenny Guy                }
164ed13187a745866483139e2878037e1f8427ce567Kenny Guy                if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
165c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                    for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
166c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                        callback.onPackageChanged(packageName, user);
167ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    }
168ed13187a745866483139e2878037e1f8427ce567Kenny Guy                } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
169ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    if (!replacing) {
170c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
171c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                            callback.onPackageRemoved(packageName, user);
172ed13187a745866483139e2878037e1f8427ce567Kenny Guy                        }
173ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    }
174ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    // else, we are replacing the package, so a PACKAGE_ADDED will be sent
175ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    // later, we will update the package at this time
176ed13187a745866483139e2878037e1f8427ce567Kenny Guy                } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
177ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    if (!replacing) {
178c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
179c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                            callback.onPackageAdded(packageName, user);
180ed13187a745866483139e2878037e1f8427ce567Kenny Guy                        }
181ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    } else {
182c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
183c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                            callback.onPackageChanged(packageName, user);
184ed13187a745866483139e2878037e1f8427ce567Kenny Guy                        }
185ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    }
186ed13187a745866483139e2878037e1f8427ce567Kenny Guy                }
187ed13187a745866483139e2878037e1f8427ce567Kenny Guy            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
188481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                // EXTRA_REPLACING is available Kitkat onwards. For lower devices, it is broadcasted
189481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                // when moving a package or mounting/un-mounting external storage. Assume that
190481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                // it is a replacing operation.
191481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING,
1929fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal                        !Utilities.ATLEAST_KITKAT);
193ed13187a745866483139e2878037e1f8427ce567Kenny Guy                String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
194c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
195c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                    callback.onPackagesAvailable(packages, user, replacing);
196ed13187a745866483139e2878037e1f8427ce567Kenny Guy                }
197ed13187a745866483139e2878037e1f8427ce567Kenny Guy            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
1981a745e8f18e54aff152ff51743ae7595adde6927Sunny Goyal                // This intent is broadcasted when moving a package or mounting/un-mounting
1991a745e8f18e54aff152ff51743ae7595adde6927Sunny Goyal                // external storage.
2001a745e8f18e54aff152ff51743ae7595adde6927Sunny Goyal                // However on Kitkat this is also sent when a package is being updated, and
2011a745e8f18e54aff152ff51743ae7595adde6927Sunny Goyal                // contains an extra Intent.EXTRA_REPLACING=true for that case.
2021a745e8f18e54aff152ff51743ae7595adde6927Sunny Goyal                // Using false as default for Intent.EXTRA_REPLACING gives correct value on
2031a745e8f18e54aff152ff51743ae7595adde6927Sunny Goyal                // lower devices as the intent is not sent when the app is updating/replacing.
2041a745e8f18e54aff152ff51743ae7595adde6927Sunny Goyal                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
205ed13187a745866483139e2878037e1f8427ce567Kenny Guy                String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
206c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
207c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                    callback.onPackagesUnavailable(packages, user, replacing);
208ed13187a745866483139e2878037e1f8427ce567Kenny Guy                }
209ed13187a745866483139e2878037e1f8427ce567Kenny Guy            }
210ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
211ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
212ed13187a745866483139e2878037e1f8427ce567Kenny Guy}
213