Home | History | Annotate | Download | only in slice
      1 package com.android.server.slice;
      2 
      3 import static org.junit.Assert.assertArrayEquals;
      4 import static org.junit.Assert.assertEquals;
      5 import static org.junit.Assert.assertFalse;
      6 import static org.junit.Assert.assertNull;
      7 import static org.junit.Assert.assertTrue;
      8 import static org.mockito.ArgumentMatchers.any;
      9 import static org.mockito.ArgumentMatchers.anyInt;
     10 import static org.mockito.ArgumentMatchers.anyString;
     11 import static org.mockito.ArgumentMatchers.argThat;
     12 import static org.mockito.ArgumentMatchers.eq;
     13 import static org.mockito.Mockito.doReturn;
     14 import static org.mockito.Mockito.mock;
     15 import static org.mockito.Mockito.verify;
     16 import static org.mockito.Mockito.when;
     17 
     18 import android.app.slice.ISliceListener;
     19 import android.app.slice.SliceProvider;
     20 import android.app.slice.SliceSpec;
     21 import android.content.ContentProvider;
     22 import android.content.IContentProvider;
     23 import android.net.Uri;
     24 import android.os.Binder;
     25 import android.os.Handler;
     26 import android.os.IBinder;
     27 import android.os.IBinder.DeathRecipient;
     28 import android.os.RemoteException;
     29 import android.support.test.filters.SmallTest;
     30 import android.testing.AndroidTestingRunner;
     31 import android.testing.TestableLooper;
     32 import android.testing.TestableLooper.RunWithLooper;
     33 
     34 import com.android.server.UiServiceTestCase;
     35 
     36 import org.junit.Before;
     37 import org.junit.Test;
     38 import org.junit.runner.RunWith;
     39 import org.mockito.ArgumentCaptor;
     40 
     41 @SmallTest
     42 @RunWith(AndroidTestingRunner.class)
     43 @RunWithLooper
     44 public class PinnedSliceStateTest extends UiServiceTestCase {
     45 
     46     private static final String AUTH = "my.authority";
     47     private static final Uri TEST_URI = Uri.parse("content://" + AUTH + "/path");
     48 
     49     private static final SliceSpec[] FIRST_SPECS = new SliceSpec[]{
     50             new SliceSpec("spec1", 3),
     51             new SliceSpec("spec2", 3),
     52             new SliceSpec("spec3", 2),
     53             new SliceSpec("spec4", 1),
     54     };
     55 
     56     private static final SliceSpec[] SECOND_SPECS = new SliceSpec[]{
     57             new SliceSpec("spec2", 1),
     58             new SliceSpec("spec3", 2),
     59             new SliceSpec("spec4", 3),
     60             new SliceSpec("spec5", 4),
     61     };
     62 
     63     private SliceManagerService mSliceService;
     64     private PinnedSliceState mPinnedSliceManager;
     65     private IContentProvider mIContentProvider;
     66     private ContentProvider mContentProvider;
     67     private IBinder mToken = new Binder();
     68 
     69     @Before
     70     public void setup() {
     71         mSliceService = mock(SliceManagerService.class);
     72         when(mSliceService.getContext()).thenReturn(mContext);
     73         when(mSliceService.getLock()).thenReturn(new Object());
     74         when(mSliceService.getHandler()).thenReturn(new Handler(TestableLooper.get(this).getLooper()));
     75         mContentProvider = mock(ContentProvider.class);
     76         mIContentProvider = mock(IContentProvider.class);
     77         when(mContentProvider.getIContentProvider()).thenReturn(mIContentProvider);
     78         mContext.getContentResolver().addProvider(AUTH, mContentProvider);
     79         mPinnedSliceManager = new PinnedSliceState(mSliceService, TEST_URI, "pkg");
     80     }
     81 
     82     @Test
     83     public void testMergeSpecs() {
     84         // No annotations to start.
     85         assertNull(mPinnedSliceManager.getSpecs());
     86 
     87         mPinnedSliceManager.mergeSpecs(FIRST_SPECS);
     88         assertArrayEquals(FIRST_SPECS, mPinnedSliceManager.getSpecs());
     89 
     90         mPinnedSliceManager.mergeSpecs(SECOND_SPECS);
     91         assertArrayEquals(new SliceSpec[]{
     92                 // spec1 is gone because it's not in the second set.
     93                 new SliceSpec("spec2", 1), // spec2 is 1 because it's smaller in the second set.
     94                 new SliceSpec("spec3", 2), // spec3 is the same in both sets
     95                 new SliceSpec("spec4", 1), // spec4 is 1 because it's smaller in the first set.
     96                 // spec5 is gone because it's not in the first set.
     97         }, mPinnedSliceManager.getSpecs());
     98     }
     99 
    100     @Test
    101     public void testSendPinnedOnPin() throws RemoteException {
    102         TestableLooper.get(this).processAllMessages();
    103 
    104         // When pinned for the first time, a pinned message should be sent.
    105         mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
    106         TestableLooper.get(this).processAllMessages();
    107 
    108         verify(mIContentProvider).call(anyString(), eq(SliceProvider.METHOD_PIN), eq(null),
    109                 argThat(b -> {
    110                     assertEquals(TEST_URI, b.getParcelable(SliceProvider.EXTRA_BIND_URI));
    111                     return true;
    112                 }));
    113     }
    114 
    115     @Test
    116     public void testPkgPin() {
    117         assertFalse(mPinnedSliceManager.hasPinOrListener());
    118 
    119         mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
    120         assertTrue(mPinnedSliceManager.hasPinOrListener());
    121 
    122         assertTrue(mPinnedSliceManager.unpin("pkg", mToken));
    123         assertFalse(mPinnedSliceManager.hasPinOrListener());
    124     }
    125 
    126     @Test
    127     public void testMultiPkgPin() {
    128         IBinder t2 = new Binder();
    129         assertFalse(mPinnedSliceManager.hasPinOrListener());
    130 
    131         mPinnedSliceManager.pin("pkg", FIRST_SPECS, mToken);
    132         assertTrue(mPinnedSliceManager.hasPinOrListener());
    133         mPinnedSliceManager.pin("pkg2", FIRST_SPECS, t2);
    134 
    135         assertFalse(mPinnedSliceManager.unpin("pkg", mToken));
    136         assertTrue(mPinnedSliceManager.unpin("pkg2", t2));
    137         assertFalse(mPinnedSliceManager.hasPinOrListener());
    138     }
    139 
    140     @Test
    141     public void testListenerDeath() throws RemoteException {
    142         ISliceListener listener = mock(ISliceListener.class);
    143         IBinder binder = mock(IBinder.class);
    144         when(binder.isBinderAlive()).thenReturn(true);
    145         when(listener.asBinder()).thenReturn(binder);
    146         assertFalse(mPinnedSliceManager.hasPinOrListener());
    147 
    148         mPinnedSliceManager.pin(mContext.getPackageName(), FIRST_SPECS, binder);
    149         assertTrue(mPinnedSliceManager.hasPinOrListener());
    150 
    151         ArgumentCaptor<DeathRecipient> arg = ArgumentCaptor.forClass(DeathRecipient.class);
    152         verify(binder).linkToDeath(arg.capture(), anyInt());
    153 
    154         when(binder.isBinderAlive()).thenReturn(false);
    155         arg.getValue().binderDied();
    156 
    157         verify(mSliceService).removePinnedSlice(eq(TEST_URI));
    158         assertFalse(mPinnedSliceManager.hasPinOrListener());
    159     }
    160 }
    161