blob: b247f65c94c3f98faff68c66b100b3880a9df547 [file] [log] [blame]
Makoto Onuki6f7362d92016-03-04 13:39:41 -08001/*
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 */
16package android.content.pm;
17
18import android.annotation.NonNull;
19import android.content.Context;
20import android.os.RemoteException;
21import android.os.UserHandle;
22import android.util.Log;
23
24import com.android.internal.annotations.VisibleForTesting;
25
26import java.util.List;
27
28/**
29 * TODO Enhance javadoc
30 *
31 * {@link ShortcutManager} manages shortcuts created by applications.
32 *
33 * <h3>Dynamic shortcuts and pinned shortcuts</h3>
34 *
35 * An application can publish shortcuts with {@link #setDynamicShortcuts(List)} and
36 * {@link #addDynamicShortcut(ShortcutInfo)}. There can be at most
37 * {@link #getMaxDynamicShortcutCount()} number of dynamic shortcuts at a time from the same
38 * application.
39 * A dynamic shortcut can be deleted with {@link #deleteDynamicShortcut(String)}, and apps
40 * can also use {@link #deleteAllDynamicShortcuts()} to delete all dynamic shortcuts.
41 *
42 * <p>The shortcuts that are currently published by the above APIs are called "dynamic", because
43 * they can be removed by the creator application at any time. The user may "pin" dynamic shortcuts
44 * on Launcher to make "pinned" shortcuts. Pinned shortcuts <b>cannot</b> be removed by the creator
45 * app. An application can obtain all pinned shortcuts from itself with
46 * {@link #getPinnedShortcuts()}. Applications should keep the pinned shortcut information
47 * up-to-date using {@link #updateShortcuts(List)}.
48 *
49 * <p>The number of pinned shortcuts does not affect the number of dynamic shortcuts that can be
50 * published by an application at a time.
51 * No matter how many pinned shortcuts that Launcher has for an application, the
52 * application can still always publish {@link #getMaxDynamicShortcutCount()} number of dynamic
53 * shortcuts.
54 *
55 * <h3>Shortcut IDs</h3>
56 *
57 * Each shortcut must have an ID, which must be unique within each application. When a shortcut is
58 * published, existing shortcuts with the same ID will be updated. Note this may include a
59 * pinned shortcut.
60 *
61 * <h3>Rate limiting</h3>
62 *
63 * Calls to {@link #setDynamicShortcuts(List)}, {@link #addDynamicShortcut(ShortcutInfo)},
64 * and {@link #updateShortcuts(List)} will be
65 * rate-limited. An application can call these methods at most
66 * {@link #getRemainingCallCount()} times until the rate-limiting counter is reset,
67 * which happens at a certain time every day.
68 *
69 * <p>An applications can use {@link #getRateLimitResetTime()} to get the next reset time.
70 *
71 * <h3>Backup and Restore</h3>
72 *
73 * Shortcuts will be backed up and restored across devices. This means all information, including
74 * IDs, must be meaningful on a different device.
75 *
76 * TODO: Define a Broadcast to let apps update shortcuts on a restored device.
77 *
78 * <h3>APIs for launcher</h3>
79 *
80 * Launcher applications should use {@link LauncherApps} to get shortcuts that are published from
81 * applications. Launcher applications can also pin shortcuts with
82 * {@link LauncherApps#pinShortcuts(String, List, UserHandle)}.
83 */
84public class ShortcutManager {
85 private static final String TAG = "ShortcutManager";
86
87 private final Context mContext;
88 private final IShortcutService mService;
89
90 /**
91 * @hide
92 */
93 public ShortcutManager(Context context, IShortcutService service) {
94 mContext = context;
95 mService = service;
96 }
97
98 /**
99 * Publish a list of shortcuts. All existing dynamic shortcuts from the caller application
100 * will be replaced.
101 *
102 * <p>This API will be rate-limited.
103 *
104 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
105 *
106 * @throws IllegalArgumentException if {@code shortcutInfoList} contains more than
107 * {@link #getMaxDynamicShortcutCount()} shortcuts.
108 */
109 public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
110 try {
111 return mService.setDynamicShortcuts(mContext.getPackageName(),
112 new ParceledListSlice(shortcutInfoList), injectMyUserId());
113 } catch (RemoteException e) {
114 throw e.rethrowFromSystemServer();
115 }
116 }
117
118 /**
119 * Return all dynamic shortcuts from the caller application. The number of result items
120 * will not exceed the value returned by {@link #getMaxDynamicShortcutCount()}.
121 */
122 @NonNull
123 public List<ShortcutInfo> getDynamicShortcuts() {
124 try {
125 return mService.getDynamicShortcuts(mContext.getPackageName(), injectMyUserId())
126 .getList();
127 } catch (RemoteException e) {
128 throw e.rethrowFromSystemServer();
129 }
130 }
131
132 /**
133 * Publish a single dynamic shortcut. If there's already dynamic or pinned shortcuts with
134 * the same ID, they will all be updated.
135 *
136 * <p>This API will be rate-limited.
137 *
138 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
139 *
140 * @throws IllegalArgumentException if the caller application has already published the
141 * max number of dynamic shortcuts.
142 */
143 public boolean addDynamicShortcut(@NonNull ShortcutInfo shortcutInfo) {
144 try {
145 return mService.addDynamicShortcut(
146 mContext.getPackageName(), shortcutInfo, injectMyUserId());
147 } catch (RemoteException e) {
148 throw e.rethrowFromSystemServer();
149 }
150 }
151
152 /**
153 * Delete a single dynamic shortcut by ID.
154 */
155 public void deleteDynamicShortcut(@NonNull String shortcutId) {
156 try {
157 mService.deleteDynamicShortcut(mContext.getPackageName(), shortcutId, injectMyUserId());
158 } catch (RemoteException e) {
159 throw e.rethrowFromSystemServer();
160 }
161 }
162
163 /**
164 * Delete all dynamic shortcuts from the caller application.
165 */
166 public void deleteAllDynamicShortcuts() {
167 try {
168 mService.deleteAllDynamicShortcuts(mContext.getPackageName(), injectMyUserId());
169 } catch (RemoteException e) {
170 throw e.rethrowFromSystemServer();
171 }
172 }
173
174 /**
175 * Return all pinned shortcuts from the caller application.
176 */
177 @NonNull
178 public List<ShortcutInfo> getPinnedShortcuts() {
179 try {
180 return mService.getPinnedShortcuts(mContext.getPackageName(), injectMyUserId())
181 .getList();
182 } catch (RemoteException e) {
183 throw e.rethrowFromSystemServer();
184 }
185 }
186
187 /**
188 * Update all existing shortcuts with the same IDs. Shortcuts may be pinned and/or dynamic.
189 *
190 * <p>This API will be rate-limited.
191 *
192 * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
193 */
194 public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
195 try {
196 return mService.updateShortcuts(mContext.getPackageName(),
197 new ParceledListSlice(shortcutInfoList), injectMyUserId());
198 } catch (RemoteException e) {
199 throw e.rethrowFromSystemServer();
200 }
201 }
202
203 /**
204 * Return the max number of dynamic shortcuts that each application can have at a time.
205 */
206 public int getMaxDynamicShortcutCount() {
207 try {
208 return mService.getMaxDynamicShortcutCount(mContext.getPackageName(), injectMyUserId());
209 } catch (RemoteException e) {
210 throw e.rethrowFromSystemServer();
211 }
212 }
213
214 /**
215 * Return the number of times the caller application can call the rate-limited APIs
216 * before the rate limit counter is reset.
217 *
218 * @see #getRateLimitResetTime()
219 */
220 public int getRemainingCallCount() {
221 try {
222 return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId());
223 } catch (RemoteException e) {
224 throw e.rethrowFromSystemServer();
225 }
226 }
227
228 /**
229 * Return when the rate limit count will be reset next time, in milliseconds since the epoch.
230 *
231 * @see #getRemainingCallCount()
232 * @see System#currentTimeMillis()
233 */
234 public long getRateLimitResetTime() {
235 try {
236 return mService.getRateLimitResetTime(mContext.getPackageName(), injectMyUserId());
237 } catch (RemoteException e) {
238 throw e.rethrowFromSystemServer();
239 }
240 }
241
Makoto Onuki55046222016-03-08 10:49:47 -0800242 /**
243 * Return the max width and height for icons, in pixels.
244 */
245 public int getIconMaxDimensions() {
246 try {
247 return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId());
248 } catch (RemoteException e) {
249 throw e.rethrowFromSystemServer();
250 }
251 }
252
Makoto Onuki6f7362d92016-03-04 13:39:41 -0800253 /** @hide injection point */
254 @VisibleForTesting
255 protected int injectMyUserId() {
256 return UserHandle.myUserId();
257 }
258}