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