ShortcutManagerCompatTest.java revision ab5e1a448f10ecacf1ac6a642523e48e79784e62
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 */
16
17package android.support.v4.content.pm;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertNotNull;
22import static org.junit.Assert.assertTrue;
23import static org.mockito.Mockito.any;
24import static org.mockito.Mockito.anyInt;
25import static org.mockito.Mockito.doReturn;
26import static org.mockito.Mockito.eq;
27import static org.mockito.Mockito.isNull;
28import static org.mockito.Mockito.mock;
29import static org.mockito.Mockito.reset;
30import static org.mockito.Mockito.spy;
31import static org.mockito.Mockito.times;
32import static org.mockito.Mockito.verify;
33import static org.mockito.Mockito.when;
34
35import android.annotation.TargetApi;
36import android.app.PendingIntent;
37import android.content.BroadcastReceiver;
38import android.content.Context;
39import android.content.Intent;
40import android.content.IntentFilter;
41import android.content.IntentSender;
42import android.content.pm.ActivityInfo;
43import android.content.pm.PackageManager;
44import android.content.pm.ResolveInfo;
45import android.content.pm.ShortcutInfo;
46import android.content.pm.ShortcutManager;
47import android.graphics.Bitmap;
48import android.support.test.filters.SmallTest;
49import android.support.test.runner.AndroidJUnit4;
50import android.support.v4.BaseInstrumentationTestCase;
51import android.support.v4.app.TestSupportActivity;
52import android.support.v4.os.BuildCompat;
53
54import org.junit.Before;
55import org.junit.Test;
56import org.junit.runner.RunWith;
57import org.mockito.ArgumentCaptor;
58
59import java.util.Arrays;
60import java.util.concurrent.CountDownLatch;
61import java.util.concurrent.TimeUnit;
62
63@RunWith(AndroidJUnit4.class)
64@SmallTest
65public class ShortcutManagerCompatTest extends BaseInstrumentationTestCase<TestSupportActivity> {
66
67    Context mContext;
68    ShortcutInfoCompat mInfoCompat;
69
70    public ShortcutManagerCompatTest() {
71        super(TestSupportActivity.class);
72    }
73
74    @Before
75    public void setup() {
76        mContext = spy(mActivityTestRule.getActivity());
77        mInfoCompat = new ShortcutInfoCompat.Builder(mContext, "test-id")
78                .setIcon(Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888))
79                .setShortLabel("Test shortcut")
80                .setIntent(new Intent("Dummy"))
81                .build();
82    }
83
84    @Test
85    @TargetApi(26)
86    public void testIsRequestPinShortcutSupported_v26() throws Throwable {
87        if (!BuildCompat.isAtLeastO()) {
88            return;
89        }
90
91        ShortcutManager mockShortcutManager = mockShortcutManager();
92        when(mockShortcutManager.isRequestPinShortcutSupported()).thenReturn(true, false, true);
93
94        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
95        assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
96        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
97        verify(mockShortcutManager, times(3)).isRequestPinShortcutSupported();
98    }
99
100    @Test
101    @TargetApi(26)
102    public void testRequestPinShortcut_v26()  throws Throwable {
103        if (!BuildCompat.isAtLeastO()) {
104            return;
105        }
106
107        ShortcutManager mockShortcutManager = mockShortcutManager();
108        when(mockShortcutManager.requestPinShortcut(
109                any(ShortcutInfo.class), any(IntentSender.class))).thenReturn(true);
110
111        assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat, null));
112        ArgumentCaptor<ShortcutInfo> captor = ArgumentCaptor.forClass(ShortcutInfo.class);
113        verify(mockShortcutManager, times(1)).requestPinShortcut(captor.capture(),
114                (IntentSender) isNull());
115        assertEquals("test-id", captor.getValue().getId());
116    }
117
118    @Test
119    @TargetApi(26)
120    public void testCreateShortcutResultIntent_v26()  throws Throwable {
121        if (!BuildCompat.isAtLeastO()) {
122            return;
123        }
124
125        ShortcutManager mockShortcutManager = mockShortcutManager();
126
127        when(mockShortcutManager.createShortcutResultIntent(any(ShortcutInfo.class)))
128                .thenReturn(new Intent("some-dummy-action"));
129
130        Intent result = ShortcutManagerCompat.createShortcutResultIntent(mContext, mInfoCompat);
131        verifyLegacyIntent(result);
132        assertEquals("some-dummy-action", result.getAction());
133
134        ArgumentCaptor<ShortcutInfo> captor = ArgumentCaptor.forClass(ShortcutInfo.class);
135        verify(mockShortcutManager, times(1)).createShortcutResultIntent(captor.capture());
136        assertEquals("test-id", captor.getValue().getId());
137    }
138
139    private ShortcutManager mockShortcutManager() {
140        ShortcutManager mockShortcutManager = mock(ShortcutManager.class);
141        doReturn(mockShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE));
142        return mockShortcutManager;
143    }
144
145    @Test
146    public void testIsRequestPinShortcutSupported_v4() throws Throwable {
147        if (BuildCompat.isAtLeastO()) {
148            return;
149        }
150        setMockPm(mockResolveInfo(null));
151        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
152
153        // We do not have the permission
154        setMockPm(mockResolveInfo("com.android.permission.something-we-dont-have"));
155        assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
156
157        // There are no receivers
158        setMockPm();
159        assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
160
161        // At least one receiver is supported
162        setMockPm(mockResolveInfo("com.android.permission.something-we-dont-have"),
163                mockResolveInfo(null));
164        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
165
166        // We have the permission
167        setMockPm(mockResolveInfo(ShortcutManagerCompat.INSTALL_SHORTCUT_PERMISSION));
168        assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext));
169    }
170
171    @Test
172    public void testRequestPinShortcut_v4_noCallback()  throws Throwable {
173        if (BuildCompat.isAtLeastO()) {
174            return;
175        }
176
177        setMockPm(mockResolveInfo(null));
178
179        BlockingBroadcastReceiver receiver =
180                new BlockingBroadcastReceiver(ShortcutManagerCompat.ACTION_INSTALL_SHORTCUT);
181        assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat, null));
182        verifyLegacyIntent(receiver.blockingGetIntent());
183    }
184
185    @Test
186    public void testRequestPinShortcut_v4_withCallback()  throws Throwable {
187        if (BuildCompat.isAtLeastO()) {
188            return;
189        }
190
191        setMockPm(mockResolveInfo(null));
192
193        BlockingBroadcastReceiver receiver =
194                new BlockingBroadcastReceiver(ShortcutManagerCompat.ACTION_INSTALL_SHORTCUT);
195        BlockingBroadcastReceiver callback =
196                new BlockingBroadcastReceiver("shortcut-callback");
197
198        assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat,
199                PendingIntent.getBroadcast(mContext, 0, new Intent("shortcut-callback"),
200                        PendingIntent.FLAG_ONE_SHOT).getIntentSender()));
201        verifyLegacyIntent(receiver.blockingGetIntent());
202        assertNotNull(callback.blockingGetIntent());
203    }
204
205    @Test
206    public void testCreateShortcutResultIntent_v4() throws Throwable {
207        if (BuildCompat.isAtLeastO()) {
208            return;
209        }
210
211        verifyLegacyIntent(ShortcutManagerCompat.createShortcutResultIntent(mContext, mInfoCompat));
212    }
213
214    private void verifyLegacyIntent(Intent intent) {
215        assertNotNull(intent);
216        assertEquals("Test shortcut", intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME));
217        assertEquals("Dummy", ((Intent) intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT))
218                .getAction());
219    }
220
221    private void setMockPm(ResolveInfo... infos) {
222        PackageManager pm = mock(PackageManager.class);
223        when(pm.queryBroadcastReceivers(any(Intent.class), anyInt()))
224                .thenReturn(Arrays.asList(infos));
225        reset(mContext);
226        doReturn(pm).when(mContext).getPackageManager();
227    }
228
229    private ResolveInfo mockResolveInfo(String permission) {
230        ActivityInfo aInfo = new ActivityInfo();
231        aInfo.packageName = mContext.getPackageName();
232        aInfo.permission = permission;
233        ResolveInfo rInfo = new ResolveInfo();
234        rInfo.activityInfo = aInfo;
235        return rInfo;
236    }
237
238    private class BlockingBroadcastReceiver extends BroadcastReceiver {
239
240        private final CountDownLatch mLatch = new CountDownLatch(1);
241        private Intent mIntent;
242
243        BlockingBroadcastReceiver(String action) {
244            mContext.registerReceiver(this, new IntentFilter(action));
245        }
246
247        @Override
248        public void onReceive(Context context, Intent intent) {
249            mIntent = intent;
250            mLatch.countDown();
251        }
252
253        public Intent blockingGetIntent() throws InterruptedException {
254            mLatch.await(5, TimeUnit.SECONDS);
255            mContext.unregisterReceiver(this);
256            return mIntent;
257        }
258    }
259}
260