1/*
2 * Copyright (C) 2017 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
19        .assertExpectException;
20import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
21
22import android.content.ComponentName;
23import android.content.Intent;
24import android.content.pm.LauncherActivityInfo;
25import android.content.pm.LauncherApps.PinItemRequest;
26import android.content.pm.ShortcutInfo;
27import android.content.pm.ShortcutManager;
28import android.os.Process;
29import android.test.suitebuilder.annotation.SmallTest;
30
31import static org.mockito.Mockito.*;
32
33/**
34 * Tests for {@link ShortcutManager#createShortcutResultIntent(ShortcutInfo)} and relevant APIs.
35 *
36 m FrameworksServicesTests &&
37 adb install \
38 -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
39 adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest10 \
40 -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
41 */
42@SmallTest
43public class ShortcutManagerTest10 extends BaseShortcutManagerTest {
44
45    private PinItemRequest mRequest;
46
47    private PinItemRequest verifyAndGetCreateShortcutResult(Intent resultIntent) {
48        PinItemRequest request = mLauncherApps.getPinItemRequest(resultIntent);
49        assertNotNull(request);
50        assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, request.getRequestType());
51        return request;
52    }
53
54    public void testCreateShortcutResult_noDefaultLauncher() {
55        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
56            ShortcutInfo s1 = makeShortcut("s1");
57            assertNull(mManager.createShortcutResultIntent(s1));
58        });
59    }
60
61    public void testCreateShortcutResult_validResult() {
62        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
63
64        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
65            ShortcutInfo s1 = makeShortcut("s1");
66            Intent intent = mManager.createShortcutResultIntent(s1);
67            mRequest = verifyAndGetCreateShortcutResult(intent);
68        });
69
70        runWithCaller(LAUNCHER_1, USER_0, () -> {
71            assertTrue(mRequest.isValid());
72            assertTrue(mRequest.accept());
73        });
74    }
75
76    public void testCreateShortcutResult_alreadyPinned() {
77        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
78
79        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
80            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
81        });
82
83        runWithCaller(LAUNCHER_1, USER_0, () -> {
84            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
85        });
86
87        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
88            ShortcutInfo s1 = makeShortcut("s1");
89            Intent intent = mManager.createShortcutResultIntent(s1);
90            mRequest = verifyAndGetCreateShortcutResult(intent);
91        });
92
93        runWithCaller(LAUNCHER_1, USER_0, () -> {
94            assertTrue(mRequest.isValid());
95            assertTrue(mRequest.getShortcutInfo().isPinned());
96            assertTrue(mRequest.accept());
97        });
98    }
99
100    public void testCreateShortcutResult_alreadyPinnedByAnother() {
101        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
102            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
103        });
104
105        // Initially all launchers have the shortcut permission, until we call setDefaultLauncher().
106        runWithCaller(LAUNCHER_2, USER_0, () -> {
107            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
108        });
109
110        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
111        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
112            ShortcutInfo s1 = makeShortcut("s1");
113            Intent intent = mManager.createShortcutResultIntent(s1);
114            mRequest = verifyAndGetCreateShortcutResult(intent);
115        });
116
117        runWithCaller(LAUNCHER_1, USER_0, () -> {
118            assertTrue(mRequest.isValid());
119            assertFalse(mRequest.getShortcutInfo().isPinned());
120            assertTrue(mRequest.accept());
121        });
122    }
123
124    public void testCreateShortcutResult_defaultLauncherChanges() {
125        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
126
127        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
128            ShortcutInfo s1 = makeShortcut("s1");
129            Intent intent = mManager.createShortcutResultIntent(s1);
130            mRequest = verifyAndGetCreateShortcutResult(intent);
131        });
132
133        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_2, USER_0));
134        // Verify that other launcher can't use this request
135        runWithCaller(LAUNCHER_2, USER_0, () -> {
136            assertFalse(mRequest.isValid());
137            assertExpectException(SecurityException.class, "Calling uid mismatch",
138                    mRequest::accept);
139        });
140
141        runWithCaller(LAUNCHER_1, USER_0, () -> {
142            // Set some random caller UID.
143            mInjectedCallingUid = 12345;
144
145            assertFalse(mRequest.isValid());
146            assertExpectException(SecurityException.class, "Calling uid mismatch",
147                    mRequest::accept);
148        });
149
150        runWithCaller(LAUNCHER_1, USER_0, () -> {
151            assertTrue(mRequest.isValid());
152            assertTrue(mRequest.accept());
153        });
154    }
155
156    private LauncherActivityInfo setupMockActivityInfo() {
157        doReturn(getTestContext().getPackageName()).when(mServiceContext).getPackageName();
158        doReturn(getTestContext().getContentResolver()).when(mServiceContext).getContentResolver();
159
160        LauncherActivityInfo info = mock(LauncherActivityInfo.class);
161        when(info.getComponentName()).thenReturn(
162                new ComponentName(getTestContext(), "a.ShortcutConfigActivity"));
163        when(info.getUser()).thenReturn(Process.myUserHandle());
164        return info;
165    }
166
167    public void testStartConfigActivity_defaultLauncher() {
168        LauncherActivityInfo info = setupMockActivityInfo();
169        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
170        runWithCaller(LAUNCHER_1, USER_0, () ->
171            assertNotNull(mLauncherApps.getShortcutConfigActivityIntent(info))
172        );
173    }
174
175    public void testStartConfigActivity_nonDefaultLauncher() {
176        LauncherActivityInfo info = setupMockActivityInfo();
177        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
178        runWithCaller(LAUNCHER_2, USER_0, () ->
179            assertExpectException(SecurityException.class, null, () ->
180                    mLauncherApps.getShortcutConfigActivityIntent(info))
181        );
182    }
183}
184