• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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.shortcuts;
18 
19 import android.annotation.TargetApi;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.pm.LauncherApps;
23 import android.content.pm.LauncherApps.ShortcutQuery;
24 import android.content.pm.ShortcutInfo;
25 import android.graphics.Rect;
26 import android.graphics.drawable.Drawable;
27 import android.os.Bundle;
28 import android.util.Log;
29 
30 import com.android.launcher3.ItemInfo;
31 import com.android.launcher3.LauncherSettings;
32 import com.android.launcher3.Utilities;
33 import com.android.launcher3.compat.UserHandleCompat;
34 
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.List;
38 
39 /**
40  * Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
41  */
42 public class DeepShortcutManager {
43     private static final String TAG = "DeepShortcutManager";
44 
45     // TODO: Replace this with platform constants when the new sdk is available.
46     public static final int FLAG_MATCH_DYNAMIC = 1 << 0;
47     public static final int FLAG_MATCH_MANIFEST = 1 << 3;
48     public static final int FLAG_MATCH_PINNED = 1 << 1;
49 
50     private static final int FLAG_GET_ALL =
51             FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST;
52 
53     private final LauncherApps mLauncherApps;
54     private boolean mWasLastCallSuccess;
55 
DeepShortcutManager(Context context, ShortcutCache shortcutCache)56     public DeepShortcutManager(Context context, ShortcutCache shortcutCache) {
57         mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
58     }
59 
supportsShortcuts(ItemInfo info)60     public static boolean supportsShortcuts(ItemInfo info) {
61         return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
62     }
63 
wasLastCallSuccess()64     public boolean wasLastCallSuccess() {
65         return mWasLastCallSuccess;
66     }
67 
onShortcutsChanged(List<ShortcutInfoCompat> shortcuts)68     public void onShortcutsChanged(List<ShortcutInfoCompat> shortcuts) {
69         // mShortcutCache.removeShortcuts(shortcuts);
70     }
71 
72     /**
73      * Queries for the shortcuts with the package name and provided ids.
74      *
75      * This method is intended to get the full details for shortcuts when they are added or updated,
76      * because we only get "key" fields in onShortcutsChanged().
77      */
queryForFullDetails(String packageName, List<String> shortcutIds, UserHandleCompat user)78     public List<ShortcutInfoCompat> queryForFullDetails(String packageName,
79             List<String> shortcutIds, UserHandleCompat user) {
80         return query(FLAG_GET_ALL, packageName, null, shortcutIds, user);
81     }
82 
83     /**
84      * Gets all the manifest and dynamic shortcuts associated with the given package and user,
85      * to be displayed in the shortcuts container on long press.
86      */
queryForShortcutsContainer(ComponentName activity, List<String> ids, UserHandleCompat user)87     public List<ShortcutInfoCompat> queryForShortcutsContainer(ComponentName activity,
88             List<String> ids, UserHandleCompat user) {
89         return query(FLAG_MATCH_MANIFEST | FLAG_MATCH_DYNAMIC,
90                 activity.getPackageName(), activity, ids, user);
91     }
92 
93     /**
94      * Removes the given shortcut from the current list of pinned shortcuts.
95      * (Runs on background thread)
96      */
97     @TargetApi(25)
unpinShortcut(final ShortcutKey key)98     public void unpinShortcut(final ShortcutKey key) {
99         if (Utilities.isNycMR1OrAbove()) {
100             String packageName = key.componentName.getPackageName();
101             String id = key.getId();
102             UserHandleCompat user = key.user;
103             List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
104             pinnedIds.remove(id);
105             try {
106                 mLauncherApps.pinShortcuts(packageName, pinnedIds, user.getUser());
107                 mWasLastCallSuccess = true;
108             } catch (SecurityException|IllegalStateException e) {
109                 Log.w(TAG, "Failed to unpin shortcut", e);
110                 mWasLastCallSuccess = false;
111             }
112         }
113     }
114 
115     /**
116      * Adds the given shortcut to the current list of pinned shortcuts.
117      * (Runs on background thread)
118      */
119     @TargetApi(25)
pinShortcut(final ShortcutKey key)120     public void pinShortcut(final ShortcutKey key) {
121         if (Utilities.isNycMR1OrAbove()) {
122             String packageName = key.componentName.getPackageName();
123             String id = key.getId();
124             UserHandleCompat user = key.user;
125             List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
126             pinnedIds.add(id);
127             try {
128                 mLauncherApps.pinShortcuts(packageName, pinnedIds, user.getUser());
129                 mWasLastCallSuccess = true;
130             } catch (SecurityException|IllegalStateException e) {
131                 Log.w(TAG, "Failed to pin shortcut", e);
132                 mWasLastCallSuccess = false;
133             }
134         }
135     }
136 
137     @TargetApi(25)
startShortcut(String packageName, String id, Rect sourceBounds, Bundle startActivityOptions, UserHandleCompat user)138     public void startShortcut(String packageName, String id, Rect sourceBounds,
139           Bundle startActivityOptions, UserHandleCompat user) {
140         if (Utilities.isNycMR1OrAbove()) {
141             try {
142                 mLauncherApps.startShortcut(packageName, id, sourceBounds,
143                         startActivityOptions, user.getUser());
144                 mWasLastCallSuccess = true;
145             } catch (SecurityException|IllegalStateException e) {
146                 Log.e(TAG, "Failed to start shortcut", e);
147                 mWasLastCallSuccess = false;
148             }
149         }
150     }
151 
152     @TargetApi(25)
getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density)153     public Drawable getShortcutIconDrawable(ShortcutInfoCompat shortcutInfo, int density) {
154         if (Utilities.isNycMR1OrAbove()) {
155             try {
156                 Drawable icon = mLauncherApps.getShortcutIconDrawable(
157                         shortcutInfo.getShortcutInfo(), density);
158                 mWasLastCallSuccess = true;
159                 return icon;
160             } catch (SecurityException|IllegalStateException e) {
161                 Log.e(TAG, "Failed to get shortcut icon", e);
162                 mWasLastCallSuccess = false;
163             }
164         }
165         return null;
166     }
167 
168     /**
169      * Returns the id's of pinned shortcuts associated with the given package and user.
170      *
171      * If packageName is null, returns all pinned shortcuts regardless of package.
172      */
queryForPinnedShortcuts(String packageName, UserHandleCompat user)173     public List<ShortcutInfoCompat> queryForPinnedShortcuts(String packageName,
174             UserHandleCompat user) {
175         return query(FLAG_MATCH_PINNED, packageName, null, null, user);
176     }
177 
queryForAllShortcuts(UserHandleCompat user)178     public List<ShortcutInfoCompat> queryForAllShortcuts(UserHandleCompat user) {
179         return query(FLAG_GET_ALL, null, null, null, user);
180     }
181 
extractIds(List<ShortcutInfoCompat> shortcuts)182     private List<String> extractIds(List<ShortcutInfoCompat> shortcuts) {
183         List<String> shortcutIds = new ArrayList<>(shortcuts.size());
184         for (ShortcutInfoCompat shortcut : shortcuts) {
185             shortcutIds.add(shortcut.getId());
186         }
187         return shortcutIds;
188     }
189 
190     /**
191      * Query the system server for all the shortcuts matching the given parameters.
192      * If packageName == null, we query for all shortcuts with the passed flags, regardless of app.
193      *
194      * TODO: Use the cache to optimize this so we don't make an RPC every time.
195      */
196     @TargetApi(25)
query(int flags, String packageName, ComponentName activity, List<String> shortcutIds, UserHandleCompat user)197     private List<ShortcutInfoCompat> query(int flags, String packageName,
198             ComponentName activity, List<String> shortcutIds, UserHandleCompat user) {
199         if (Utilities.isNycMR1OrAbove()) {
200             ShortcutQuery q = new ShortcutQuery();
201             q.setQueryFlags(flags);
202             if (packageName != null) {
203                 q.setPackage(packageName);
204                 q.setActivity(activity);
205                 q.setShortcutIds(shortcutIds);
206             }
207             List<ShortcutInfo> shortcutInfos = null;
208             try {
209                 shortcutInfos = mLauncherApps.getShortcuts(q, user.getUser());
210                 mWasLastCallSuccess = true;
211             } catch (SecurityException|IllegalStateException e) {
212                 Log.e(TAG, "Failed to query for shortcuts", e);
213                 mWasLastCallSuccess = false;
214             }
215             if (shortcutInfos == null) {
216                 return Collections.EMPTY_LIST;
217             }
218             List<ShortcutInfoCompat> shortcutInfoCompats = new ArrayList<>(shortcutInfos.size());
219             for (ShortcutInfo shortcutInfo : shortcutInfos) {
220                 shortcutInfoCompats.add(new ShortcutInfoCompat(shortcutInfo));
221             }
222             return shortcutInfoCompats;
223         } else {
224             return Collections.EMPTY_LIST;
225         }
226     }
227 
228     @TargetApi(25)
hasHostPermission()229     public boolean hasHostPermission() {
230         if (Utilities.isNycMR1OrAbove()) {
231             try {
232                 return mLauncherApps.hasShortcutHostPermission();
233             } catch (SecurityException|IllegalStateException e) {
234                 Log.e(TAG, "Failed to make shortcut manager call", e);
235             }
236         }
237         return false;
238     }
239 }
240