1782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal/* 2782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * Copyright (C) 2017 The Android Open Source Project 3782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * 4782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * Licensed under the Apache License, Version 2.0 (the "License"); 5782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * you may not use this file except in compliance with the License. 6782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * You may obtain a copy of the License at 7782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * 8782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * http://www.apache.org/licenses/LICENSE-2.0 9782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * 10782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * Unless required by applicable law or agreed to in writing, software 11782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * distributed under the License is distributed on an "AS IS" BASIS, 12782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * See the License for the specific language governing permissions and 14782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal * limitations under the License. 15782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal */ 16782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal 17782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyalpackage com.android.launcher3.compat; 18782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal 19135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyalimport android.annotation.TargetApi; 20782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyalimport android.content.Context; 2122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport android.content.Intent; 223ff9047221820a01c6510503466f8c78b43fdc6dCharles Heimport android.content.pm.ApplicationInfo; 23782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyalimport android.content.pm.LauncherActivityInfo; 24782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyalimport android.content.pm.LauncherApps; 2522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport android.content.pm.LauncherApps.PinItemRequest; 26135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyalimport android.content.pm.PackageManager; 27b57645fcdb87847edd216e71e3b08107027e0ed3Sunny Goyalimport android.os.Build; 2822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport android.os.Parcelable; 29b57645fcdb87847edd216e71e3b08107027e0ed3Sunny Goyalimport android.os.Process; 30782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyalimport android.os.UserHandle; 3186222d23e28a09a7a26e7a0d4b4830ded2efb384Tony Wickhamimport android.support.annotation.Nullable; 32782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal 3322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport com.android.launcher3.LauncherAppState; 3422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport com.android.launcher3.LauncherModel; 3522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport com.android.launcher3.ShortcutInfo; 3686222d23e28a09a7a26e7a0d4b4830ded2efb384Tony Wickhamimport com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO; 3722ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport com.android.launcher3.graphics.LauncherIcons; 3822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport com.android.launcher3.shortcuts.ShortcutInfoCompat; 3922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyalimport com.android.launcher3.util.LooperExecutor; 4086222d23e28a09a7a26e7a0d4b4830ded2efb384Tony Wickhamimport com.android.launcher3.util.PackageUserKey; 4186222d23e28a09a7a26e7a0d4b4830ded2efb384Tony Wickham 42782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyalimport java.util.ArrayList; 43782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyalimport java.util.List; 44782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal 45135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyal@TargetApi(26) 46782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyalpublic class LauncherAppsCompatVO extends LauncherAppsCompatVL { 47782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal 48782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal LauncherAppsCompatVO(Context context) { 49782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal super(context); 50782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal } 51782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal 52782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal @Override 53ad2e91a216edae0f25bce83a2b058c81953981afSunny Goyal public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) { 54135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyal try { 55135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyal ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user); 56135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyal return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 || !info.enabled 57135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyal ? null : info; 58135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyal } catch (PackageManager.NameNotFoundException e) { 59135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyal return null; 60135c1be5a319b826cbe954a30132a08e3973ffb8Sunny Goyal } 613ff9047221820a01c6510503466f8c78b43fdc6dCharles He } 623ff9047221820a01c6510503466f8c78b43fdc6dCharles He 633ff9047221820a01c6510503466f8c78b43fdc6dCharles He @Override 6486222d23e28a09a7a26e7a0d4b4830ded2efb384Tony Wickham public List<ShortcutConfigActivityInfo> getCustomShortcutActivityList( 6586222d23e28a09a7a26e7a0d4b4830ded2efb384Tony Wickham @Nullable PackageUserKey packageUser) { 66782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal List<ShortcutConfigActivityInfo> result = new ArrayList<>(); 67b57645fcdb87847edd216e71e3b08107027e0ed3Sunny Goyal UserHandle myUser = Process.myUserHandle(); 68782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal 6922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal final List<UserHandle> users; 7022ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal final String packageName; 7122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal if (packageUser == null) { 7222ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal users = UserManagerCompat.getInstance(mContext).getUserProfiles(); 7322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal packageName = null; 7422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } else { 7522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal users = new ArrayList<>(1); 7622ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal users.add(packageUser.mUser); 7722ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal packageName = packageUser.mPackageName; 7822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 7922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal for (UserHandle user : users) { 8022ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal boolean ignoreTargetSdk = myUser.equals(user); 8122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal List<LauncherActivityInfo> activities = 8222ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal mLauncherApps.getShortcutConfigActivityList(packageName, user); 8322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal for (LauncherActivityInfo activityInfo : activities) { 8422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >= 8522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal Build.VERSION_CODES.O) { 8622ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal result.add(new ShortcutConfigActivityInfoVO(activityInfo)); 87782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal } 88782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal } 89782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal } 90782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal 91782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal return result; 92782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal } 9322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal 9422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal /** 9522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * request.accept() will initiate the following flow: 9622ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * -> go-to-system-process for actual processing (a) 9722ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * -> callback-to-launcher on UI thread (b) 9822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * -> post callback on the worker thread (c) 9922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * -> Update model and unpin (in system) any shortcut not in out model. (d) 10022ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * 10122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * Note that (b) will take at-least one frame as it involves posting callback from binder 10222ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * thread to UI thread. 10322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * If (d) happens before we add this shortcut to our model, we will end up unpinning 10422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * the shortcut in the system. 10522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * Here its the caller's responsibility to add the newly created ShortcutInfo immediately 10622ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * to the model (which may involves a single post-to-worker-thread). That will guarantee 10722ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal * that (d) happens after model is updated. 10822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal */ 10922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal @Nullable 11022ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal public static ShortcutInfo createShortcutInfoFromPinItemRequest( 11122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal Context context, final PinItemRequest request, final long acceptDelay) { 11222ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal if (request != null && 11322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal request.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT && 11422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal request.isValid()) { 11522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal 11622ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal if (acceptDelay <= 0) { 11722ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal if (!request.accept()) { 11822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal return null; 11922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 12022ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } else { 12122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal // Block the worker thread until the accept() is called. 12222ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal new LooperExecutor(LauncherModel.getWorkerLooper()).execute(new Runnable() { 12322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal @Override 12422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal public void run() { 12522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal try { 12622ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal Thread.sleep(acceptDelay); 12722ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } catch (InterruptedException e) { 12822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal // Ignore 12922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 13022ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal if (request.isValid()) { 13122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal request.accept(); 13222ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 13322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 13422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal }); 13522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 13622ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal 13722ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo()); 13822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal ShortcutInfo info = new ShortcutInfo(compat, context); 13922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal // Apply the unbadged icon and fetch the actual icon asynchronously. 14022ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal info.iconBitmap = LauncherIcons 14122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal .createShortcutIcon(compat, context, false /* badged */); 14222ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal LauncherAppState.getInstance(context).getModel() 14322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal .updateAndBindShortcutInfo(info, compat); 14422ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal return info; 14522ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } else { 14622ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal return null; 14722ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 14822ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 14922ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal 15022ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal public static PinItemRequest getPinItemRequest(Intent intent) { 15122ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal Parcelable extra = intent.getParcelableExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST); 15222ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal return extra instanceof PinItemRequest ? (PinItemRequest) extra : null; 15322ca9ec137ec8eb70026f90591ae01af7669a3b7Sunny Goyal } 154782f0c9a896db58aeaa60d15f291831b8d7b4c93Sunny Goyal} 155