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;
25cf5d24b21aaff1b6b524874f4609e0c7ebd48458Sunny Goyalimport android.content.pm.PackageInfo;
26ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.pm.PackageManager;
27ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.pm.PackageManager.NameNotFoundException;
28ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.content.pm.ResolveInfo;
29ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.graphics.Rect;
30f07af7b77de0319355e228e8630824d924522d78Kenny Guyimport android.net.Uri;
31ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.os.Build;
32ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport android.os.Bundle;
33f07af7b77de0319355e228e8630824d924522d78Kenny Guyimport android.provider.Settings;
34ed13187a745866483139e2878037e1f8427ce567Kenny Guy
35ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport java.util.ArrayList;
36ed13187a745866483139e2878037e1f8427ce567Kenny Guyimport java.util.List;
37ed13187a745866483139e2878037e1f8427ce567Kenny Guy
38f07af7b77de0319355e228e8630824d924522d78Kenny Guy/**
39f07af7b77de0319355e228e8630824d924522d78Kenny Guy * Version of {@link LauncherAppsCompat} for devices with API level 16.
40f07af7b77de0319355e228e8630824d924522d78Kenny Guy * Devices Pre-L don't support multiple profiles in one launcher so
41f07af7b77de0319355e228e8630824d924522d78Kenny Guy * user parameters are ignored and all methods operate on the current user.
42f07af7b77de0319355e228e8630824d924522d78Kenny Guy */
43ed13187a745866483139e2878037e1f8427ce567Kenny Guypublic class LauncherAppsCompatV16 extends LauncherAppsCompat {
44ed13187a745866483139e2878037e1f8427ce567Kenny Guy
45ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private PackageManager mPm;
46ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private Context mContext;
47c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    private List<OnAppsChangedCallbackCompat> mCallbacks
48c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy            = new ArrayList<OnAppsChangedCallbackCompat>();
49ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private PackageMonitor mPackageMonitor;
50ed13187a745866483139e2878037e1f8427ce567Kenny Guy
51ed13187a745866483139e2878037e1f8427ce567Kenny Guy    LauncherAppsCompatV16(Context context) {
52ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mPm = context.getPackageManager();
53ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext = context;
54ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mPackageMonitor = new PackageMonitor();
55ed13187a745866483139e2878037e1f8427ce567Kenny Guy   }
56ed13187a745866483139e2878037e1f8427ce567Kenny Guy
57ed13187a745866483139e2878037e1f8427ce567Kenny Guy    public List<LauncherActivityInfoCompat> getActivityList(String packageName,
58ed13187a745866483139e2878037e1f8427ce567Kenny Guy            UserHandleCompat user) {
59ed13187a745866483139e2878037e1f8427ce567Kenny Guy        final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
60ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
61ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mainIntent.setPackage(packageName);
62ed13187a745866483139e2878037e1f8427ce567Kenny Guy        List<ResolveInfo> infos = mPm.queryIntentActivities(mainIntent, 0);
63ed13187a745866483139e2878037e1f8427ce567Kenny Guy        List<LauncherActivityInfoCompat> list =
64ed13187a745866483139e2878037e1f8427ce567Kenny Guy                new ArrayList<LauncherActivityInfoCompat>(infos.size());
65ed13187a745866483139e2878037e1f8427ce567Kenny Guy        for (ResolveInfo info : infos) {
66ed13187a745866483139e2878037e1f8427ce567Kenny Guy            list.add(new LauncherActivityInfoCompatV16(mContext, info));
67ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
68ed13187a745866483139e2878037e1f8427ce567Kenny Guy        return list;
69ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
70ed13187a745866483139e2878037e1f8427ce567Kenny Guy
71ed13187a745866483139e2878037e1f8427ce567Kenny Guy    public LauncherActivityInfoCompat resolveActivity(Intent intent, UserHandleCompat user) {
72ed13187a745866483139e2878037e1f8427ce567Kenny Guy        ResolveInfo info = mPm.resolveActivity(intent, 0);
73ed13187a745866483139e2878037e1f8427ce567Kenny Guy        if (info != null) {
74ed13187a745866483139e2878037e1f8427ce567Kenny Guy            return new LauncherActivityInfoCompatV16(mContext, info);
75ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
76ed13187a745866483139e2878037e1f8427ce567Kenny Guy        return null;
77ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
78ed13187a745866483139e2878037e1f8427ce567Kenny Guy
79c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    public void startActivityForProfile(ComponentName component, UserHandleCompat user,
80c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy            Rect sourceBounds, Bundle opts) {
81ed13187a745866483139e2878037e1f8427ce567Kenny Guy        Intent launchIntent = new Intent(Intent.ACTION_MAIN);
82ed13187a745866483139e2878037e1f8427ce567Kenny Guy        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
83ed13187a745866483139e2878037e1f8427ce567Kenny Guy        launchIntent.setComponent(component);
84ed13187a745866483139e2878037e1f8427ce567Kenny Guy        launchIntent.setSourceBounds(sourceBounds);
85ed13187a745866483139e2878037e1f8427ce567Kenny Guy        launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
86ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext.startActivity(launchIntent, opts);
87ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
88ed13187a745866483139e2878037e1f8427ce567Kenny Guy
89f07af7b77de0319355e228e8630824d924522d78Kenny Guy    public void showAppDetailsForProfile(ComponentName component, UserHandleCompat user) {
90f07af7b77de0319355e228e8630824d924522d78Kenny Guy        String packageName = component.getPackageName();
91f07af7b77de0319355e228e8630824d924522d78Kenny Guy        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
92f07af7b77de0319355e228e8630824d924522d78Kenny Guy                Uri.fromParts("package", packageName, null));
93f07af7b77de0319355e228e8630824d924522d78Kenny Guy        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK |
94f07af7b77de0319355e228e8630824d924522d78Kenny Guy                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
95f07af7b77de0319355e228e8630824d924522d78Kenny Guy        mContext.startActivity(intent, null);
96f07af7b77de0319355e228e8630824d924522d78Kenny Guy    }
97f07af7b77de0319355e228e8630824d924522d78Kenny Guy
98c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    public synchronized void addOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
99c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        if (callback != null && !mCallbacks.contains(callback)) {
100c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy            mCallbacks.add(callback);
101c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy            if (mCallbacks.size() == 1) {
102ed13187a745866483139e2878037e1f8427ce567Kenny Guy                registerForPackageIntents();
103ed13187a745866483139e2878037e1f8427ce567Kenny Guy            }
104ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
105ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
106ed13187a745866483139e2878037e1f8427ce567Kenny Guy
107c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    public synchronized void removeOnAppsChangedCallback(OnAppsChangedCallbackCompat callback) {
108c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        mCallbacks.remove(callback);
109c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        if (mCallbacks.size() == 0) {
110ed13187a745866483139e2878037e1f8427ce567Kenny Guy            unregisterForPackageIntents();
111ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
112ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
113ed13187a745866483139e2878037e1f8427ce567Kenny Guy
114ed13187a745866483139e2878037e1f8427ce567Kenny Guy    public boolean isPackageEnabledForProfile(String packageName, UserHandleCompat user) {
115ed13187a745866483139e2878037e1f8427ce567Kenny Guy        try {
116ed13187a745866483139e2878037e1f8427ce567Kenny Guy            PackageInfo info = mPm.getPackageInfo(packageName, 0);
117ed13187a745866483139e2878037e1f8427ce567Kenny Guy            return info != null && info.applicationInfo.enabled;
118ed13187a745866483139e2878037e1f8427ce567Kenny Guy        } catch (NameNotFoundException e) {
119ed13187a745866483139e2878037e1f8427ce567Kenny Guy            return false;
120ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
121ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
122ed13187a745866483139e2878037e1f8427ce567Kenny Guy
123ed13187a745866483139e2878037e1f8427ce567Kenny Guy    public boolean isActivityEnabledForProfile(ComponentName component, UserHandleCompat user) {
124ed13187a745866483139e2878037e1f8427ce567Kenny Guy        try {
125ed13187a745866483139e2878037e1f8427ce567Kenny Guy            ActivityInfo info = mPm.getActivityInfo(component, 0);
126ed13187a745866483139e2878037e1f8427ce567Kenny Guy            return info != null && info.isEnabled();
127ed13187a745866483139e2878037e1f8427ce567Kenny Guy        } catch (NameNotFoundException e) {
128ed13187a745866483139e2878037e1f8427ce567Kenny Guy            return false;
129ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
130ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
131ed13187a745866483139e2878037e1f8427ce567Kenny Guy
132ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private void unregisterForPackageIntents() {
133ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext.unregisterReceiver(mPackageMonitor);
134ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
135ed13187a745866483139e2878037e1f8427ce567Kenny Guy
136ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private void registerForPackageIntents() {
137ed13187a745866483139e2878037e1f8427ce567Kenny Guy        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
138ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
139ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
140ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addDataScheme("package");
141ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext.registerReceiver(mPackageMonitor, filter);
142ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter = new IntentFilter();
143ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
144ed13187a745866483139e2878037e1f8427ce567Kenny Guy        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
145ed13187a745866483139e2878037e1f8427ce567Kenny Guy        mContext.registerReceiver(mPackageMonitor, filter);
146ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
147ed13187a745866483139e2878037e1f8427ce567Kenny Guy
148c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy    private synchronized List<OnAppsChangedCallbackCompat> getCallbacks() {
149c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy        return new ArrayList<OnAppsChangedCallbackCompat>(mCallbacks);
150ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
151ed13187a745866483139e2878037e1f8427ce567Kenny Guy
152ed13187a745866483139e2878037e1f8427ce567Kenny Guy    private class PackageMonitor extends BroadcastReceiver {
153ed13187a745866483139e2878037e1f8427ce567Kenny Guy        public void onReceive(Context context, Intent intent) {
154ed13187a745866483139e2878037e1f8427ce567Kenny Guy            final String action = intent.getAction();
155ed13187a745866483139e2878037e1f8427ce567Kenny Guy            final UserHandleCompat user = UserHandleCompat.myUserHandle();
156ed13187a745866483139e2878037e1f8427ce567Kenny Guy
157ed13187a745866483139e2878037e1f8427ce567Kenny Guy            if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
158ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    || Intent.ACTION_PACKAGE_REMOVED.equals(action)
159ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    || Intent.ACTION_PACKAGE_ADDED.equals(action)) {
160ed13187a745866483139e2878037e1f8427ce567Kenny Guy                final String packageName = intent.getData().getSchemeSpecificPart();
161ed13187a745866483139e2878037e1f8427ce567Kenny Guy                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
162ed13187a745866483139e2878037e1f8427ce567Kenny Guy
163ed13187a745866483139e2878037e1f8427ce567Kenny Guy                if (packageName == null || packageName.length() == 0) {
164ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    // they sent us a bad intent
165ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    return;
166ed13187a745866483139e2878037e1f8427ce567Kenny Guy                }
167ed13187a745866483139e2878037e1f8427ce567Kenny Guy                if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
168c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                    for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
169c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                        callback.onPackageChanged(packageName, user);
170ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    }
171ed13187a745866483139e2878037e1f8427ce567Kenny Guy                } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
172ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    if (!replacing) {
173c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
174c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                            callback.onPackageRemoved(packageName, user);
175ed13187a745866483139e2878037e1f8427ce567Kenny Guy                        }
176ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    }
177ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    // else, we are replacing the package, so a PACKAGE_ADDED will be sent
178ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    // later, we will update the package at this time
179ed13187a745866483139e2878037e1f8427ce567Kenny Guy                } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
180ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    if (!replacing) {
181c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
182c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                            callback.onPackageAdded(packageName, user);
183ed13187a745866483139e2878037e1f8427ce567Kenny Guy                        }
184ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    } else {
185c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                        for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
186c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                            callback.onPackageChanged(packageName, user);
187ed13187a745866483139e2878037e1f8427ce567Kenny Guy                        }
188ed13187a745866483139e2878037e1f8427ce567Kenny Guy                    }
189ed13187a745866483139e2878037e1f8427ce567Kenny Guy                }
190ed13187a745866483139e2878037e1f8427ce567Kenny Guy            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
191481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                // EXTRA_REPLACING is available Kitkat onwards. For lower devices, it is broadcasted
192481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                // when moving a package or mounting/un-mounting external storage. Assume that
193481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                // it is a replacing operation.
194481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING,
195481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                        Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT);
196ed13187a745866483139e2878037e1f8427ce567Kenny Guy                String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
197c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
198c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                    callback.onPackagesAvailable(packages, user, replacing);
199ed13187a745866483139e2878037e1f8427ce567Kenny Guy                }
200ed13187a745866483139e2878037e1f8427ce567Kenny Guy            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
201481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING,
202481c1fb796ea00d725b079a98cd6958247794a83Sunny Goyal                        Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT);
203ed13187a745866483139e2878037e1f8427ce567Kenny Guy                String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
204c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                for (OnAppsChangedCallbackCompat callback : getCallbacks()) {
205c2bd8101b8e26b9ebb2c079ae6867229dad3f196Kenny Guy                    callback.onPackagesUnavailable(packages, user, replacing);
206ed13187a745866483139e2878037e1f8427ce567Kenny Guy                }
207ed13187a745866483139e2878037e1f8427ce567Kenny Guy            }
208ed13187a745866483139e2878037e1f8427ce567Kenny Guy        }
209ed13187a745866483139e2878037e1f8427ce567Kenny Guy    }
210ed13187a745866483139e2878037e1f8427ce567Kenny Guy}
211