1 /* 2 * Copyright 2018 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 17 package androidx.slice; 18 19 import static androidx.slice.compat.SliceProviderCompat.PERMS_PREFIX; 20 21 import static junit.framework.Assert.assertEquals; 22 import static junit.framework.Assert.assertTrue; 23 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.eq; 26 import static org.mockito.Mockito.clearInvocations; 27 import static org.mockito.Mockito.mock; 28 import static org.mockito.Mockito.timeout; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.when; 31 32 import android.content.ContentResolver; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.net.Uri; 36 import android.support.test.InstrumentationRegistry; 37 import android.support.test.filters.SmallTest; 38 import android.support.test.runner.AndroidJUnit4; 39 40 import androidx.annotation.NonNull; 41 import androidx.core.os.BuildCompat; 42 import androidx.slice.compat.CompatPermissionManager; 43 import androidx.slice.render.SliceRenderActivity; 44 45 import org.junit.Before; 46 import org.junit.Test; 47 import org.junit.runner.RunWith; 48 49 import java.util.Arrays; 50 import java.util.Collection; 51 import java.util.List; 52 import java.util.concurrent.Executor; 53 54 @RunWith(AndroidJUnit4.class) 55 @SmallTest 56 public class SliceManagerTest { 57 58 private final Context mContext = InstrumentationRegistry.getContext(); 59 private SliceProvider mSliceProvider; 60 private SliceManager mManager; 61 62 @Before setup()63 public void setup() { 64 TestSliceProvider.sSliceProviderReceiver = mSliceProvider = mock(SliceProvider.class); 65 mManager = SliceManager.getInstance(mContext); 66 } 67 68 @Test testPin()69 public void testPin() { 70 Uri uri = new Uri.Builder() 71 .scheme(ContentResolver.SCHEME_CONTENT) 72 .authority(mContext.getPackageName()) 73 .build(); 74 try { 75 mManager.pinSlice(uri); 76 verify(mSliceProvider, timeout(2000)).onSlicePinned(eq(uri)); 77 } finally { 78 mManager.unpinSlice(uri); 79 } 80 } 81 82 @Test testUnpin()83 public void testUnpin() { 84 Uri uri = new Uri.Builder() 85 .scheme(ContentResolver.SCHEME_CONTENT) 86 .authority(mContext.getPackageName()) 87 .build(); 88 mManager.pinSlice(uri); 89 verify(mSliceProvider, timeout(2000)).onSlicePinned(eq(uri)); 90 clearInvocations(mSliceProvider); 91 mManager.unpinSlice(uri); 92 verify(mSliceProvider, timeout(2000)).onSliceUnpinned(eq(uri)); 93 } 94 95 @Test testPinList()96 public void testPinList() { 97 Uri uri = new Uri.Builder() 98 .scheme(ContentResolver.SCHEME_CONTENT) 99 .authority(mContext.getPackageName()) 100 .build(); 101 Uri longerUri = uri.buildUpon().appendPath("something").build(); 102 try { 103 mManager.pinSlice(uri); 104 mManager.pinSlice(longerUri); 105 verify(mSliceProvider, timeout(2000)).onSlicePinned(eq(longerUri)); 106 107 List<Uri> uris = mManager.getPinnedSlices(); 108 assertEquals(2, uris.size()); 109 assertTrue(uris.contains(uri)); 110 assertTrue(uris.contains(longerUri)); 111 } finally { 112 mManager.unpinSlice(uri); 113 mManager.unpinSlice(longerUri); 114 } 115 } 116 117 @Test testCallback()118 public void testCallback() { 119 if (BuildCompat.isAtLeastP()) { 120 return; 121 } 122 Uri uri = new Uri.Builder() 123 .scheme(ContentResolver.SCHEME_CONTENT) 124 .authority(mContext.getPackageName()) 125 .build(); 126 Slice s = new Slice.Builder(uri).build(); 127 SliceManager.SliceCallback callback = mock(SliceManager.SliceCallback.class); 128 when(mSliceProvider.onBindSlice(eq(uri))).thenReturn(s); 129 mManager.registerSliceCallback(uri, new Executor() { 130 @Override 131 public void execute(@NonNull Runnable command) { 132 command.run(); 133 } 134 }, callback); 135 136 mContext.getContentResolver().notifyChange(uri, null); 137 138 verify(callback, timeout(2000)).onSliceUpdated(any(Slice.class)); 139 } 140 141 @Test testPinnedSpecs()142 public void testPinnedSpecs() { 143 if (BuildCompat.isAtLeastP()) { 144 return; 145 } 146 Uri uri = new Uri.Builder() 147 .scheme(ContentResolver.SCHEME_CONTENT) 148 .authority(mContext.getPackageName()) 149 .build(); 150 mManager.pinSlice(uri); 151 verify(mSliceProvider).onSlicePinned(eq(uri)); 152 153 // Disabled while we update APIs. 154 //assertEquals(SliceLiveData.SUPPORTED_SPECS, mManager.getPinnedSpecs(uri)); 155 } 156 157 @Test testMapIntentToUriStatic()158 public void testMapIntentToUriStatic() { 159 Uri expected = Uri.parse("content://androidx.slice.view.test/render"); 160 161 Uri uri = mManager.mapIntentToUri(new Intent(mContext, SliceRenderActivity.class)); 162 163 assertEquals(expected, uri); 164 } 165 166 @Test testMapIntentToUri()167 public void testMapIntentToUri() { 168 Uri expected = Uri.parse("content://androidx.slice.view.test/render"); 169 Intent intent = new Intent("androidx.slice.action.TEST") 170 .setPackage(mContext.getPackageName()); 171 172 when(mSliceProvider.onMapIntentToUri(eq(intent))).thenReturn(expected); 173 Uri uri = mManager.mapIntentToUri(intent); 174 175 verify(mSliceProvider).onMapIntentToUri(eq(intent)); 176 assertEquals(expected, uri); 177 } 178 179 @Test testGetDescendants()180 public void testGetDescendants() { 181 Uri uri = new Uri.Builder() 182 .scheme(ContentResolver.SCHEME_CONTENT) 183 .authority(mContext.getPackageName()) 184 .build(); 185 Collection<Uri> collection = Arrays.asList( 186 uri, 187 uri.buildUpon().appendPath("1").build(), 188 uri.buildUpon().appendPath("2").build() 189 ); 190 when(mSliceProvider.onGetSliceDescendants(any(Uri.class))) 191 .thenReturn(collection); 192 193 Collection<Uri> allUris = mManager.getSliceDescendants(uri); 194 195 assertEquals(allUris, collection); 196 verify(mSliceProvider).onGetSliceDescendants(eq(uri)); 197 } 198 199 public static class TestSliceProvider extends SliceProvider { 200 201 public static SliceProvider sSliceProviderReceiver; 202 203 @Override onCreateSliceProvider()204 public boolean onCreateSliceProvider() { 205 if (sSliceProviderReceiver != null) { 206 sSliceProviderReceiver.onCreateSliceProvider(); 207 } 208 return true; 209 } 210 211 @Override onBindSlice(Uri sliceUri)212 public Slice onBindSlice(Uri sliceUri) { 213 if (sSliceProviderReceiver != null) { 214 return sSliceProviderReceiver.onBindSlice(sliceUri); 215 } 216 return null; 217 } 218 219 @NonNull 220 @Override onMapIntentToUri(Intent intent)221 public Uri onMapIntentToUri(Intent intent) { 222 if (sSliceProviderReceiver != null) { 223 return sSliceProviderReceiver.onMapIntentToUri(intent); 224 } 225 return null; 226 } 227 228 @Override onSlicePinned(Uri sliceUri)229 public void onSlicePinned(Uri sliceUri) { 230 if (sSliceProviderReceiver != null) { 231 sSliceProviderReceiver.onSlicePinned(sliceUri); 232 } 233 } 234 235 @Override onSliceUnpinned(Uri sliceUri)236 public void onSliceUnpinned(Uri sliceUri) { 237 if (sSliceProviderReceiver != null) { 238 sSliceProviderReceiver.onSliceUnpinned(sliceUri); 239 } 240 } 241 onCreatePermissionManager( String[] autoGrantPermissions)242 protected CompatPermissionManager onCreatePermissionManager( 243 String[] autoGrantPermissions) { 244 return new CompatPermissionManager(getContext(), PERMS_PREFIX + getClass().getName(), 245 -1 /* Different uid to run permissions */, autoGrantPermissions); 246 } 247 248 @Override onGetSliceDescendants(Uri uri)249 public Collection<Uri> onGetSliceDescendants(Uri uri) { 250 if (sSliceProviderReceiver != null) { 251 return sSliceProviderReceiver.onGetSliceDescendants(uri); 252 } 253 return super.onGetSliceDescendants(uri); 254 } 255 } 256 } 257