ShortcutManagerTest2.java revision 76269928e677725e2d9b28e2e3aa79961a60a1d0
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 */
16package com.android.server.pm;
17
18import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundlesEqual;
19import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
20import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertWith;
21import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
22import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
23import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.parceled;
24import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
25
26import static org.mockito.Matchers.anyInt;
27import static org.mockito.Matchers.anyString;
28import static org.mockito.Matchers.eq;
29import static org.mockito.Mockito.reset;
30import static org.mockito.Mockito.times;
31import static org.mockito.Mockito.verify;
32
33import android.Manifest.permission;
34import android.app.ActivityManager;
35import android.content.ComponentName;
36import android.content.Intent;
37import android.content.pm.ShortcutInfo;
38import android.content.res.Resources;
39import android.graphics.BitmapFactory;
40import android.graphics.drawable.Icon;
41import android.net.Uri;
42import android.os.PersistableBundle;
43import android.os.UserHandle;
44import android.test.MoreAsserts;
45import android.test.suitebuilder.annotation.SmallTest;
46
47import com.android.frameworks.servicestests.R;
48import com.android.server.pm.ShortcutService.ConfigConstants;
49
50import java.io.File;
51import java.io.IOException;
52import java.io.PrintWriter;
53import java.io.StringWriter;
54import java.util.Locale;
55
56/**
57 * Tests for ShortcutService and ShortcutManager.
58 *
59 m FrameworksServicesTests &&
60 adb install \
61 -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
62 adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest2 \
63 -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
64 */
65@SmallTest
66public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
67    // ShortcutInfo tests
68
69    public void testShortcutInfoMissingMandatoryFields() {
70        // Disable throttling.
71        mService.updateConfigurationLocked(
72                ShortcutService.ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=99999999,"
73                + ShortcutService.ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999"
74        );
75
76        assertExpectException(
77                IllegalArgumentException.class,
78                "ID must be provided",
79                () -> new ShortcutInfo.Builder(getTestContext()).build());
80
81        assertExpectException(
82                RuntimeException.class,
83                "id cannot be empty",
84                () -> new ShortcutInfo.Builder(getTestContext(), null));
85
86        assertExpectException(
87                RuntimeException.class,
88                "id cannot be empty",
89                () -> new ShortcutInfo.Builder(getTestContext(), ""));
90
91        assertExpectException(
92                RuntimeException.class,
93                "intent cannot be null",
94                () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(null));
95
96        assertExpectException(
97                RuntimeException.class,
98                "action must be set",
99                () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
100
101        assertExpectException(
102                RuntimeException.class,
103                "activity cannot be null",
104                () -> new ShortcutInfo.Builder(getTestContext(), "id").setActivity(null));
105
106        assertExpectException(
107                RuntimeException.class,
108                "shortLabel cannot be empty",
109                () -> new ShortcutInfo.Builder(getTestContext(), "id").setShortLabel(null));
110
111        assertExpectException(
112                RuntimeException.class,
113                "shortLabel cannot be empty",
114                () -> new ShortcutInfo.Builder(getTestContext(), "id").setShortLabel(""));
115
116        assertExpectException(
117                RuntimeException.class,
118                "longLabel cannot be empty",
119                () -> new ShortcutInfo.Builder(getTestContext(), "id").setLongLabel(null));
120
121        assertExpectException(
122                RuntimeException.class,
123                "longLabel cannot be empty",
124                () -> new ShortcutInfo.Builder(getTestContext(), "id").setLongLabel(""));
125
126        assertExpectException(
127                RuntimeException.class,
128                "disabledMessage cannot be empty",
129                () -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage(null));
130
131        assertExpectException(
132                RuntimeException.class,
133                "disabledMessage cannot be empty",
134                () -> new ShortcutInfo.Builder(getTestContext(), "id").setDisabledMessage(""));
135
136        assertExpectException(NullPointerException.class, "action must be set",
137                () -> new ShortcutInfo.Builder(getTestContext(), "id").setIntent(new Intent()));
138
139        assertExpectException(
140                IllegalArgumentException.class, "Short label must be provided", () -> {
141            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
142                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
143                    .build();
144            assertTrue(getManager().setDynamicShortcuts(list(si)));
145        });
146
147        // same for add.
148        assertExpectException(
149                IllegalArgumentException.class, "Short label must be provided", () -> {
150            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
151                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
152                    .build();
153            assertTrue(getManager().addDynamicShortcuts(list(si)));
154        });
155
156        assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
157            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
158                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
159                    .setShortLabel("x")
160                    .build();
161            assertTrue(getManager().setDynamicShortcuts(list(si)));
162        });
163
164        // same for add.
165        assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
166            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
167                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
168                    .setShortLabel("x")
169                    .build();
170            assertTrue(getManager().addDynamicShortcuts(list(si)));
171        });
172
173        assertExpectException(
174                IllegalStateException.class, "does not belong to package", () -> {
175            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
176                    .setActivity(new ComponentName("xxx", "s"))
177                    .build();
178            assertTrue(getManager().setDynamicShortcuts(list(si)));
179        });
180
181        // same for add.
182        assertExpectException(
183                IllegalStateException.class, "does not belong to package", () -> {
184            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
185                    .setActivity(new ComponentName("xxx", "s"))
186                    .build();
187            assertTrue(getManager().addDynamicShortcuts(list(si)));
188        });
189
190        // Now all activities are not main.
191        mMainActivityChecker = (component, userId) -> false;
192
193        assertExpectException(
194                IllegalStateException.class, "is not main", () -> {
195                    ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
196                            .setActivity(new ComponentName(getTestContext(), "s"))
197                            .build();
198                    assertTrue(getManager().setDynamicShortcuts(list(si)));
199                });
200        // For add
201        assertExpectException(
202                IllegalStateException.class, "is not main", () -> {
203                    ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
204                            .setActivity(new ComponentName(getTestContext(), "s"))
205                            .build();
206                    assertTrue(getManager().addDynamicShortcuts(list(si)));
207                });
208        // For update
209        assertExpectException(
210                IllegalStateException.class, "is not main", () -> {
211                    ShortcutInfo si = new ShortcutInfo.Builder(getTestContext(), "id")
212                            .setActivity(new ComponentName(getTestContext(), "s"))
213                            .build();
214                    assertTrue(getManager().updateShortcuts(list(si)));
215                });
216    }
217
218    public void testShortcutInfoParcel() {
219        setCaller(CALLING_PACKAGE_1, USER_10);
220        ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)
221                .setId("id")
222                .setTitle("title")
223                .setIntent(makeIntent("action", ShortcutActivity.class))
224                .build());
225        assertEquals(mClientContext.getPackageName(), si.getPackage());
226        assertEquals(USER_10, si.getUserId());
227        assertEquals(HANDLE_USER_10, si.getUserHandle());
228        assertEquals("id", si.getId());
229        assertEquals("title", si.getTitle());
230        assertEquals("action", si.getIntent().getAction());
231
232        PersistableBundle pb = new PersistableBundle();
233        pb.putInt("k", 1);
234
235        si = new ShortcutInfo.Builder(getTestContext())
236                .setId("id")
237                .setActivity(new ComponentName("a", "b"))
238                .setIcon(Icon.createWithResource(mClientContext, 123))
239                .setTitle("title")
240                .setText("text")
241                .setDisabledMessage("dismes")
242                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
243                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
244                .setRank(123)
245                .setExtras(pb)
246                .build();
247        si.addFlags(ShortcutInfo.FLAG_PINNED);
248        si.setBitmapPath("abc");
249        si.setIconResourceId(456);
250
251        si = parceled(si);
252
253        assertEquals(getTestContext().getPackageName(), si.getPackage());
254        assertEquals("id", si.getId());
255        assertEquals(new ComponentName("a", "b"), si.getActivity());
256        assertEquals(123, si.getIcon().getResId());
257        assertEquals("title", si.getTitle());
258        assertEquals("text", si.getText());
259        assertEquals("dismes", si.getDisabledMessage());
260        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
261        assertEquals("action", si.getIntent().getAction());
262        assertEquals("val", si.getIntent().getStringExtra("key"));
263        assertEquals(123, si.getRank());
264        assertEquals(1, si.getExtras().getInt("k"));
265
266        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
267        assertEquals("abc", si.getBitmapPath());
268        assertEquals(456, si.getIconResourceId());
269
270        assertEquals(0, si.getTitleResId());
271        assertEquals(null, si.getTitleResName());
272        assertEquals(0, si.getTextResId());
273        assertEquals(null, si.getTextResName());
274        assertEquals(0, si.getDisabledMessageResourceId());
275        assertEquals(null, si.getDisabledMessageResName());
276    }
277
278    public void testShortcutInfoParcel_resId() {
279        setCaller(CALLING_PACKAGE_1, USER_10);
280        ShortcutInfo si;
281
282        PersistableBundle pb = new PersistableBundle();
283        pb.putInt("k", 1);
284
285        si = new ShortcutInfo.Builder(getTestContext())
286                .setId("id")
287                .setActivity(new ComponentName("a", "b"))
288                .setIcon(Icon.createWithResource(mClientContext, 123))
289                .setTitleResId(10)
290                .setTextResId(11)
291                .setDisabledMessageResId(12)
292                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
293                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
294                .setRank(123)
295                .setExtras(pb)
296                .build();
297        si.addFlags(ShortcutInfo.FLAG_PINNED);
298        si.setBitmapPath("abc");
299        si.setIconResourceId(456);
300
301        lookupAndFillInResourceNames(si);
302
303        si = parceled(si);
304
305        assertEquals(getTestContext().getPackageName(), si.getPackage());
306        assertEquals("id", si.getId());
307        assertEquals(new ComponentName("a", "b"), si.getActivity());
308        assertEquals(123, si.getIcon().getResId());
309        assertEquals(10, si.getTitleResId());
310        assertEquals("r10", si.getTitleResName());
311        assertEquals(11, si.getTextResId());
312        assertEquals("r11", si.getTextResName());
313        assertEquals(12, si.getDisabledMessageResourceId());
314        assertEquals("r12", si.getDisabledMessageResName());
315        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
316        assertEquals("action", si.getIntent().getAction());
317        assertEquals("val", si.getIntent().getStringExtra("key"));
318        assertEquals(123, si.getRank());
319        assertEquals(1, si.getExtras().getInt("k"));
320
321        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
322        assertEquals("abc", si.getBitmapPath());
323        assertEquals(456, si.getIconResourceId());
324        assertEquals("string/r456", si.getIconResName());
325    }
326
327    public void testShortcutInfoClone() {
328        setCaller(CALLING_PACKAGE_1, USER_11);
329
330        PersistableBundle pb = new PersistableBundle();
331        pb.putInt("k", 1);
332        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
333                .setId("id")
334                .setActivity(new ComponentName("a", "b"))
335                .setIcon(Icon.createWithResource(mClientContext, 123))
336                .setTitle("title")
337                .setText("text")
338                .setDisabledMessage("dismes")
339                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
340                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
341                .setRank(123)
342                .setExtras(pb)
343                .build();
344        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
345        sorig.setBitmapPath("abc");
346        sorig.setIconResourceId(456);
347
348        lookupAndFillInResourceNames(sorig);
349
350        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
351
352        assertEquals(USER_11, si.getUserId());
353        assertEquals(HANDLE_USER_11, si.getUserHandle());
354        assertEquals(mClientContext.getPackageName(), si.getPackage());
355        assertEquals("id", si.getId());
356        assertEquals(new ComponentName("a", "b"), si.getActivity());
357        assertEquals(123, si.getIcon().getResId());
358        assertEquals("title", si.getTitle());
359        assertEquals("text", si.getText());
360        assertEquals("dismes", si.getDisabledMessage());
361        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
362        assertEquals("action", si.getIntent().getAction());
363        assertEquals("val", si.getIntent().getStringExtra("key"));
364        assertEquals(123, si.getRank());
365        assertEquals(1, si.getExtras().getInt("k"));
366
367        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
368        assertEquals("abc", si.getBitmapPath());
369        assertEquals(456, si.getIconResourceId());
370        assertEquals("string/r456", si.getIconResName());
371
372        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
373
374        assertEquals(mClientContext.getPackageName(), si.getPackage());
375        assertEquals("id", si.getId());
376        assertEquals(new ComponentName("a", "b"), si.getActivity());
377        assertEquals(null, si.getIcon());
378        assertEquals("title", si.getTitle());
379        assertEquals("text", si.getText());
380        assertEquals("dismes", si.getDisabledMessage());
381        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
382        assertEquals("action", si.getIntent().getAction());
383        assertEquals("val", si.getIntent().getStringExtra("key"));
384        assertEquals(123, si.getRank());
385        assertEquals(1, si.getExtras().getInt("k"));
386
387        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
388        assertEquals(null, si.getBitmapPath());
389
390        assertEquals(456, si.getIconResourceId());
391        assertEquals(null, si.getIconResName());
392
393        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
394
395        assertEquals(mClientContext.getPackageName(), si.getPackage());
396        assertEquals("id", si.getId());
397        assertEquals(new ComponentName("a", "b"), si.getActivity());
398        assertEquals(null, si.getIcon());
399        assertEquals("title", si.getTitle());
400        assertEquals("text", si.getText());
401        assertEquals("dismes", si.getDisabledMessage());
402        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
403        assertEquals(null, si.getIntent());
404        assertEquals(123, si.getRank());
405        assertEquals(1, si.getExtras().getInt("k"));
406
407        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
408        assertEquals(null, si.getBitmapPath());
409
410        assertEquals(456, si.getIconResourceId());
411        assertEquals(null, si.getIconResName());
412
413        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
414
415        assertEquals(mClientContext.getPackageName(), si.getPackage());
416        assertEquals("id", si.getId());
417        assertEquals(new ComponentName("a", "b"), si.getActivity());
418        assertEquals(null, si.getIcon());
419        assertEquals(null, si.getTitle());
420        assertEquals(null, si.getText());
421        assertEquals(null, si.getDisabledMessage());
422        assertEquals(null, si.getCategories());
423        assertEquals(null, si.getIntent());
424        assertEquals(0, si.getRank());
425        assertEquals(null, si.getExtras());
426
427        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
428        assertEquals(null, si.getBitmapPath());
429
430        assertEquals(456, si.getIconResourceId());
431        assertEquals(null, si.getIconResName());
432    }
433
434    public void testShortcutInfoClone_resId() {
435        setCaller(CALLING_PACKAGE_1, USER_11);
436
437        PersistableBundle pb = new PersistableBundle();
438        pb.putInt("k", 1);
439        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
440                .setId("id")
441                .setActivity(new ComponentName("a", "b"))
442                .setIcon(Icon.createWithResource(mClientContext, 123))
443                .setTitleResId(10)
444                .setTextResId(11)
445                .setDisabledMessageResId(12)
446                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
447                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
448                .setRank(123)
449                .setExtras(pb)
450                .build();
451        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
452        sorig.setBitmapPath("abc");
453        sorig.setIconResourceId(456);
454
455        lookupAndFillInResourceNames(sorig);
456
457        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
458
459        assertEquals(USER_11, si.getUserId());
460        assertEquals(HANDLE_USER_11, si.getUserHandle());
461        assertEquals(mClientContext.getPackageName(), si.getPackage());
462        assertEquals("id", si.getId());
463        assertEquals(new ComponentName("a", "b"), si.getActivity());
464        assertEquals(123, si.getIcon().getResId());
465        assertEquals(10, si.getTitleResId());
466        assertEquals("r10", si.getTitleResName());
467        assertEquals(11, si.getTextResId());
468        assertEquals("r11", si.getTextResName());
469        assertEquals(12, si.getDisabledMessageResourceId());
470        assertEquals("r12", si.getDisabledMessageResName());
471        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
472        assertEquals("action", si.getIntent().getAction());
473        assertEquals("val", si.getIntent().getStringExtra("key"));
474        assertEquals(123, si.getRank());
475        assertEquals(1, si.getExtras().getInt("k"));
476
477        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
478        assertEquals("abc", si.getBitmapPath());
479        assertEquals(456, si.getIconResourceId());
480        assertEquals("string/r456", si.getIconResName());
481
482        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
483
484        assertEquals(mClientContext.getPackageName(), si.getPackage());
485        assertEquals("id", si.getId());
486        assertEquals(new ComponentName("a", "b"), si.getActivity());
487        assertEquals(null, si.getIcon());
488        assertEquals(10, si.getTitleResId());
489        assertEquals(null, si.getTitleResName());
490        assertEquals(11, si.getTextResId());
491        assertEquals(null, si.getTextResName());
492        assertEquals(12, si.getDisabledMessageResourceId());
493        assertEquals(null, si.getDisabledMessageResName());
494        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
495        assertEquals("action", si.getIntent().getAction());
496        assertEquals("val", si.getIntent().getStringExtra("key"));
497        assertEquals(123, si.getRank());
498        assertEquals(1, si.getExtras().getInt("k"));
499
500        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
501        assertEquals(null, si.getBitmapPath());
502
503        assertEquals(456, si.getIconResourceId());
504        assertEquals(null, si.getIconResName());
505
506        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
507
508        assertEquals(mClientContext.getPackageName(), si.getPackage());
509        assertEquals("id", si.getId());
510        assertEquals(new ComponentName("a", "b"), si.getActivity());
511        assertEquals(null, si.getIcon());
512        assertEquals(10, si.getTitleResId());
513        assertEquals(null, si.getTitleResName());
514        assertEquals(11, si.getTextResId());
515        assertEquals(null, si.getTextResName());
516        assertEquals(12, si.getDisabledMessageResourceId());
517        assertEquals(null, si.getDisabledMessageResName());
518        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
519        assertEquals(null, si.getIntent());
520        assertEquals(123, si.getRank());
521        assertEquals(1, si.getExtras().getInt("k"));
522
523        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
524        assertEquals(null, si.getBitmapPath());
525
526        assertEquals(456, si.getIconResourceId());
527        assertEquals(null, si.getIconResName());
528
529        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
530
531        assertEquals(mClientContext.getPackageName(), si.getPackage());
532        assertEquals("id", si.getId());
533        assertEquals(new ComponentName("a", "b"), si.getActivity());
534        assertEquals(null, si.getIcon());
535        assertEquals(0, si.getTitleResId());
536        assertEquals(null, si.getTitleResName());
537        assertEquals(0, si.getTextResId());
538        assertEquals(null, si.getTextResName());
539        assertEquals(0, si.getDisabledMessageResourceId());
540        assertEquals(null, si.getDisabledMessageResName());
541        assertEquals(null, si.getCategories());
542        assertEquals(null, si.getIntent());
543        assertEquals(0, si.getRank());
544        assertEquals(null, si.getExtras());
545
546        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
547        assertEquals(null, si.getBitmapPath());
548
549        assertEquals(456, si.getIconResourceId());
550        assertEquals(null, si.getIconResName());
551    }
552
553    public void testShortcutInfoClone_minimum() {
554        PersistableBundle pb = new PersistableBundle();
555        pb.putInt("k", 1);
556        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
557                .setId("id")
558                .setTitle("title")
559                .setIntent(makeIntent("action", ShortcutActivity.class))
560                .build();
561        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
562
563        assertEquals(getTestContext().getPackageName(), si.getPackage());
564        assertEquals("id", si.getId());
565        assertEquals("title", si.getTitle());
566        assertEquals("action", si.getIntent().getAction());
567        assertEquals(null, si.getCategories());
568
569        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
570
571        assertEquals(getTestContext().getPackageName(), si.getPackage());
572        assertEquals("id", si.getId());
573        assertEquals("title", si.getTitle());
574        assertEquals("action", si.getIntent().getAction());
575        assertEquals(null, si.getCategories());
576
577        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
578
579        assertEquals(getTestContext().getPackageName(), si.getPackage());
580        assertEquals("id", si.getId());
581        assertEquals("title", si.getTitle());
582        assertEquals(null, si.getIntent());
583        assertEquals(null, si.getCategories());
584
585        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
586
587        assertEquals(getTestContext().getPackageName(), si.getPackage());
588        assertEquals("id", si.getId());
589        assertEquals(null, si.getTitle());
590        assertEquals(null, si.getIntent());
591        assertEquals(null, si.getCategories());
592    }
593
594    public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
595        PersistableBundle pb = new PersistableBundle();
596        pb.putInt("k", 1);
597        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
598                .setId("id")
599                .setActivity(new ComponentName("a", "b"))
600                .setIcon(Icon.createWithResource(mClientContext, 123))
601                .setTitle("title")
602                .setText("text")
603                .setDisabledMessage("dismes")
604                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
605                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
606                .setRank(123)
607                .setExtras(pb)
608                .build();
609        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
610        sorig.setBitmapPath("abc");
611        sorig.setIconResourceId(456);
612
613        lookupAndFillInResourceNames(sorig);
614
615        ShortcutInfo si;
616
617        si = sorig.clone(/* flags=*/ 0);
618        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
619                .setActivity(new ComponentName("x", "y")).build());
620        assertEquals("text", si.getText());
621        assertEquals(123, si.getRank());
622        assertEquals(new ComponentName("x", "y"), si.getActivity());
623
624        si = sorig.clone(/* flags=*/ 0);
625        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
626                .setIcon(Icon.createWithResource(mClientContext, 456)).build());
627        assertEquals("text", si.getText());
628        assertEquals(456, si.getIcon().getResId());
629        assertEquals(0, si.getIconResourceId());
630        assertEquals(null, si.getIconResName());
631        assertEquals(null, si.getBitmapPath());
632
633        si = sorig.clone(/* flags=*/ 0);
634        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
635                .setTitle("xyz").build());
636        assertEquals("text", si.getText());
637        assertEquals("xyz", si.getTitle());
638        assertEquals(0, si.getTitleResId());
639
640        si = sorig.clone(/* flags=*/ 0);
641        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
642                .setTitleResId(123).build());
643        assertEquals("text", si.getText());
644        assertEquals(null, si.getTitle());
645        assertEquals(123, si.getTitleResId());
646
647        si = sorig.clone(/* flags=*/ 0);
648        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
649                .setText("xxx").build());
650        assertEquals(123, si.getRank());
651        assertEquals("xxx", si.getText());
652        assertEquals(0, si.getTextResId());
653
654        si = sorig.clone(/* flags=*/ 0);
655        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
656                .setTextResId(1111).build());
657        assertEquals(123, si.getRank());
658        assertEquals(null, si.getText());
659        assertEquals(1111, si.getTextResId());
660
661        si = sorig.clone(/* flags=*/ 0);
662        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
663                .setDisabledMessage("xxx").build());
664        assertEquals(123, si.getRank());
665        assertEquals("xxx", si.getDisabledMessage());
666        assertEquals(0, si.getDisabledMessageResourceId());
667
668        si = sorig.clone(/* flags=*/ 0);
669        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
670                .setDisabledMessageResId(11111).build());
671        assertEquals(123, si.getRank());
672        assertEquals(null, si.getDisabledMessage());
673        assertEquals(11111, si.getDisabledMessageResourceId());
674
675        si = sorig.clone(/* flags=*/ 0);
676        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
677                .setCategories(set()).build());
678        assertEquals("text", si.getText());
679        assertEquals(set(), si.getCategories());
680
681        si = sorig.clone(/* flags=*/ 0);
682        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
683                .setCategories(set("x")).build());
684        assertEquals("text", si.getText());
685        assertEquals(set("x"), si.getCategories());
686
687        si = sorig.clone(/* flags=*/ 0);
688        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
689                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
690        assertEquals("text", si.getText());
691        assertEquals("action2", si.getIntent().getAction());
692        assertEquals(null, si.getIntent().getStringExtra("key"));
693
694        si = sorig.clone(/* flags=*/ 0);
695        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
696                .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
697        assertEquals("text", si.getText());
698        assertEquals("action3", si.getIntent().getAction());
699        assertEquals("x", si.getIntent().getStringExtra("key"));
700
701        si = sorig.clone(/* flags=*/ 0);
702        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
703                .setRank(999).build());
704        assertEquals("text", si.getText());
705        assertEquals(999, si.getRank());
706
707
708        PersistableBundle pb2 = new PersistableBundle();
709        pb2.putInt("x", 99);
710
711        si = sorig.clone(/* flags=*/ 0);
712        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
713                .setExtras(pb2).build());
714        assertEquals("text", si.getText());
715        assertEquals(99, si.getExtras().getInt("x"));
716    }
717
718    public void testShortcutInfoCopyNonNullFieldsFrom_resId() throws InterruptedException {
719        PersistableBundle pb = new PersistableBundle();
720        pb.putInt("k", 1);
721        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
722                .setId("id")
723                .setActivity(new ComponentName("a", "b"))
724                .setIcon(Icon.createWithResource(mClientContext, 123))
725                .setTitleResId(10)
726                .setTextResId(11)
727                .setDisabledMessageResId(12)
728                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
729                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
730                .setRank(123)
731                .setExtras(pb)
732                .build();
733        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
734        sorig.setBitmapPath("abc");
735        sorig.setIconResourceId(456);
736
737        ShortcutInfo si;
738
739        si = sorig.clone(/* flags=*/ 0);
740        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
741                .setActivity(new ComponentName("x", "y")).build());
742        assertEquals(11, si.getTextResId());
743        assertEquals(new ComponentName("x", "y"), si.getActivity());
744
745        si = sorig.clone(/* flags=*/ 0);
746        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
747                .setIcon(Icon.createWithResource(mClientContext, 456)).build());
748        assertEquals(11, si.getTextResId());
749        assertEquals(456, si.getIcon().getResId());
750        assertEquals(0, si.getIconResourceId());
751        assertEquals(null, si.getIconResName());
752        assertEquals(null, si.getBitmapPath());
753
754        si = sorig.clone(/* flags=*/ 0);
755        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
756                .setTitle("xyz").build());
757        assertEquals(11, si.getTextResId());
758        assertEquals("xyz", si.getTitle());
759        assertEquals(0, si.getTitleResId());
760        assertEquals(null, si.getTitleResName());
761
762        si = sorig.clone(/* flags=*/ 0);
763        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
764                .setTitleResId(123).build());
765        assertEquals(11, si.getTextResId());
766        assertEquals(null, si.getTitle());
767        assertEquals(123, si.getTitleResId());
768        assertEquals(null, si.getTitleResName());
769
770        si = sorig.clone(/* flags=*/ 0);
771        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
772                .setText("xxx").build());
773        assertEquals(123, si.getRank());
774        assertEquals("xxx", si.getText());
775        assertEquals(0, si.getTextResId());
776        assertEquals(null, si.getTextResName());
777
778        si = sorig.clone(/* flags=*/ 0);
779        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
780                .setTextResId(1111).build());
781        assertEquals(123, si.getRank());
782        assertEquals(null, si.getText());
783        assertEquals(1111, si.getTextResId());
784        assertEquals(null, si.getTextResName());
785
786        si = sorig.clone(/* flags=*/ 0);
787        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
788                .setDisabledMessage("xxx").build());
789        assertEquals(123, si.getRank());
790        assertEquals("xxx", si.getDisabledMessage());
791        assertEquals(0, si.getDisabledMessageResourceId());
792        assertEquals(null, si.getDisabledMessageResName());
793
794        si = sorig.clone(/* flags=*/ 0);
795        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
796                .setDisabledMessageResId(11111).build());
797        assertEquals(123, si.getRank());
798        assertEquals(null, si.getDisabledMessage());
799        assertEquals(11111, si.getDisabledMessageResourceId());
800        assertEquals(null, si.getDisabledMessageResName());
801
802        si = sorig.clone(/* flags=*/ 0);
803        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
804                .setCategories(set()).build());
805        assertEquals(11, si.getTextResId());
806        assertEquals(set(), si.getCategories());
807
808        si = sorig.clone(/* flags=*/ 0);
809        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
810                .setCategories(set("x")).build());
811        assertEquals(11, si.getTextResId());
812        assertEquals(set("x"), si.getCategories());
813
814        si = sorig.clone(/* flags=*/ 0);
815        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
816                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
817        assertEquals(11, si.getTextResId());
818        assertEquals("action2", si.getIntent().getAction());
819        assertEquals(null, si.getIntent().getStringExtra("key"));
820
821        si = sorig.clone(/* flags=*/ 0);
822        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
823                .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
824        assertEquals(11, si.getTextResId());
825        assertEquals("action3", si.getIntent().getAction());
826        assertEquals("x", si.getIntent().getStringExtra("key"));
827
828        si = sorig.clone(/* flags=*/ 0);
829        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
830                .setRank(999).build());
831        assertEquals(11, si.getTextResId());
832        assertEquals(999, si.getRank());
833
834
835        PersistableBundle pb2 = new PersistableBundle();
836        pb2.putInt("x", 99);
837
838        si = sorig.clone(/* flags=*/ 0);
839        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
840                .setExtras(pb2).build());
841        assertEquals(11, si.getTextResId());
842        assertEquals(99, si.getExtras().getInt("x"));
843    }
844
845    public void testShortcutInfoSaveAndLoad() throws InterruptedException {
846        setCaller(CALLING_PACKAGE_1, USER_10);
847
848        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
849                getTestContext().getResources(), R.drawable.black_32x32));
850
851        PersistableBundle pb = new PersistableBundle();
852        pb.putInt("k", 1);
853        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
854                .setId("id")
855                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
856                .setIcon(bmp32x32)
857                .setTitle("title")
858                .setText("text")
859                .setDisabledMessage("dismes")
860                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
861                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
862                .setRank(123)
863                .setExtras(pb)
864                .build();
865        sorig.setTimestamp(mInjectedCurrentTimeMillis);
866
867        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
868                .setId("id2")
869                .setTitle("x")
870                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
871                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
872                .setRank(456)
873                .build();
874        sorig2.setTimestamp(mInjectedCurrentTimeMillis);
875
876        mManager.addDynamicShortcuts(list(sorig, sorig2));
877
878        mInjectedCurrentTimeMillis += 1;
879        final long now = mInjectedCurrentTimeMillis;
880        mInjectedCurrentTimeMillis += 1;
881
882        // Save and load.
883        mService.saveDirtyInfo();
884        initService();
885        mService.handleUnlockUser(USER_10);
886
887        ShortcutInfo si;
888        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
889
890        assertEquals(USER_10, si.getUserId());
891        assertEquals(HANDLE_USER_10, si.getUserHandle());
892        assertEquals(CALLING_PACKAGE_1, si.getPackage());
893        assertEquals("id", si.getId());
894        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
895        assertEquals(null, si.getIcon());
896        assertEquals("title", si.getTitle());
897        assertEquals("text", si.getText());
898        assertEquals("dismes", si.getDisabledMessage());
899        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
900        assertEquals("action", si.getIntent().getAction());
901        assertEquals("val", si.getIntent().getStringExtra("key"));
902        assertEquals(0, si.getRank());
903        assertEquals(1, si.getExtras().getInt("k"));
904
905        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
906                | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
907        assertNotNull(si.getBitmapPath()); // Something should be set.
908        assertEquals(0, si.getIconResourceId());
909        assertTrue(si.getLastChangedTimestamp() < now);
910
911        // Make sure ranks are saved too.  Because of the auto-adjusting, we need two shortcuts
912        // to test it.
913        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
914        assertEquals(1, si.getRank());
915    }
916
917    public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
918        setCaller(CALLING_PACKAGE_1, USER_10);
919
920        final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32);
921
922        PersistableBundle pb = new PersistableBundle();
923        pb.putInt("k", 1);
924        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
925                .setId("id")
926                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
927                .setIcon(res32x32)
928                .setTitleResId(10)
929                .setTextResId(11)
930                .setDisabledMessageResId(12)
931                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
932                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
933                .setRank(123)
934                .setExtras(pb)
935                .build();
936        sorig.setTimestamp(mInjectedCurrentTimeMillis);
937
938        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
939                .setId("id2")
940                .setTitle("x")
941                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
942                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
943                .setRank(456)
944                .build();
945        sorig2.setTimestamp(mInjectedCurrentTimeMillis);
946
947        mManager.addDynamicShortcuts(list(sorig, sorig2));
948
949        mInjectedCurrentTimeMillis += 1;
950        final long now = mInjectedCurrentTimeMillis;
951        mInjectedCurrentTimeMillis += 1;
952
953        // Save and load.
954        mService.saveDirtyInfo();
955        initService();
956        mService.handleUnlockUser(USER_10);
957
958        ShortcutInfo si;
959        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
960
961        assertEquals(USER_10, si.getUserId());
962        assertEquals(HANDLE_USER_10, si.getUserHandle());
963        assertEquals(CALLING_PACKAGE_1, si.getPackage());
964        assertEquals("id", si.getId());
965        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
966        assertEquals(null, si.getIcon());
967        assertEquals(10, si.getTitleResId());
968        assertEquals("r10", si.getTitleResName());
969        assertEquals(11, si.getTextResId());
970        assertEquals("r11", si.getTextResName());
971        assertEquals(12, si.getDisabledMessageResourceId());
972        assertEquals("r12", si.getDisabledMessageResName());
973        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
974        assertEquals("action", si.getIntent().getAction());
975        assertEquals("val", si.getIntent().getStringExtra("key"));
976        assertEquals(0, si.getRank());
977        assertEquals(1, si.getExtras().getInt("k"));
978
979        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_RES
980                | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
981        assertNull(si.getBitmapPath());
982        assertEquals(R.drawable.black_32x32, si.getIconResourceId());
983        assertTrue(si.getLastChangedTimestamp() < now);
984
985        // Make sure ranks are saved too.  Because of the auto-adjusting, we need two shortcuts
986        // to test it.
987        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
988        assertEquals(1, si.getRank());
989    }
990
991    public void testShortcutInfoSaveAndLoad_forBackup() {
992        setCaller(CALLING_PACKAGE_1, USER_0);
993
994        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
995                getTestContext().getResources(), R.drawable.black_32x32));
996
997        PersistableBundle pb = new PersistableBundle();
998        pb.putInt("k", 1);
999        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
1000                .setId("id")
1001                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
1002                .setIcon(bmp32x32)
1003                .setTitle("title")
1004                .setText("text")
1005                .setDisabledMessage("dismes")
1006                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
1007                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
1008                .setRank(123)
1009                .setExtras(pb)
1010                .build();
1011
1012        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
1013                .setId("id2")
1014                .setTitle("x")
1015                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
1016                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
1017                .setRank(456)
1018                .build();
1019
1020        mManager.addDynamicShortcuts(list(sorig, sorig2));
1021
1022        // Dynamic shortcuts won't be backed up, so we need to pin it.
1023        setCaller(LAUNCHER_1, USER_0);
1024        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0);
1025
1026        // Do backup & restore.
1027        backupAndRestore();
1028
1029        mService.handleUnlockUser(USER_0); // Load user-0.
1030
1031        ShortcutInfo si;
1032        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
1033
1034        assertEquals(CALLING_PACKAGE_1, si.getPackage());
1035        assertEquals("id", si.getId());
1036        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
1037        assertEquals(null, si.getIcon());
1038        assertEquals("title", si.getTitle());
1039        assertEquals("text", si.getText());
1040        assertEquals("dismes", si.getDisabledMessage());
1041        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
1042        assertEquals("action", si.getIntent().getAction());
1043        assertEquals("val", si.getIntent().getStringExtra("key"));
1044        assertEquals(0, si.getRank());
1045        assertEquals(1, si.getExtras().getInt("k"));
1046
1047        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
1048        assertNull(si.getBitmapPath()); // No icon.
1049        assertEquals(0, si.getIconResourceId());
1050
1051        // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank.
1052        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0);
1053        assertEquals(0, si.getRank());
1054    }
1055
1056    public void testShortcutInfoSaveAndLoad_forBackup_resId() {
1057        setCaller(CALLING_PACKAGE_1, USER_0);
1058
1059        final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32);
1060
1061        PersistableBundle pb = new PersistableBundle();
1062        pb.putInt("k", 1);
1063        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
1064                .setId("id")
1065                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
1066                .setIcon(res32x32)
1067                .setTitleResId(10)
1068                .setTextResId(11)
1069                .setDisabledMessageResId(12)
1070                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
1071                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
1072                .setRank(123)
1073                .setExtras(pb)
1074                .build();
1075
1076        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
1077                .setId("id2")
1078                .setTitle("x")
1079                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
1080                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
1081                .setRank(456)
1082                .build();
1083
1084        mManager.addDynamicShortcuts(list(sorig, sorig2));
1085
1086        // Dynamic shortcuts won't be backed up, so we need to pin it.
1087        setCaller(LAUNCHER_1, USER_0);
1088        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0);
1089
1090        // Do backup & restore.
1091        backupAndRestore();
1092
1093        mService.handleUnlockUser(USER_0); // Load user-0.
1094
1095        ShortcutInfo si;
1096        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
1097
1098        assertEquals(CALLING_PACKAGE_1, si.getPackage());
1099        assertEquals("id", si.getId());
1100        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
1101        assertEquals(null, si.getIcon());
1102        assertEquals(10, si.getTitleResId());
1103        assertEquals("r10", si.getTitleResName());
1104        assertEquals(11, si.getTextResId());
1105        assertEquals("r11", si.getTextResName());
1106        assertEquals(12, si.getDisabledMessageResourceId());
1107        assertEquals("r12", si.getDisabledMessageResName());
1108        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
1109        assertEquals("action", si.getIntent().getAction());
1110        assertEquals("val", si.getIntent().getStringExtra("key"));
1111        assertEquals(0, si.getRank());
1112        assertEquals(1, si.getExtras().getInt("k"));
1113
1114        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
1115        assertNull(si.getBitmapPath()); // No icon.
1116        assertEquals(0, si.getIconResourceId());
1117        assertEquals(null, si.getIconResName());
1118
1119        // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank.
1120        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0);
1121        assertEquals(0, si.getRank());
1122    }
1123
1124    private void checkShortcutInfoSaveAndLoad_intents(Intent intent) {
1125        assertTrue(mManager.setDynamicShortcuts(list(
1126                makeShortcutWithIntent("s1", intent))));
1127        initService();
1128        mService.handleUnlockUser(USER_0);
1129
1130        assertWith(getCallerShortcuts())
1131                .haveIds("s1")
1132                .forShortcutWithId("s1", si -> {
1133                    assertEquals(intent.getAction(), si.getIntent().getAction());
1134                    assertEquals(intent.getData(), si.getIntent().getData());
1135                    assertEquals(intent.getComponent(), si.getIntent().getComponent());
1136                    assertBundlesEqual(intent.getExtras(), si.getExtras());
1137                });
1138    }
1139
1140    public void testShortcutInfoSaveAndLoad_intents() {
1141        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW));
1142
1143        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1144
1145        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN));
1146
1147        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1148
1149        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW,
1150                Uri.parse("http://www.example.com/")));
1151
1152        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1153
1154        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN,
1155                Uri.parse("http://www.example.com/")));
1156
1157        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1158
1159        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW)
1160                .setComponent(new ComponentName("a", "b")));
1161
1162        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1163
1164        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN)
1165                .setComponent(new ComponentName("a", "b")));
1166
1167        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1168
1169        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW)
1170                .putExtras(makeBundle("a", "b")));
1171
1172        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1173
1174
1175        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN)
1176                .putExtras(makeBundle("a", "b")));
1177
1178        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1179    }
1180
1181    public void testThrottling() {
1182        final ShortcutInfo si1 = makeShortcut("shortcut1");
1183
1184        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1185        assertEquals(2, mManager.getRemainingCallCount());
1186        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1187
1188        mInjectedCurrentTimeMillis++;
1189        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1190        assertEquals(1, mManager.getRemainingCallCount());
1191        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1192
1193        mInjectedCurrentTimeMillis++;
1194        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1195        assertEquals(0, mManager.getRemainingCallCount());
1196        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1197
1198        // Reached the max
1199
1200        mInjectedCurrentTimeMillis++;
1201        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1202        assertEquals(0, mManager.getRemainingCallCount());
1203        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1204
1205        // Still throttled
1206        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
1207        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1208        assertEquals(0, mManager.getRemainingCallCount());
1209        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1210
1211        // Now it should work.
1212        mInjectedCurrentTimeMillis++;
1213        assertTrue(mManager.setDynamicShortcuts(list(si1))); // fail
1214        assertEquals(2, mManager.getRemainingCallCount());
1215        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
1216
1217        mInjectedCurrentTimeMillis++;
1218        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1219        assertEquals(1, mManager.getRemainingCallCount());
1220        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
1221
1222        mInjectedCurrentTimeMillis++;
1223        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1224        assertEquals(0, mManager.getRemainingCallCount());
1225        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
1226
1227        mInjectedCurrentTimeMillis++;
1228        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1229        assertEquals(0, mManager.getRemainingCallCount());
1230        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
1231
1232        // 4 hours later...
1233        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL;
1234        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1235        assertEquals(2, mManager.getRemainingCallCount());
1236        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
1237
1238        mInjectedCurrentTimeMillis++;
1239        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1240        assertEquals(1, mManager.getRemainingCallCount());
1241        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
1242
1243        // Make sure getRemainingCallCount() itself gets reset without calling setDynamicShortcuts().
1244        mInjectedCurrentTimeMillis = START_TIME + 8 * INTERVAL;
1245        assertEquals(3, mManager.getRemainingCallCount());
1246        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
1247
1248        mInjectedCurrentTimeMillis++;
1249        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1250        assertEquals(2, mManager.getRemainingCallCount());
1251        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
1252    }
1253
1254    public void testThrottling_rewind() {
1255        final ShortcutInfo si1 = makeShortcut("shortcut1");
1256
1257        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1258        assertEquals(2, mManager.getRemainingCallCount());
1259        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1260
1261        mInjectedCurrentTimeMillis = 12345; // Clock reset!
1262
1263        // Since the clock looks invalid, the counter shouldn't have reset.
1264        assertEquals(2, mManager.getRemainingCallCount());
1265        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1266
1267        // Forward again.  Still haven't reset yet.
1268        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
1269        assertEquals(2, mManager.getRemainingCallCount());
1270        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1271
1272        // Now rewind -- this will reset the counters.
1273        mInjectedCurrentTimeMillis = START_TIME - 100000;
1274        assertEquals(3, mManager.getRemainingCallCount());
1275
1276        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1277        assertEquals(2, mManager.getRemainingCallCount());
1278
1279        // Forward again, should be reset now.
1280        mInjectedCurrentTimeMillis += INTERVAL;
1281        assertEquals(3, mManager.getRemainingCallCount());
1282    }
1283
1284    public void testThrottling_perPackage() {
1285        final ShortcutInfo si1 = makeShortcut("shortcut1");
1286
1287        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1288        assertEquals(2, mManager.getRemainingCallCount());
1289
1290        mInjectedCurrentTimeMillis++;
1291        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1292        assertEquals(1, mManager.getRemainingCallCount());
1293
1294        mInjectedCurrentTimeMillis++;
1295        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1296        assertEquals(0, mManager.getRemainingCallCount());
1297
1298        // Reached the max
1299
1300        mInjectedCurrentTimeMillis++;
1301        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1302
1303        // Try from a different caller.
1304        mInjectedClientPackage = CALLING_PACKAGE_2;
1305        mInjectedCallingUid = CALLING_UID_2;
1306
1307        // Need to create a new one wit the updated package name.
1308        final ShortcutInfo si2 = makeShortcut("shortcut1");
1309
1310        assertEquals(3, mManager.getRemainingCallCount());
1311
1312        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1313        assertEquals(2, mManager.getRemainingCallCount());
1314
1315        mInjectedCurrentTimeMillis++;
1316        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1317        assertEquals(1, mManager.getRemainingCallCount());
1318
1319        // Back to the original caller, still throttled.
1320        mInjectedClientPackage = CALLING_PACKAGE_1;
1321        mInjectedCallingUid = CALLING_UID_1;
1322
1323        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
1324        assertEquals(0, mManager.getRemainingCallCount());
1325        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1326        assertEquals(0, mManager.getRemainingCallCount());
1327
1328        // Now it should work.
1329        mInjectedCurrentTimeMillis++;
1330        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1331
1332        mInjectedCurrentTimeMillis++;
1333        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1334
1335        mInjectedCurrentTimeMillis++;
1336        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1337
1338        mInjectedCurrentTimeMillis++;
1339        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1340
1341        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL;
1342        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1343        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1344        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1345        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1346
1347        mInjectedClientPackage = CALLING_PACKAGE_2;
1348        mInjectedCallingUid = CALLING_UID_2;
1349
1350        assertEquals(3, mManager.getRemainingCallCount());
1351
1352        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1353        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1354        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1355        assertFalse(mManager.setDynamicShortcuts(list(si2)));
1356    }
1357
1358    public void testThrottling_localeChanges() {
1359        prepareCrossProfileDataSet();
1360
1361        dumpsysOnLogcat("Before save & load");
1362
1363        mService.saveDirtyInfo();
1364        initService();
1365
1366        mInjectedLocale = Locale.CHINA;
1367        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
1368
1369        // Note at this point only user-0 is loaded, and the counters are reset for this user,
1370        // but it will work for other users too because we check the locale change at any
1371        // API entry point.
1372
1373        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1374            assertEquals(3, mManager.getRemainingCallCount());
1375        });
1376        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1377            assertEquals(3, mManager.getRemainingCallCount());
1378        });
1379        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1380            assertEquals(3, mManager.getRemainingCallCount());
1381        });
1382        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1383            assertEquals(3, mManager.getRemainingCallCount());
1384        });
1385        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1386            assertEquals(3, mManager.getRemainingCallCount());
1387        });
1388        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1389            assertEquals(3, mManager.getRemainingCallCount());
1390        });
1391
1392        // Make sure even if we receive ACTION_LOCALE_CHANGED, if the locale hasn't actually
1393        // changed, we don't reset throttling.
1394        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1395            mManager.updateShortcuts(list());
1396            assertEquals(2, mManager.getRemainingCallCount());
1397        });
1398
1399        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
1400
1401        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1402            assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
1403        });
1404
1405        mService.saveDirtyInfo();
1406        initService();
1407
1408        // The locale should be persisted, so it still shouldn't reset throttling.
1409        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
1410
1411        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1412            assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
1413        });
1414    }
1415
1416    public void testThrottling_foreground() throws Exception {
1417        prepareCrossProfileDataSet();
1418
1419        dumpsysOnLogcat("Before save & load");
1420
1421        mService.saveDirtyInfo();
1422        initService();
1423
1424        // We need to update the current time from time to time, since some of the internal checks
1425        // rely on the time being correctly incremented.
1426        mInjectedCurrentTimeMillis++;
1427
1428        // First, all packages have less than 3 (== initial value) remaining calls.
1429
1430        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1431            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1432        });
1433        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1434            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1435        });
1436        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1437            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1438        });
1439        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1440            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1441        });
1442        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1443            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1444        });
1445        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1446            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1447        });
1448
1449        mInjectedCurrentTimeMillis++;
1450
1451        // State changed, but not foreground, so no resetting.
1452        mService.mUidObserver.onUidStateChanged(
1453                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
1454        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1455            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1456        });
1457        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1458            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1459        });
1460        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1461            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1462        });
1463        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1464            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1465        });
1466        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1467            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1468        });
1469        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1470            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1471        });
1472
1473        mInjectedCurrentTimeMillis++;
1474
1475        // State changed, package1 foreground, reset.
1476        mService.mUidObserver.onUidStateChanged(
1477                CALLING_UID_1, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
1478        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1479            assertEquals(3, mManager.getRemainingCallCount());
1480        });
1481        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1482            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1483        });
1484        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1485            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1486        });
1487        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1488            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1489        });
1490        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1491            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1492        });
1493        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1494            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1495        });
1496        mService.mUidObserver.onUidStateChanged(
1497                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
1498
1499        mInjectedCurrentTimeMillis++;
1500
1501        // Different app comes to foreground briefly, and goes back to background.
1502        // Now, make sure package 2's counter is reset, even in this case.
1503        mService.mUidObserver.onUidStateChanged(
1504                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
1505        mService.mUidObserver.onUidStateChanged(
1506                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
1507
1508        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1509            assertEquals(3, mManager.getRemainingCallCount());
1510        });
1511        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1512            assertEquals(3, mManager.getRemainingCallCount());
1513        });
1514        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1515            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1516        });
1517        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1518            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1519        });
1520        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1521            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1522        });
1523        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1524            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1525        });
1526
1527        mInjectedCurrentTimeMillis++;
1528
1529        // Do the same thing one more time.  This would catch the bug with mixuing up
1530        // the current time and the elapsed time.
1531        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1532            mManager.updateShortcuts(list(makeShortcut("s")));
1533            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1534        });
1535
1536        mService.mUidObserver.onUidStateChanged(
1537                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
1538        mService.mUidObserver.onUidStateChanged(
1539                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
1540
1541        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1542            assertEquals(3, mManager.getRemainingCallCount());
1543        });
1544        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1545            assertEquals(3, mManager.getRemainingCallCount());
1546        });
1547        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1548            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1549        });
1550        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1551            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1552        });
1553        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1554            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1555        });
1556        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1557            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1558        });
1559
1560        mInjectedCurrentTimeMillis++;
1561
1562        // Package 1 on user-10 comes to foreground.
1563        // Now, also try calling some APIs and make sure foreground apps don't get throttled.
1564        mService.mUidObserver.onUidStateChanged(
1565                UserHandle.getUid(USER_10, CALLING_UID_1),
1566                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
1567        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1568            assertEquals(3, mManager.getRemainingCallCount());
1569
1570            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1571            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1572            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1573
1574            assertEquals(0, mManager.getRemainingCallCount());
1575        });
1576        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1577            assertEquals(3, mManager.getRemainingCallCount());
1578
1579            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1580            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1581            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1582
1583            assertEquals(0, mManager.getRemainingCallCount());
1584        });
1585        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1586            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1587
1588            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1589            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1590            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1591
1592            assertEquals(0, mManager.getRemainingCallCount());
1593        });
1594        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1595            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1596
1597            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1598            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1599            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1600
1601            assertEquals(0, mManager.getRemainingCallCount());
1602        });
1603        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1604            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1605
1606            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1607            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1608            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1609
1610            assertEquals(0, mManager.getRemainingCallCount());
1611        });
1612        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1613            assertEquals(3, mManager.getRemainingCallCount());
1614
1615            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1616            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1617            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1618
1619            assertEquals(3, mManager.getRemainingCallCount()); // Still 3!
1620        });
1621    }
1622
1623
1624    public void testThrottling_resetByInternalCall() throws Exception {
1625        prepareCrossProfileDataSet();
1626
1627        dumpsysOnLogcat("Before save & load");
1628
1629        mService.saveDirtyInfo();
1630        initService();
1631
1632        // First, all packages have less than 3 (== initial value) remaining calls.
1633
1634        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1635            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1636        });
1637        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1638            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1639        });
1640        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1641            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1642        });
1643        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1644            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1645        });
1646        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1647            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1648        });
1649        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1650            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1651        });
1652
1653        // Simulate a call from sys UI.
1654        mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
1655        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
1656
1657        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1658            assertEquals(3, mManager.getRemainingCallCount());
1659        });
1660        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1661            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1662        });
1663        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1664            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1665        });
1666        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1667            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1668        });
1669        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1670            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1671        });
1672        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1673            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1674        });
1675
1676        mManager.onApplicationActive(CALLING_PACKAGE_3, USER_0);
1677
1678        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1679            assertEquals(3, mManager.getRemainingCallCount());
1680        });
1681        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1682            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1683        });
1684        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1685            assertEquals(3, mManager.getRemainingCallCount());
1686        });
1687        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1688            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1689        });
1690        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1691            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1692        });
1693        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1694            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1695        });
1696
1697        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10);
1698
1699        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1700            assertEquals(3, mManager.getRemainingCallCount());
1701        });
1702        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1703            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1704        });
1705        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1706            assertEquals(3, mManager.getRemainingCallCount());
1707        });
1708        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1709            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1710        });
1711        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1712            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1713        });
1714        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1715            assertEquals(3, mManager.getRemainingCallCount());
1716        });
1717    }
1718
1719    public void testReportShortcutUsed() {
1720        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1721            reset(mMockUsageStatsManagerInternal);
1722
1723            // Report with an nonexistent shortcut.
1724            mManager.reportShortcutUsed("s1");
1725            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
1726                    anyString(), anyString(), anyInt());
1727
1728            // Publish s2, but s1 still doesn't exist.
1729            mManager.setDynamicShortcuts(list(makeShortcut("s2")));
1730            mManager.reportShortcutUsed("s1");
1731            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
1732                    anyString(), anyString(), anyInt());
1733
1734            mManager.reportShortcutUsed("s2");
1735            verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
1736                    eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_10));
1737
1738        });
1739        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
1740            // Try with a different package.
1741            reset(mMockUsageStatsManagerInternal);
1742
1743            // Report with an nonexistent shortcut.
1744            mManager.reportShortcutUsed("s2");
1745            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
1746                    anyString(), anyString(), anyInt());
1747
1748            // Publish s2, but s1 still doesn't exist.
1749            mManager.setDynamicShortcuts(list(makeShortcut("s3")));
1750            mManager.reportShortcutUsed("s2");
1751            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
1752                    anyString(), anyString(), anyInt());
1753
1754            mManager.reportShortcutUsed("s3");
1755            verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
1756                    eq(CALLING_PACKAGE_2), eq("s3"), eq(USER_10));
1757
1758        });
1759    }
1760
1761    // Test for a ShortcutInfo method.
1762    public void testGetResourcePackageName() {
1763        assertEquals(null, ShortcutInfo.getResourcePackageName(""));
1764        assertEquals(null, ShortcutInfo.getResourcePackageName("abc"));
1765        assertEquals("p", ShortcutInfo.getResourcePackageName("p:"));
1766        assertEquals("p", ShortcutInfo.getResourcePackageName("p:xx"));
1767        assertEquals("pac", ShortcutInfo.getResourcePackageName("pac:"));
1768    }
1769
1770    // Test for a ShortcutInfo method.
1771    public void testGetResourceTypeName() {
1772        assertEquals(null, ShortcutInfo.getResourceTypeName(""));
1773        assertEquals(null, ShortcutInfo.getResourceTypeName(":"));
1774        assertEquals(null, ShortcutInfo.getResourceTypeName("/"));
1775        assertEquals(null, ShortcutInfo.getResourceTypeName("/:"));
1776        assertEquals("a", ShortcutInfo.getResourceTypeName(":a/"));
1777        assertEquals("type", ShortcutInfo.getResourceTypeName("xxx:type/yyy"));
1778    }
1779
1780    // Test for a ShortcutInfo method.
1781    public void testGetResourceTypeAndEntryName() {
1782        assertEquals(null, ShortcutInfo.getResourceTypeAndEntryName(""));
1783        assertEquals(null, ShortcutInfo.getResourceTypeAndEntryName("abc"));
1784        assertEquals("", ShortcutInfo.getResourceTypeAndEntryName("p:"));
1785        assertEquals("x", ShortcutInfo.getResourceTypeAndEntryName(":x"));
1786        assertEquals("x", ShortcutInfo.getResourceTypeAndEntryName("p:x"));
1787        assertEquals("xyz", ShortcutInfo.getResourceTypeAndEntryName("pac:xyz"));
1788    }
1789
1790    // Test for a ShortcutInfo method.
1791    public void testGetResourceEntryName() {
1792        assertEquals(null, ShortcutInfo.getResourceEntryName(""));
1793        assertEquals(null, ShortcutInfo.getResourceEntryName("ab:"));
1794        assertEquals("", ShortcutInfo.getResourceEntryName("/"));
1795        assertEquals("abc", ShortcutInfo.getResourceEntryName("/abc"));
1796        assertEquals("abc", ShortcutInfo.getResourceEntryName("xyz/abc"));
1797    }
1798
1799    // Test for a ShortcutInfo method.
1800    public void testLookUpResourceName_systemResources() {
1801        // For android system resources, lookUpResourceName will simply return the value as a
1802        // string, regardless of "withType".
1803        final Resources res = getTestContext().getResources();
1804
1805        assertEquals("" + android.R.string.cancel, ShortcutInfo.lookUpResourceName(res,
1806                android.R.string.cancel, true, getTestContext().getPackageName()));
1807        assertEquals("" + android.R.drawable.alert_dark_frame, ShortcutInfo.lookUpResourceName(res,
1808                android.R.drawable.alert_dark_frame, true, getTestContext().getPackageName()));
1809        assertEquals("" + android.R.string.cancel, ShortcutInfo.lookUpResourceName(res,
1810                android.R.string.cancel, false, getTestContext().getPackageName()));
1811    }
1812
1813    public void testLookUpResourceName_appResources() {
1814        final Resources res = getTestContext().getResources();
1815
1816        assertEquals("shortcut_text1", ShortcutInfo.lookUpResourceName(res,
1817                R.string.shortcut_text1, false, getTestContext().getPackageName()));
1818        assertEquals("string/shortcut_text1", ShortcutInfo.lookUpResourceName(res,
1819                R.string.shortcut_text1, true, getTestContext().getPackageName()));
1820
1821        assertEquals("black_16x64", ShortcutInfo.lookUpResourceName(res,
1822                R.drawable.black_16x64, false, getTestContext().getPackageName()));
1823        assertEquals("drawable/black_16x64", ShortcutInfo.lookUpResourceName(res,
1824                R.drawable.black_16x64, true, getTestContext().getPackageName()));
1825    }
1826
1827    // Test for a ShortcutInfo method.
1828    public void testLookUpResourceId_systemResources() {
1829        final Resources res = getTestContext().getResources();
1830
1831        assertEquals(android.R.string.cancel, ShortcutInfo.lookUpResourceId(res,
1832                "" + android.R.string.cancel, null,
1833                getTestContext().getPackageName()));
1834        assertEquals(android.R.drawable.alert_dark_frame, ShortcutInfo.lookUpResourceId(res,
1835                "" + android.R.drawable.alert_dark_frame, null,
1836                getTestContext().getPackageName()));
1837    }
1838
1839    // Test for a ShortcutInfo method.
1840    public void testLookUpResourceId_appResources() {
1841        final Resources res = getTestContext().getResources();
1842
1843        assertEquals(R.string.shortcut_text1,
1844                ShortcutInfo.lookUpResourceId(res, "shortcut_text1", "string",
1845                        getTestContext().getPackageName()));
1846
1847        assertEquals(R.string.shortcut_text1,
1848                ShortcutInfo.lookUpResourceId(res, "string/shortcut_text1", null,
1849                        getTestContext().getPackageName()));
1850
1851        assertEquals(R.drawable.black_16x64,
1852                ShortcutInfo.lookUpResourceId(res, "black_16x64", "drawable",
1853                        getTestContext().getPackageName()));
1854
1855        assertEquals(R.drawable.black_16x64,
1856                ShortcutInfo.lookUpResourceId(res, "drawable/black_16x64", null,
1857                        getTestContext().getPackageName()));
1858    }
1859
1860    public void testDumpCheckin() throws IOException {
1861        prepareCrossProfileDataSet();
1862
1863        // prepareCrossProfileDataSet() doesn't set any icons, so do set here.
1864        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
1865        final Icon res64x64 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
1866        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
1867                getTestContext().getResources(), R.drawable.black_32x32));
1868        final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource(
1869                getTestContext().getResources(), R.drawable.black_64x64));
1870
1871        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1872            assertTrue(mManager.setDynamicShortcuts(list(
1873                    makeShortcutWithIcon("res32x32", res32x32),
1874                    makeShortcutWithIcon("res64x64", res64x64),
1875                    makeShortcutWithIcon("bmp32x32", bmp32x32),
1876                    makeShortcutWithIcon("bmp64x64", bmp64x64))));
1877        });
1878        // We can't predict the compressed bitmap sizes, so get the real sizes here.
1879        final long bitmapTotal =
1880                new File(getPackageShortcut(CALLING_PACKAGE_2, "bmp32x32", USER_0)
1881                        .getBitmapPath()).length() +
1882                new File(getPackageShortcut(CALLING_PACKAGE_2, "bmp64x64", USER_0)
1883                        .getBitmapPath()).length();
1884
1885        // Read the expected output and inject the bitmap size.
1886        final String expected = readTestAsset("shortcut/dumpsys_expected.txt")
1887                .replace("***BITMAP_SIZE***", String.valueOf(bitmapTotal));
1888
1889        assertEquals(expected, dumpCheckin());
1890    }
1891
1892    public void testDumpsysNoPermission() {
1893        assertExpectException(SecurityException.class, "android.permission.DUMP",
1894                () -> mService.dump(null, new PrintWriter(new StringWriter()), null));
1895
1896        // System can call it without the permission.
1897        runWithSystemUid(() -> {
1898            mService.dump(null, new PrintWriter(new StringWriter()), null);
1899        });
1900    }
1901}
1902