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