ShortcutManagerTest2.java revision 440a1ea8e2204ecb171e0187318beb2f08f6012c
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                "intents cannot contain 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        dumpsysOnLogcat("before save");
883
884        // Save and load.
885        mService.saveDirtyInfo();
886        initService();
887        mService.handleUnlockUser(USER_10);
888
889        dumpUserFile(USER_10);
890        dumpsysOnLogcat("after load");
891
892        ShortcutInfo si;
893        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
894
895        assertEquals(USER_10, si.getUserId());
896        assertEquals(HANDLE_USER_10, si.getUserHandle());
897        assertEquals(CALLING_PACKAGE_1, si.getPackage());
898        assertEquals("id", si.getId());
899        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
900        assertEquals(null, si.getIcon());
901        assertEquals("title", si.getTitle());
902        assertEquals("text", si.getText());
903        assertEquals("dismes", si.getDisabledMessage());
904        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
905        assertEquals("action", si.getIntent().getAction());
906        assertEquals("val", si.getIntent().getStringExtra("key"));
907        assertEquals(0, si.getRank());
908        assertEquals(1, si.getExtras().getInt("k"));
909
910        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE
911                | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
912        assertNotNull(si.getBitmapPath()); // Something should be set.
913        assertEquals(0, si.getIconResourceId());
914        assertTrue(si.getLastChangedTimestamp() < now);
915
916        // Make sure ranks are saved too.  Because of the auto-adjusting, we need two shortcuts
917        // to test it.
918        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
919        assertEquals(1, si.getRank());
920
921        dumpUserFile(USER_10);
922    }
923
924    public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
925        setCaller(CALLING_PACKAGE_1, USER_10);
926
927        final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32);
928
929        PersistableBundle pb = new PersistableBundle();
930        pb.putInt("k", 1);
931        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
932                .setId("id")
933                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
934                .setIcon(res32x32)
935                .setTitleResId(10)
936                .setTextResId(11)
937                .setDisabledMessageResId(12)
938                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
939                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
940                .setRank(123)
941                .setExtras(pb)
942                .build();
943        sorig.setTimestamp(mInjectedCurrentTimeMillis);
944
945        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
946                .setId("id2")
947                .setTitle("x")
948                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
949                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
950                .setRank(456)
951                .build();
952        sorig2.setTimestamp(mInjectedCurrentTimeMillis);
953
954        mManager.addDynamicShortcuts(list(sorig, sorig2));
955
956        mInjectedCurrentTimeMillis += 1;
957        final long now = mInjectedCurrentTimeMillis;
958        mInjectedCurrentTimeMillis += 1;
959
960        // Save and load.
961        mService.saveDirtyInfo();
962        initService();
963        mService.handleUnlockUser(USER_10);
964
965        ShortcutInfo si;
966        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
967
968        assertEquals(USER_10, si.getUserId());
969        assertEquals(HANDLE_USER_10, si.getUserHandle());
970        assertEquals(CALLING_PACKAGE_1, si.getPackage());
971        assertEquals("id", si.getId());
972        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
973        assertEquals(null, si.getIcon());
974        assertEquals(10, si.getTitleResId());
975        assertEquals("r10", si.getTitleResName());
976        assertEquals(11, si.getTextResId());
977        assertEquals("r11", si.getTextResName());
978        assertEquals(12, si.getDisabledMessageResourceId());
979        assertEquals("r12", si.getDisabledMessageResName());
980        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
981        assertEquals("action", si.getIntent().getAction());
982        assertEquals("val", si.getIntent().getStringExtra("key"));
983        assertEquals(0, si.getRank());
984        assertEquals(1, si.getExtras().getInt("k"));
985
986        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_RES
987                | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
988        assertNull(si.getBitmapPath());
989        assertEquals(R.drawable.black_32x32, si.getIconResourceId());
990        assertTrue(si.getLastChangedTimestamp() < now);
991
992        // Make sure ranks are saved too.  Because of the auto-adjusting, we need two shortcuts
993        // to test it.
994        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10);
995        assertEquals(1, si.getRank());
996    }
997
998    public void testShortcutInfoSaveAndLoad_forBackup() {
999        setCaller(CALLING_PACKAGE_1, USER_0);
1000
1001        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
1002                getTestContext().getResources(), R.drawable.black_32x32));
1003
1004        PersistableBundle pb = new PersistableBundle();
1005        pb.putInt("k", 1);
1006        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
1007                .setId("id")
1008                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
1009                .setIcon(bmp32x32)
1010                .setTitle("title")
1011                .setText("text")
1012                .setDisabledMessage("dismes")
1013                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
1014                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
1015                .setRank(123)
1016                .setExtras(pb)
1017                .build();
1018
1019        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
1020                .setId("id2")
1021                .setTitle("x")
1022                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
1023                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
1024                .setRank(456)
1025                .build();
1026
1027        mManager.addDynamicShortcuts(list(sorig, sorig2));
1028
1029        // Dynamic shortcuts won't be backed up, so we need to pin it.
1030        setCaller(LAUNCHER_1, USER_0);
1031        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0);
1032
1033        // Do backup & restore.
1034        backupAndRestore();
1035
1036        mService.handleUnlockUser(USER_0); // Load user-0.
1037
1038        ShortcutInfo si;
1039        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
1040
1041        assertEquals(CALLING_PACKAGE_1, si.getPackage());
1042        assertEquals("id", si.getId());
1043        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
1044        assertEquals(null, si.getIcon());
1045        assertEquals("title", si.getTitle());
1046        assertEquals("text", si.getText());
1047        assertEquals("dismes", si.getDisabledMessage());
1048        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
1049        assertEquals("action", si.getIntent().getAction());
1050        assertEquals("val", si.getIntent().getStringExtra("key"));
1051        assertEquals(0, si.getRank());
1052        assertEquals(1, si.getExtras().getInt("k"));
1053
1054        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
1055        assertNull(si.getBitmapPath()); // No icon.
1056        assertEquals(0, si.getIconResourceId());
1057
1058        // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank.
1059        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0);
1060        assertEquals(0, si.getRank());
1061    }
1062
1063    public void testShortcutInfoSaveAndLoad_forBackup_resId() {
1064        setCaller(CALLING_PACKAGE_1, USER_0);
1065
1066        final Icon res32x32 = Icon.createWithResource(mClientContext, R.drawable.black_32x32);
1067
1068        PersistableBundle pb = new PersistableBundle();
1069        pb.putInt("k", 1);
1070        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
1071                .setId("id")
1072                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
1073                .setIcon(res32x32)
1074                .setTitleResId(10)
1075                .setTextResId(11)
1076                .setDisabledMessageResId(12)
1077                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
1078                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
1079                .setRank(123)
1080                .setExtras(pb)
1081                .build();
1082
1083        ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext)
1084                .setId("id2")
1085                .setTitle("x")
1086                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
1087                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
1088                .setRank(456)
1089                .build();
1090
1091        mManager.addDynamicShortcuts(list(sorig, sorig2));
1092
1093        // Dynamic shortcuts won't be backed up, so we need to pin it.
1094        setCaller(LAUNCHER_1, USER_0);
1095        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0);
1096
1097        // Do backup & restore.
1098        backupAndRestore();
1099
1100        mService.handleUnlockUser(USER_0); // Load user-0.
1101
1102        ShortcutInfo si;
1103        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
1104
1105        assertEquals(CALLING_PACKAGE_1, si.getPackage());
1106        assertEquals("id", si.getId());
1107        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
1108        assertEquals(null, si.getIcon());
1109        assertEquals(10, si.getTitleResId());
1110        assertEquals("r10", si.getTitleResName());
1111        assertEquals(11, si.getTextResId());
1112        assertEquals("r11", si.getTextResName());
1113        assertEquals(12, si.getDisabledMessageResourceId());
1114        assertEquals("r12", si.getDisabledMessageResName());
1115        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
1116        assertEquals("action", si.getIntent().getAction());
1117        assertEquals("val", si.getIntent().getStringExtra("key"));
1118        assertEquals(0, si.getRank());
1119        assertEquals(1, si.getExtras().getInt("k"));
1120
1121        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags());
1122        assertNull(si.getBitmapPath()); // No icon.
1123        assertEquals(0, si.getIconResourceId());
1124        assertEquals(null, si.getIconResName());
1125
1126        // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank.
1127        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0);
1128        assertEquals(0, si.getRank());
1129    }
1130
1131    private void checkShortcutInfoSaveAndLoad_intents(Intent intent) {
1132        assertTrue(mManager.setDynamicShortcuts(list(
1133                makeShortcutWithIntent("s1", intent))));
1134        initService();
1135        mService.handleUnlockUser(USER_0);
1136
1137        assertWith(getCallerShortcuts())
1138                .haveIds("s1")
1139                .forShortcutWithId("s1", si -> {
1140                    assertEquals(intent.getAction(), si.getIntent().getAction());
1141                    assertEquals(intent.getData(), si.getIntent().getData());
1142                    assertEquals(intent.getComponent(), si.getIntent().getComponent());
1143                    assertBundlesEqual(intent.getExtras(), si.getIntent().getExtras());
1144                });
1145    }
1146
1147    private void checkShortcutInfoSaveAndLoad_intents(Intent... intents) {
1148        assertTrue(mManager.setDynamicShortcuts(list(
1149                makeShortcutWithIntents("s1", intents))));
1150        initService();
1151        mService.handleUnlockUser(USER_0);
1152
1153        assertWith(getCallerShortcuts())
1154                .haveIds("s1")
1155                .forShortcutWithId("s1", si -> {
1156
1157                    final Intent[] actual = si.getIntents();
1158                    assertEquals(intents.length, actual.length);
1159
1160                    for (int i = 0; i < intents.length; i++) {
1161                        assertEquals(intents[i].getAction(), actual[i].getAction());
1162                        assertEquals(intents[i].getData(), actual[i].getData());
1163                        assertEquals(intents[i].getComponent(), actual[i].getComponent());
1164                        assertEquals(intents[i].getFlags(), actual[i].getFlags());
1165                        assertBundlesEqual(intents[i].getExtras(), actual[i].getExtras());
1166                    }
1167                });
1168    }
1169
1170    public void testShortcutInfoSaveAndLoad_intents() {
1171        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW));
1172
1173        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1174
1175        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN));
1176
1177        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1178
1179        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW,
1180                Uri.parse("http://www.example.com/")));
1181
1182        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1183
1184        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN,
1185                Uri.parse("http://www.example.com/")));
1186
1187        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1188
1189        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW)
1190                .setComponent(new ComponentName("a", "b")));
1191
1192        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1193
1194        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN)
1195                .setComponent(new ComponentName("a", "b")));
1196
1197        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1198
1199        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_VIEW)
1200                .putExtras(makeBundle("a", "b")));
1201
1202        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1203
1204
1205        checkShortcutInfoSaveAndLoad_intents(new Intent(Intent.ACTION_MAIN)
1206                .putExtras(makeBundle("a", "b")));
1207
1208        mInjectedCurrentTimeMillis += INTERVAL; // reset throttling.
1209
1210        // Multi-intents
1211        checkShortcutInfoSaveAndLoad_intents(
1212                new Intent(Intent.ACTION_MAIN).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK),
1213                new Intent(Intent.ACTION_VIEW).setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
1214        );
1215
1216        checkShortcutInfoSaveAndLoad_intents(
1217                new Intent(Intent.ACTION_MAIN).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
1218                        .setComponent(new ComponentName("a", "b")),
1219                new Intent(Intent.ACTION_VIEW)
1220                        .setComponent(new ComponentName("a", "b"))
1221                );
1222
1223        checkShortcutInfoSaveAndLoad_intents(
1224                new Intent(Intent.ACTION_MAIN)
1225                        .setComponent(new ComponentName("a", "b")),
1226                new Intent(Intent.ACTION_VIEW).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
1227                        .setComponent(new ComponentName("a", "b")),
1228                new Intent("xyz").setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK
1229                        | Intent.FILL_IN_COMPONENT)
1230                        .setComponent(new ComponentName("a", "b")).putExtras(
1231                        makeBundle("xx", "yy"))
1232                );
1233    }
1234
1235    public void testThrottling() {
1236        final ShortcutInfo si1 = makeShortcut("shortcut1");
1237
1238        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1239        assertEquals(2, mManager.getRemainingCallCount());
1240        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1241
1242        mInjectedCurrentTimeMillis++;
1243        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1244        assertEquals(1, mManager.getRemainingCallCount());
1245        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1246
1247        mInjectedCurrentTimeMillis++;
1248        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1249        assertEquals(0, mManager.getRemainingCallCount());
1250        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1251
1252        // Reached the max
1253
1254        mInjectedCurrentTimeMillis++;
1255        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1256        assertEquals(0, mManager.getRemainingCallCount());
1257        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1258
1259        // Still throttled
1260        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
1261        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1262        assertEquals(0, mManager.getRemainingCallCount());
1263        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1264
1265        // Now it should work.
1266        mInjectedCurrentTimeMillis++;
1267        assertTrue(mManager.setDynamicShortcuts(list(si1))); // fail
1268        assertEquals(2, mManager.getRemainingCallCount());
1269        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
1270
1271        mInjectedCurrentTimeMillis++;
1272        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1273        assertEquals(1, mManager.getRemainingCallCount());
1274        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
1275
1276        mInjectedCurrentTimeMillis++;
1277        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1278        assertEquals(0, mManager.getRemainingCallCount());
1279        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
1280
1281        mInjectedCurrentTimeMillis++;
1282        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1283        assertEquals(0, mManager.getRemainingCallCount());
1284        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
1285
1286        // 4 hours later...
1287        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL;
1288        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1289        assertEquals(2, mManager.getRemainingCallCount());
1290        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
1291
1292        mInjectedCurrentTimeMillis++;
1293        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1294        assertEquals(1, mManager.getRemainingCallCount());
1295        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
1296
1297        // Make sure getRemainingCallCount() itself gets reset without calling setDynamicShortcuts().
1298        mInjectedCurrentTimeMillis = START_TIME + 8 * INTERVAL;
1299        assertEquals(3, mManager.getRemainingCallCount());
1300        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
1301
1302        mInjectedCurrentTimeMillis++;
1303        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1304        assertEquals(2, mManager.getRemainingCallCount());
1305        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
1306    }
1307
1308    public void testThrottling_rewind() {
1309        final ShortcutInfo si1 = makeShortcut("shortcut1");
1310
1311        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1312        assertEquals(2, mManager.getRemainingCallCount());
1313        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1314
1315        mInjectedCurrentTimeMillis = 12345; // Clock reset!
1316
1317        // Since the clock looks invalid, the counter shouldn't have reset.
1318        assertEquals(2, mManager.getRemainingCallCount());
1319        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1320
1321        // Forward again.  Still haven't reset yet.
1322        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
1323        assertEquals(2, mManager.getRemainingCallCount());
1324        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
1325
1326        // Now rewind -- this will reset the counters.
1327        mInjectedCurrentTimeMillis = START_TIME - 100000;
1328        assertEquals(3, mManager.getRemainingCallCount());
1329
1330        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1331        assertEquals(2, mManager.getRemainingCallCount());
1332
1333        // Forward again, should be reset now.
1334        mInjectedCurrentTimeMillis += INTERVAL;
1335        assertEquals(3, mManager.getRemainingCallCount());
1336    }
1337
1338    public void testThrottling_perPackage() {
1339        final ShortcutInfo si1 = makeShortcut("shortcut1");
1340
1341        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1342        assertEquals(2, mManager.getRemainingCallCount());
1343
1344        mInjectedCurrentTimeMillis++;
1345        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1346        assertEquals(1, mManager.getRemainingCallCount());
1347
1348        mInjectedCurrentTimeMillis++;
1349        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1350        assertEquals(0, mManager.getRemainingCallCount());
1351
1352        // Reached the max
1353
1354        mInjectedCurrentTimeMillis++;
1355        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1356
1357        // Try from a different caller.
1358        mInjectedClientPackage = CALLING_PACKAGE_2;
1359        mInjectedCallingUid = CALLING_UID_2;
1360
1361        // Need to create a new one wit the updated package name.
1362        final ShortcutInfo si2 = makeShortcut("shortcut1");
1363
1364        assertEquals(3, mManager.getRemainingCallCount());
1365
1366        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1367        assertEquals(2, mManager.getRemainingCallCount());
1368
1369        mInjectedCurrentTimeMillis++;
1370        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1371        assertEquals(1, mManager.getRemainingCallCount());
1372
1373        // Back to the original caller, still throttled.
1374        mInjectedClientPackage = CALLING_PACKAGE_1;
1375        mInjectedCallingUid = CALLING_UID_1;
1376
1377        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
1378        assertEquals(0, mManager.getRemainingCallCount());
1379        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1380        assertEquals(0, mManager.getRemainingCallCount());
1381
1382        // Now it should work.
1383        mInjectedCurrentTimeMillis++;
1384        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1385
1386        mInjectedCurrentTimeMillis++;
1387        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1388
1389        mInjectedCurrentTimeMillis++;
1390        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1391
1392        mInjectedCurrentTimeMillis++;
1393        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1394
1395        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL;
1396        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1397        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1398        assertTrue(mManager.setDynamicShortcuts(list(si1)));
1399        assertFalse(mManager.setDynamicShortcuts(list(si1)));
1400
1401        mInjectedClientPackage = CALLING_PACKAGE_2;
1402        mInjectedCallingUid = CALLING_UID_2;
1403
1404        assertEquals(3, mManager.getRemainingCallCount());
1405
1406        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1407        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1408        assertTrue(mManager.setDynamicShortcuts(list(si2)));
1409        assertFalse(mManager.setDynamicShortcuts(list(si2)));
1410    }
1411
1412    public void testThrottling_localeChanges() {
1413        prepareCrossProfileDataSet();
1414
1415        dumpsysOnLogcat("Before save & load");
1416
1417        mService.saveDirtyInfo();
1418        initService();
1419
1420        mInjectedLocale = Locale.CHINA;
1421        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
1422
1423        // Note at this point only user-0 is loaded, and the counters are reset for this user,
1424        // but it will work for other users too because we check the locale change at any
1425        // API entry point.
1426
1427        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1428            assertEquals(3, mManager.getRemainingCallCount());
1429        });
1430        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1431            assertEquals(3, mManager.getRemainingCallCount());
1432        });
1433        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1434            assertEquals(3, mManager.getRemainingCallCount());
1435        });
1436        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1437            assertEquals(3, mManager.getRemainingCallCount());
1438        });
1439        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1440            assertEquals(3, mManager.getRemainingCallCount());
1441        });
1442        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1443            assertEquals(3, mManager.getRemainingCallCount());
1444        });
1445
1446        // Make sure even if we receive ACTION_LOCALE_CHANGED, if the locale hasn't actually
1447        // changed, we don't reset throttling.
1448        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1449            mManager.updateShortcuts(list());
1450            assertEquals(2, mManager.getRemainingCallCount());
1451        });
1452
1453        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
1454
1455        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1456            assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
1457        });
1458
1459        mService.saveDirtyInfo();
1460        initService();
1461
1462        // The locale should be persisted, so it still shouldn't reset throttling.
1463        mService.mReceiver.onReceive(mServiceContext, new Intent(Intent.ACTION_LOCALE_CHANGED));
1464
1465        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1466            assertEquals(2, mManager.getRemainingCallCount()); // Still 2.
1467        });
1468    }
1469
1470    public void testThrottling_foreground() throws Exception {
1471        prepareCrossProfileDataSet();
1472
1473        dumpsysOnLogcat("Before save & load");
1474
1475        mService.saveDirtyInfo();
1476        initService();
1477
1478        // We need to update the current time from time to time, since some of the internal checks
1479        // rely on the time being correctly incremented.
1480        mInjectedCurrentTimeMillis++;
1481
1482        // First, all packages have less than 3 (== initial value) remaining calls.
1483
1484        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1485            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1486        });
1487        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1488            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1489        });
1490        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1491            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1492        });
1493        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1494            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1495        });
1496        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1497            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1498        });
1499        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1500            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1501        });
1502
1503        mInjectedCurrentTimeMillis++;
1504
1505        // State changed, but not foreground, so no resetting.
1506        mService.mUidObserver.onUidStateChanged(
1507                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
1508        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1509            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1510        });
1511        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1512            MoreAsserts.assertNotEqual(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        // State changed, package1 foreground, reset.
1530        mService.mUidObserver.onUidStateChanged(
1531                CALLING_UID_1, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
1532        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1533            assertEquals(3, mManager.getRemainingCallCount());
1534        });
1535        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1536            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1537        });
1538        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1539            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1540        });
1541        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1542            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1543        });
1544        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1545            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1546        });
1547        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1548            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1549        });
1550        mService.mUidObserver.onUidStateChanged(
1551                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
1552
1553        mInjectedCurrentTimeMillis++;
1554
1555        // Different app comes to foreground briefly, and goes back to background.
1556        // Now, make sure package 2's counter is reset, even in this case.
1557        mService.mUidObserver.onUidStateChanged(
1558                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
1559        mService.mUidObserver.onUidStateChanged(
1560                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
1561
1562        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1563            assertEquals(3, mManager.getRemainingCallCount());
1564        });
1565        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1566            assertEquals(3, mManager.getRemainingCallCount());
1567        });
1568        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1569            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1570        });
1571        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1572            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1573        });
1574        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1575            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1576        });
1577        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1578            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1579        });
1580
1581        mInjectedCurrentTimeMillis++;
1582
1583        // Do the same thing one more time.  This would catch the bug with mixuing up
1584        // the current time and the elapsed time.
1585        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1586            mManager.updateShortcuts(list(makeShortcut("s")));
1587            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1588        });
1589
1590        mService.mUidObserver.onUidStateChanged(
1591                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
1592        mService.mUidObserver.onUidStateChanged(
1593                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
1594
1595        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1596            assertEquals(3, mManager.getRemainingCallCount());
1597        });
1598        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1599            assertEquals(3, mManager.getRemainingCallCount());
1600        });
1601        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1602            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1603        });
1604        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1605            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1606        });
1607        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1608            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1609        });
1610        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1611            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1612        });
1613
1614        mInjectedCurrentTimeMillis++;
1615
1616        // Package 1 on user-10 comes to foreground.
1617        // Now, also try calling some APIs and make sure foreground apps don't get throttled.
1618        mService.mUidObserver.onUidStateChanged(
1619                UserHandle.getUid(USER_10, CALLING_UID_1),
1620                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
1621        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1622            assertEquals(3, mManager.getRemainingCallCount());
1623            assertFalse(mManager.isRateLimitingActive());
1624
1625            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1626
1627            assertEquals(2, mManager.getRemainingCallCount());
1628            assertFalse(mManager.isRateLimitingActive());
1629
1630            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1631
1632            assertEquals(1, mManager.getRemainingCallCount());
1633            assertFalse(mManager.isRateLimitingActive());
1634
1635            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1636
1637            assertEquals(0, mManager.getRemainingCallCount());
1638            assertTrue(mManager.isRateLimitingActive());
1639        });
1640        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1641            assertEquals(3, mManager.getRemainingCallCount());
1642
1643            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1644            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1645            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1646
1647            assertEquals(0, mManager.getRemainingCallCount());
1648            assertTrue(mManager.isRateLimitingActive());
1649        });
1650        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1651            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1652
1653            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1654            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1655            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1656
1657            assertEquals(0, mManager.getRemainingCallCount());
1658            assertTrue(mManager.isRateLimitingActive());
1659        });
1660        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1661            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1662
1663            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1664            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1665            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1666
1667            assertEquals(0, mManager.getRemainingCallCount());
1668            assertTrue(mManager.isRateLimitingActive());
1669        });
1670        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1671            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1672
1673            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1674            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1675            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1676
1677            assertEquals(0, mManager.getRemainingCallCount());
1678            assertTrue(mManager.isRateLimitingActive());
1679        });
1680        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1681            assertEquals(3, mManager.getRemainingCallCount());
1682
1683            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1684            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1685            mManager.setDynamicShortcuts(list(makeShortcut("s")));
1686
1687            assertEquals(3, mManager.getRemainingCallCount()); // Still 3!
1688            assertFalse(mManager.isRateLimitingActive());
1689        });
1690    }
1691
1692
1693    public void testThrottling_resetByInternalCall() throws Exception {
1694        prepareCrossProfileDataSet();
1695
1696        dumpsysOnLogcat("Before save & load");
1697
1698        mService.saveDirtyInfo();
1699        initService();
1700
1701        // First, all packages have less than 3 (== initial value) remaining calls.
1702
1703        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1704            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1705        });
1706        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1707            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1708        });
1709        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1710            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1711        });
1712        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1713            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1714        });
1715        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1716            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1717        });
1718        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1719            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1720        });
1721
1722        // Simulate a call from sys UI.
1723        mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
1724        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_0);
1725
1726        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1727            assertEquals(3, mManager.getRemainingCallCount());
1728        });
1729        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1730            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1731        });
1732        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1733            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1734        });
1735        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1736            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1737        });
1738        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1739            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1740        });
1741        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1742            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1743        });
1744
1745        mManager.onApplicationActive(CALLING_PACKAGE_3, USER_0);
1746
1747        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1748            assertEquals(3, mManager.getRemainingCallCount());
1749        });
1750        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1751            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1752        });
1753        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1754            assertEquals(3, mManager.getRemainingCallCount());
1755        });
1756        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1757            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1758        });
1759        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1760            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1761        });
1762        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1763            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1764        });
1765
1766        mManager.onApplicationActive(CALLING_PACKAGE_1, USER_10);
1767
1768        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
1769            assertEquals(3, mManager.getRemainingCallCount());
1770        });
1771        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1772            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1773        });
1774        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
1775            assertEquals(3, mManager.getRemainingCallCount());
1776        });
1777        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
1778            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1779        });
1780        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
1781            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
1782        });
1783        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1784            assertEquals(3, mManager.getRemainingCallCount());
1785        });
1786    }
1787
1788    public void testReportShortcutUsed() {
1789        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
1790            reset(mMockUsageStatsManagerInternal);
1791
1792            // Report with an nonexistent shortcut.
1793            mManager.reportShortcutUsed("s1");
1794            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
1795                    anyString(), anyString(), anyInt());
1796
1797            // Publish s2, but s1 still doesn't exist.
1798            mManager.setDynamicShortcuts(list(makeShortcut("s2")));
1799            mManager.reportShortcutUsed("s1");
1800            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
1801                    anyString(), anyString(), anyInt());
1802
1803            mManager.reportShortcutUsed("s2");
1804            verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
1805                    eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_10));
1806
1807        });
1808        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
1809            // Try with a different package.
1810            reset(mMockUsageStatsManagerInternal);
1811
1812            // Report with an nonexistent shortcut.
1813            mManager.reportShortcutUsed("s2");
1814            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
1815                    anyString(), anyString(), anyInt());
1816
1817            // Publish s2, but s1 still doesn't exist.
1818            mManager.setDynamicShortcuts(list(makeShortcut("s3")));
1819            mManager.reportShortcutUsed("s2");
1820            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
1821                    anyString(), anyString(), anyInt());
1822
1823            mManager.reportShortcutUsed("s3");
1824            verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
1825                    eq(CALLING_PACKAGE_2), eq("s3"), eq(USER_10));
1826
1827        });
1828    }
1829
1830    // Test for a ShortcutInfo method.
1831    public void testGetResourcePackageName() {
1832        assertEquals(null, ShortcutInfo.getResourcePackageName(""));
1833        assertEquals(null, ShortcutInfo.getResourcePackageName("abc"));
1834        assertEquals("p", ShortcutInfo.getResourcePackageName("p:"));
1835        assertEquals("p", ShortcutInfo.getResourcePackageName("p:xx"));
1836        assertEquals("pac", ShortcutInfo.getResourcePackageName("pac:"));
1837    }
1838
1839    // Test for a ShortcutInfo method.
1840    public void testGetResourceTypeName() {
1841        assertEquals(null, ShortcutInfo.getResourceTypeName(""));
1842        assertEquals(null, ShortcutInfo.getResourceTypeName(":"));
1843        assertEquals(null, ShortcutInfo.getResourceTypeName("/"));
1844        assertEquals(null, ShortcutInfo.getResourceTypeName("/:"));
1845        assertEquals("a", ShortcutInfo.getResourceTypeName(":a/"));
1846        assertEquals("type", ShortcutInfo.getResourceTypeName("xxx:type/yyy"));
1847    }
1848
1849    // Test for a ShortcutInfo method.
1850    public void testGetResourceTypeAndEntryName() {
1851        assertEquals(null, ShortcutInfo.getResourceTypeAndEntryName(""));
1852        assertEquals(null, ShortcutInfo.getResourceTypeAndEntryName("abc"));
1853        assertEquals("", ShortcutInfo.getResourceTypeAndEntryName("p:"));
1854        assertEquals("x", ShortcutInfo.getResourceTypeAndEntryName(":x"));
1855        assertEquals("x", ShortcutInfo.getResourceTypeAndEntryName("p:x"));
1856        assertEquals("xyz", ShortcutInfo.getResourceTypeAndEntryName("pac:xyz"));
1857    }
1858
1859    // Test for a ShortcutInfo method.
1860    public void testGetResourceEntryName() {
1861        assertEquals(null, ShortcutInfo.getResourceEntryName(""));
1862        assertEquals(null, ShortcutInfo.getResourceEntryName("ab:"));
1863        assertEquals("", ShortcutInfo.getResourceEntryName("/"));
1864        assertEquals("abc", ShortcutInfo.getResourceEntryName("/abc"));
1865        assertEquals("abc", ShortcutInfo.getResourceEntryName("xyz/abc"));
1866    }
1867
1868    // Test for a ShortcutInfo method.
1869    public void testLookUpResourceName_systemResources() {
1870        // For android system resources, lookUpResourceName will simply return the value as a
1871        // string, regardless of "withType".
1872        final Resources res = getTestContext().getResources();
1873
1874        assertEquals("" + android.R.string.cancel, ShortcutInfo.lookUpResourceName(res,
1875                android.R.string.cancel, true, getTestContext().getPackageName()));
1876        assertEquals("" + android.R.drawable.alert_dark_frame, ShortcutInfo.lookUpResourceName(res,
1877                android.R.drawable.alert_dark_frame, true, getTestContext().getPackageName()));
1878        assertEquals("" + android.R.string.cancel, ShortcutInfo.lookUpResourceName(res,
1879                android.R.string.cancel, false, getTestContext().getPackageName()));
1880    }
1881
1882    public void testLookUpResourceName_appResources() {
1883        final Resources res = getTestContext().getResources();
1884
1885        assertEquals("shortcut_text1", ShortcutInfo.lookUpResourceName(res,
1886                R.string.shortcut_text1, false, getTestContext().getPackageName()));
1887        assertEquals("string/shortcut_text1", ShortcutInfo.lookUpResourceName(res,
1888                R.string.shortcut_text1, true, getTestContext().getPackageName()));
1889
1890        assertEquals("black_16x64", ShortcutInfo.lookUpResourceName(res,
1891                R.drawable.black_16x64, false, getTestContext().getPackageName()));
1892        assertEquals("drawable/black_16x64", ShortcutInfo.lookUpResourceName(res,
1893                R.drawable.black_16x64, true, getTestContext().getPackageName()));
1894    }
1895
1896    // Test for a ShortcutInfo method.
1897    public void testLookUpResourceId_systemResources() {
1898        final Resources res = getTestContext().getResources();
1899
1900        assertEquals(android.R.string.cancel, ShortcutInfo.lookUpResourceId(res,
1901                "" + android.R.string.cancel, null,
1902                getTestContext().getPackageName()));
1903        assertEquals(android.R.drawable.alert_dark_frame, ShortcutInfo.lookUpResourceId(res,
1904                "" + android.R.drawable.alert_dark_frame, null,
1905                getTestContext().getPackageName()));
1906    }
1907
1908    // Test for a ShortcutInfo method.
1909    public void testLookUpResourceId_appResources() {
1910        final Resources res = getTestContext().getResources();
1911
1912        assertEquals(R.string.shortcut_text1,
1913                ShortcutInfo.lookUpResourceId(res, "shortcut_text1", "string",
1914                        getTestContext().getPackageName()));
1915
1916        assertEquals(R.string.shortcut_text1,
1917                ShortcutInfo.lookUpResourceId(res, "string/shortcut_text1", null,
1918                        getTestContext().getPackageName()));
1919
1920        assertEquals(R.drawable.black_16x64,
1921                ShortcutInfo.lookUpResourceId(res, "black_16x64", "drawable",
1922                        getTestContext().getPackageName()));
1923
1924        assertEquals(R.drawable.black_16x64,
1925                ShortcutInfo.lookUpResourceId(res, "drawable/black_16x64", null,
1926                        getTestContext().getPackageName()));
1927    }
1928
1929    public void testDumpCheckin() throws IOException {
1930        prepareCrossProfileDataSet();
1931
1932        // prepareCrossProfileDataSet() doesn't set any icons, so do set here.
1933        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
1934        final Icon res64x64 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
1935        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
1936                getTestContext().getResources(), R.drawable.black_32x32));
1937        final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource(
1938                getTestContext().getResources(), R.drawable.black_64x64));
1939
1940        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
1941            assertTrue(mManager.setDynamicShortcuts(list(
1942                    makeShortcutWithIcon("res32x32", res32x32),
1943                    makeShortcutWithIcon("res64x64", res64x64),
1944                    makeShortcutWithIcon("bmp32x32", bmp32x32),
1945                    makeShortcutWithIcon("bmp64x64", bmp64x64))));
1946        });
1947        // We can't predict the compressed bitmap sizes, so get the real sizes here.
1948        final long bitmapTotal =
1949                new File(getPackageShortcut(CALLING_PACKAGE_2, "bmp32x32", USER_0)
1950                        .getBitmapPath()).length() +
1951                new File(getPackageShortcut(CALLING_PACKAGE_2, "bmp64x64", USER_0)
1952                        .getBitmapPath()).length();
1953
1954        // Read the expected output and inject the bitmap size.
1955        final String expected = readTestAsset("shortcut/dumpsys_expected.txt")
1956                .replace("***BITMAP_SIZE***", String.valueOf(bitmapTotal));
1957
1958        assertEquals(expected, dumpCheckin());
1959    }
1960
1961    public void testDumpsysNoPermission() {
1962        assertExpectException(SecurityException.class, "android.permission.DUMP",
1963                () -> mService.dump(null, new PrintWriter(new StringWriter()), null));
1964
1965        // System can call it without the permission.
1966        runWithSystemUid(() -> {
1967            mService.dump(null, new PrintWriter(new StringWriter()), null);
1968        });
1969    }
1970}
1971