• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 
17 package com.android.launcher3.compat;
18 
19 import android.annotation.TargetApi;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.content.pm.ApplicationInfo;
23 import android.content.pm.LauncherActivityInfo;
24 import android.content.pm.LauncherApps;
25 import android.content.pm.LauncherApps.PinItemRequest;
26 import android.content.pm.PackageManager;
27 import android.os.Build;
28 import android.os.Parcelable;
29 import android.os.Process;
30 import android.os.UserHandle;
31 import android.support.annotation.Nullable;
32 
33 import com.android.launcher3.LauncherAppState;
34 import com.android.launcher3.LauncherModel;
35 import com.android.launcher3.ShortcutInfo;
36 import com.android.launcher3.compat.ShortcutConfigActivityInfo.ShortcutConfigActivityInfoVO;
37 import com.android.launcher3.graphics.LauncherIcons;
38 import com.android.launcher3.shortcuts.ShortcutInfoCompat;
39 import com.android.launcher3.util.LooperExecutor;
40 import com.android.launcher3.util.PackageUserKey;
41 
42 import java.util.ArrayList;
43 import java.util.List;
44 
45 @TargetApi(26)
46 public class LauncherAppsCompatVO extends LauncherAppsCompatVL {
47 
LauncherAppsCompatVO(Context context)48     LauncherAppsCompatVO(Context context) {
49         super(context);
50     }
51 
52     @Override
getApplicationInfo(String packageName, int flags, UserHandle user)53     public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user) {
54         try {
55             ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user);
56             return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0 || !info.enabled
57                     ? null : info;
58         } catch (PackageManager.NameNotFoundException e) {
59             return null;
60         }
61     }
62 
63     @Override
getCustomShortcutActivityList( @ullable PackageUserKey packageUser)64     public List<ShortcutConfigActivityInfo> getCustomShortcutActivityList(
65             @Nullable PackageUserKey packageUser) {
66         List<ShortcutConfigActivityInfo> result = new ArrayList<>();
67         UserHandle myUser = Process.myUserHandle();
68 
69         final List<UserHandle> users;
70         final String packageName;
71         if (packageUser == null) {
72             users = UserManagerCompat.getInstance(mContext).getUserProfiles();
73             packageName = null;
74         } else {
75             users = new ArrayList<>(1);
76             users.add(packageUser.mUser);
77             packageName = packageUser.mPackageName;
78         }
79         for (UserHandle user : users) {
80             boolean ignoreTargetSdk = myUser.equals(user);
81             List<LauncherActivityInfo> activities =
82                     mLauncherApps.getShortcutConfigActivityList(packageName, user);
83             for (LauncherActivityInfo activityInfo : activities) {
84                 if (ignoreTargetSdk || activityInfo.getApplicationInfo().targetSdkVersion >=
85                         Build.VERSION_CODES.O) {
86                     result.add(new ShortcutConfigActivityInfoVO(activityInfo));
87                 }
88             }
89         }
90 
91         return result;
92     }
93 
94     /**
95      * request.accept() will initiate the following flow:
96      *      -> go-to-system-process for actual processing (a)
97      *      -> callback-to-launcher on UI thread (b)
98      *      -> post callback on the worker thread (c)
99      *      -> Update model and unpin (in system) any shortcut not in out model. (d)
100      *
101      * Note that (b) will take at-least one frame as it involves posting callback from binder
102      * thread to UI thread.
103      * If (d) happens before we add this shortcut to our model, we will end up unpinning
104      * the shortcut in the system.
105      * Here its the caller's responsibility to add the newly created ShortcutInfo immediately
106      * to the model (which may involves a single post-to-worker-thread). That will guarantee
107      * that (d) happens after model is updated.
108      */
109     @Nullable
createShortcutInfoFromPinItemRequest( Context context, final PinItemRequest request, final long acceptDelay)110     public static ShortcutInfo createShortcutInfoFromPinItemRequest(
111             Context context, final PinItemRequest request, final long acceptDelay) {
112         if (request != null &&
113                 request.getRequestType() == PinItemRequest.REQUEST_TYPE_SHORTCUT &&
114                 request.isValid()) {
115 
116             if (acceptDelay <= 0) {
117                 if (!request.accept()) {
118                     return null;
119                 }
120             } else {
121                 // Block the worker thread until the accept() is called.
122                 new LooperExecutor(LauncherModel.getWorkerLooper()).execute(new Runnable() {
123                     @Override
124                     public void run() {
125                         try {
126                             Thread.sleep(acceptDelay);
127                         } catch (InterruptedException e) {
128                             // Ignore
129                         }
130                         if (request.isValid()) {
131                             request.accept();
132                         }
133                     }
134                 });
135             }
136 
137             ShortcutInfoCompat compat = new ShortcutInfoCompat(request.getShortcutInfo());
138             ShortcutInfo info = new ShortcutInfo(compat, context);
139             // Apply the unbadged icon and fetch the actual icon asynchronously.
140             LauncherIcons li = LauncherIcons.obtain(context);
141             li.createShortcutIcon(compat, false /* badged */).applyTo(info);
142             li.recycle();
143             LauncherAppState.getInstance(context).getModel()
144                     .updateAndBindShortcutInfo(info, compat);
145             return info;
146         } else {
147             return null;
148         }
149     }
150 
getPinItemRequest(Intent intent)151     public static PinItemRequest getPinItemRequest(Intent intent) {
152         Parcelable extra = intent.getParcelableExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST);
153         return extra instanceof PinItemRequest ? (PinItemRequest) extra : null;
154     }
155 }
156