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