| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.core.content.pm; |
| |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertTrue; |
| import static org.mockito.ArgumentMatchers.nullable; |
| import static org.mockito.Mockito.any; |
| import static org.mockito.Mockito.anyInt; |
| import static org.mockito.Mockito.doNothing; |
| import static org.mockito.Mockito.doReturn; |
| import static org.mockito.Mockito.eq; |
| import static org.mockito.Mockito.isNull; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.reset; |
| import static org.mockito.Mockito.spy; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.when; |
| |
| import android.app.PendingIntent; |
| import android.content.BroadcastReceiver; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentSender; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.content.pm.ShortcutInfo; |
| import android.content.pm.ShortcutManager; |
| import android.graphics.Bitmap; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.support.v4.BaseInstrumentationTestCase; |
| |
| import androidx.core.app.TestActivity; |
| import androidx.core.graphics.drawable.IconCompat; |
| import androidx.test.ext.junit.runners.AndroidJUnit4; |
| import androidx.test.filters.LargeTest; |
| import androidx.test.filters.MediumTest; |
| import androidx.test.filters.SdkSuppress; |
| |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.mockito.ArgumentCaptor; |
| |
| import java.util.Arrays; |
| |
| @RunWith(AndroidJUnit4.class) |
| public class ShortcutManagerCompatTest extends BaseInstrumentationTestCase<TestActivity> { |
| |
| Context mContext; |
| ShortcutInfoCompat mInfoCompat; |
| |
| public ShortcutManagerCompatTest() { |
| super(TestActivity.class); |
| } |
| |
| @Before |
| public void setup() { |
| mContext = spy(mActivityTestRule.getActivity()); |
| mInfoCompat = new ShortcutInfoCompat.Builder(mContext, "test-id") |
| .setIcon(IconCompat.createWithBitmap(Bitmap.createBitmap( |
| 10, 10, Bitmap.Config.ARGB_8888))) |
| .setShortLabel("Test shortcut") |
| .setIntent(new Intent("Dummy")) |
| .build(); |
| } |
| |
| @Test |
| @MediumTest |
| @SdkSuppress(minSdkVersion = 26) |
| public void testIsRequestPinShortcutSupported_v26() throws Throwable { |
| ShortcutManager mockShortcutManager = mock(ShortcutManager.class); |
| doReturn(mockShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE)); |
| when(mockShortcutManager.isRequestPinShortcutSupported()).thenReturn(true, false, true); |
| |
| assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext)); |
| assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext)); |
| assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext)); |
| verify(mockShortcutManager, times(3)).isRequestPinShortcutSupported(); |
| } |
| |
| @Test |
| @MediumTest |
| @SdkSuppress(minSdkVersion = 26) |
| public void testRequestPinShortcut_v26() throws Throwable { |
| ShortcutManager mockShortcutManager = mock(ShortcutManager.class); |
| doReturn(mockShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE)); |
| when(mockShortcutManager.requestPinShortcut( |
| any(ShortcutInfo.class), nullable(IntentSender.class))).thenReturn(true); |
| |
| assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat, null)); |
| ArgumentCaptor<ShortcutInfo> captor = ArgumentCaptor.forClass(ShortcutInfo.class); |
| verify(mockShortcutManager, times(1)).requestPinShortcut(captor.capture(), |
| (IntentSender) isNull()); |
| assertEquals("test-id", captor.getValue().getId()); |
| } |
| |
| @Test |
| @MediumTest |
| @SdkSuppress(minSdkVersion = 26) |
| public void testCreateShortcutResultIntent_v26() throws Throwable { |
| ShortcutManager mockShortcutManager = mock(ShortcutManager.class); |
| doReturn(mockShortcutManager).when(mContext).getSystemService(eq(Context.SHORTCUT_SERVICE)); |
| |
| when(mockShortcutManager.createShortcutResultIntent(any(ShortcutInfo.class))) |
| .thenReturn(new Intent("some-dummy-action")); |
| |
| Intent result = ShortcutManagerCompat.createShortcutResultIntent(mContext, mInfoCompat); |
| verifyLegacyIntent(result); |
| assertEquals("some-dummy-action", result.getAction()); |
| |
| ArgumentCaptor<ShortcutInfo> captor = ArgumentCaptor.forClass(ShortcutInfo.class); |
| verify(mockShortcutManager, times(1)).createShortcutResultIntent(captor.capture()); |
| assertEquals("test-id", captor.getValue().getId()); |
| } |
| |
| @MediumTest |
| @Test |
| @SdkSuppress(maxSdkVersion = 25) |
| public void testIsRequestPinShortcutSupported_v4() throws Throwable { |
| setMocks(mockResolveInfo(null)); |
| assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext)); |
| |
| // We do not have the permission |
| setMocks(mockResolveInfo("com.android.permission.something-we-dont-have")); |
| assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext)); |
| |
| // There are no receivers |
| setMocks(); |
| assertFalse(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext)); |
| |
| // At least one receiver is supported |
| setMocks(mockResolveInfo("com.android.permission.something-we-dont-have"), |
| mockResolveInfo(null)); |
| assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext)); |
| |
| // We have the permission |
| setMocks(mockResolveInfo(ShortcutManagerCompat.INSTALL_SHORTCUT_PERMISSION)); |
| assertTrue(ShortcutManagerCompat.isRequestPinShortcutSupported(mContext)); |
| } |
| |
| @LargeTest |
| @Test |
| @SdkSuppress(maxSdkVersion = 25) |
| public void testRequestPinShortcut_v4_noCallback() { |
| setMocks(mockResolveInfo(null)); |
| assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat, null)); |
| final ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext).sendBroadcast(argument.capture()); |
| verifyLegacyIntent(argument.getValue()); |
| } |
| |
| @LargeTest |
| @Test |
| @SdkSuppress(maxSdkVersion = 25) |
| public void testRequestPinShortcut_v4_withCallback() { |
| setMocks(mockResolveInfo(null)); |
| assertTrue(ShortcutManagerCompat.requestPinShortcut(mContext, mInfoCompat, |
| PendingIntent.getBroadcast(mContext, 0, new Intent("shortcut-callback"), |
| PendingIntent.FLAG_ONE_SHOT).getIntentSender())); |
| final ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class); |
| verify(mContext).sendOrderedBroadcast(argument.capture(), nullable(String.class), |
| any(BroadcastReceiver.class), nullable(Handler.class), anyInt(), |
| nullable(String.class), nullable(Bundle.class)); |
| verifyLegacyIntent(argument.getValue()); |
| } |
| |
| @MediumTest |
| @Test |
| @SdkSuppress(maxSdkVersion = 25) |
| public void testCreateShortcutResultIntent_v4() throws Throwable { |
| verifyLegacyIntent(ShortcutManagerCompat.createShortcutResultIntent(mContext, mInfoCompat)); |
| } |
| |
| private void verifyLegacyIntent(Intent intent) { |
| assertNotNull(intent); |
| assertEquals("Test shortcut", intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME)); |
| assertEquals("Dummy", ((Intent) intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT)) |
| .getAction()); |
| } |
| |
| private void setMocks(ResolveInfo... infos) { |
| PackageManager pm = mock(PackageManager.class); |
| when(pm.queryBroadcastReceivers(any(Intent.class), anyInt())) |
| .thenReturn(Arrays.asList(infos)); |
| reset(mContext); |
| doReturn(pm).when(mContext).getPackageManager(); |
| doNothing().when(mContext).sendBroadcast(any(Intent.class)); |
| doNothing().when(mContext).sendOrderedBroadcast(any(Intent.class), nullable(String.class), |
| any(BroadcastReceiver.class), nullable(Handler.class), anyInt(), |
| nullable(String.class), nullable(Bundle.class)); |
| } |
| |
| private ResolveInfo mockResolveInfo(String permission) { |
| ActivityInfo aInfo = new ActivityInfo(); |
| aInfo.packageName = mContext.getPackageName(); |
| aInfo.permission = permission; |
| ResolveInfo rInfo = new ResolveInfo(); |
| rInfo.activityInfo = aInfo; |
| return rInfo; |
| } |
| } |