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 package com.android.documentsui.inspector; 17 18 import static android.provider.DocumentsContract.Document.FLAG_SUPPORTS_SETTINGS; 19 import static junit.framework.Assert.assertEquals; 20 import static junit.framework.Assert.assertFalse; 21 import static junit.framework.Assert.assertNotNull; 22 import static junit.framework.Assert.assertTrue; 23 24 import android.app.Activity; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.graphics.drawable.Drawable; 28 import android.net.Uri; 29 import android.os.Looper; 30 import android.provider.DocumentsContract; 31 import android.provider.DocumentsContract.Document; 32 import android.support.annotation.Nullable; 33 import android.support.test.InstrumentationRegistry; 34 import android.support.test.runner.AndroidJUnit4; 35 import android.test.suitebuilder.annotation.SmallTest; 36 import android.view.View.OnClickListener; 37 import com.android.documentsui.InspectorProvider; 38 import com.android.documentsui.ProviderExecutor; 39 import com.android.documentsui.base.DocumentInfo; 40 import com.android.documentsui.inspector.InspectorController.DetailsDisplay; 41 import com.android.documentsui.inspector.InspectorController.Loader; 42 import com.android.documentsui.inspector.actions.Action; 43 import com.android.documentsui.inspector.InspectorController.ActionDisplay; 44 import com.android.documentsui.testing.TestConsumer; 45 import com.android.documentsui.testing.TestEnv; 46 import com.android.documentsui.testing.TestLoaderManager; 47 import com.android.documentsui.testing.TestPackageManager; 48 import com.android.documentsui.testing.TestPackageManager.TestResolveInfo; 49 import com.android.documentsui.testing.TestProvidersAccess; 50 import java.util.ArrayList; 51 import org.junit.Assert; 52 import org.junit.Before; 53 import org.junit.Test; 54 import org.junit.runner.RunWith; 55 56 @RunWith(AndroidJUnit4.class) 57 @SmallTest 58 public class InspectorControllerTest { 59 60 private static final String OPEN_IN_PROVIDER_DOC = "OpenInProviderTest"; 61 62 private TestActivity mContext; 63 private TestLoaderManager mLoaderManager; 64 private Loader mLoader; 65 private TestPackageManager mPm; 66 private InspectorController mController; 67 private TestEnv mEnv; 68 private TestConsumer<DocumentInfo> mHeaderTestDouble; 69 private TestDetails mDetailsTestDouble; 70 private TestAction mShowInProvider; 71 private TestAction mDefaultsTestDouble; 72 private TestConsumer<DocumentInfo> mDebugTestDouble; 73 private Boolean mShowSnackbarsCalled; 74 75 @Before 76 public void setUp() throws Exception { 77 78 //Needed to create a non null loader for the InspectorController. 79 Context loader = InstrumentationRegistry.getTargetContext(); 80 mEnv = TestEnv.create(); 81 mPm = TestPackageManager.create(); 82 mLoaderManager = new TestLoaderManager(); 83 mLoader = new DocumentLoader(loader, mLoaderManager); 84 mHeaderTestDouble = new TestConsumer<>(); 85 mDetailsTestDouble = new TestDetails(); 86 mShowInProvider = new TestAction(); 87 mDefaultsTestDouble = new TestAction(); 88 mDebugTestDouble = new TestConsumer<>(); 89 90 mShowSnackbarsCalled = false; 91 92 //Crashes if not called before "new TestActivity". 93 if (Looper.myLooper() == null) { 94 Looper.prepare(); 95 } 96 mContext = new TestActivity(); 97 98 mController = new InspectorController( 99 mContext, 100 mLoader, 101 mPm, 102 new TestProvidersAccess(), 103 false, 104 mHeaderTestDouble, 105 mDetailsTestDouble, 106 mShowInProvider, 107 mDefaultsTestDouble, 108 mDebugTestDouble, 109 ProviderExecutor::forAuthority, 110 () -> { 111 mShowSnackbarsCalled = true; 112 } 113 ); 114 } 115 116 /** 117 * Tests Debug view should be hidden and therefore not updated by default. 118 */ 119 @Test 120 public void testHideDebugByDefault() throws Exception { 121 mController.updateView(new DocumentInfo()); 122 mDebugTestDouble.assertNotCalled(); 123 } 124 125 /** 126 * Tests Debug view should be updated when visible. 127 */ 128 @Test 129 public void testShowDebugUpdatesView() throws Exception { 130 mController = new InspectorController( 131 mContext, 132 mLoader, 133 mPm, 134 new TestProvidersAccess(), 135 true, 136 mHeaderTestDouble, 137 mDetailsTestDouble, 138 mShowInProvider, 139 mDefaultsTestDouble, 140 mDebugTestDouble, 141 ProviderExecutor::forAuthority, 142 () -> { 143 mShowSnackbarsCalled = true; 144 } 145 ); 146 147 mController.updateView(new DocumentInfo()); 148 mDebugTestDouble.assertCalled(); 149 } 150 151 /** 152 * Tests show in provider feature of the controller. This test loads a documentInfo from a uri. 153 * calls showInProvider on the documentInfo and verifies that the TestProvider activity has 154 * started. 155 * 156 * @see InspectorProvider 157 * @see TestProviderActivity 158 * 159 * @throws Exception 160 */ 161 @Test 162 public void testShowInProvider() throws Exception { 163 164 Uri uri = DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, 165 OPEN_IN_PROVIDER_DOC); 166 mController.showInProvider(uri); 167 168 assertNotNull(mContext.started); 169 assertEquals("com.android.documentsui", mContext.started.getPackage()); 170 assertEquals(uri, mContext.started.getData()); 171 } 172 /** 173 * Test that valid input will update the view properly. The test uses a test double for header 174 * and details view and asserts that .accept was called on both. 175 * 176 * @throws Exception 177 */ 178 @Test 179 public void testUpdateViewWithValidInput() throws Exception { 180 mController.updateView(new DocumentInfo()); 181 mHeaderTestDouble.assertCalled(); 182 mDetailsTestDouble.assertCalled(); 183 } 184 185 /** 186 * Test that when a document has the FLAG_SUPPORTS_SETTINGS set the showInProvider view will 187 * be visible. 188 * 189 * @throws Exception 190 */ 191 @Test 192 public void testShowInProvider_visible() throws Exception { 193 DocumentInfo doc = new DocumentInfo(); 194 doc.derivedUri = 195 DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, OPEN_IN_PROVIDER_DOC); 196 197 doc.flags = doc.flags | Document.FLAG_SUPPORTS_SETTINGS; 198 mController.updateView(doc); 199 assertTrue(mShowInProvider.becameVisible); 200 } 201 202 /** 203 * Test that when a document does not have the FLAG_SUPPORTS_SETTINGS set the view will be 204 * invisible. 205 * @throws Exception 206 */ 207 @Test 208 public void testShowInProvider_invisible() throws Exception { 209 DocumentInfo doc = new DocumentInfo(); 210 doc.derivedUri = 211 DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, OPEN_IN_PROVIDER_DOC); 212 213 mController.updateView(doc); 214 assertFalse(mShowInProvider.becameVisible); 215 } 216 217 /** 218 * Test that the action clear app defaults is visible when conditions are met. 219 * @throws Exception 220 */ 221 @Test 222 public void testAppDefaults_visible() throws Exception { 223 224 mPm.queryIntentProvidersResults = new ArrayList<>(); 225 mPm.queryIntentProvidersResults.add(new TestResolveInfo()); 226 mPm.queryIntentProvidersResults.add(new TestResolveInfo()); 227 DocumentInfo doc = new DocumentInfo(); 228 doc.derivedUri = 229 DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, OPEN_IN_PROVIDER_DOC); 230 231 mController.updateView(doc); 232 assertTrue(mDefaultsTestDouble.becameVisible); 233 } 234 235 /** 236 * Test that action clear app defaults is invisible when conditions have not been met. 237 * @throws Exception 238 */ 239 @Test 240 public void testAppDefaults_invisible() throws Exception { 241 mPm.queryIntentProvidersResults = new ArrayList<>(); 242 mPm.queryIntentProvidersResults.add(new TestResolveInfo()); 243 DocumentInfo doc = new DocumentInfo(); 244 doc.derivedUri = 245 DocumentsContract.buildDocumentUri(InspectorProvider.AUTHORITY, OPEN_IN_PROVIDER_DOC); 246 247 mController.updateView(doc); 248 assertFalse(mDefaultsTestDouble.becameVisible); 249 } 250 251 /** 252 * Test that update view will handle a null value properly. It uses a runnable to verify that 253 * the static method Snackbars.showInspectorError(Activity activity) is called. 254 * 255 * @throws Exception 256 */ 257 @Test 258 public void testUpdateViewWithNullValue() throws Exception { 259 mController.updateView(null); 260 assertTrue(mShowSnackbarsCalled); 261 mHeaderTestDouble.assertNotCalled(); 262 mDetailsTestDouble.assertNotCalled(); 263 } 264 265 private static class TestActivity extends Activity { 266 267 private @Nullable Intent started; 268 269 @Override 270 public void startActivity(Intent intent) { 271 started = intent; 272 } 273 } 274 275 private static class TestAction implements ActionDisplay { 276 277 private TestAction() { 278 becameVisible = false; 279 } 280 281 private boolean becameVisible; 282 283 @Override 284 public void init(Action action, OnClickListener listener) { 285 286 } 287 288 @Override 289 public void setVisible(boolean visible) { 290 becameVisible = visible; 291 } 292 293 @Override 294 public void setActionHeader(String header) { 295 296 } 297 298 @Override 299 public void setAppIcon(Drawable icon) { 300 301 } 302 303 @Override 304 public void setAppName(String name) { 305 306 } 307 308 @Override 309 public void showAction(boolean visible) { 310 311 } 312 } 313 314 private static class TestDetails implements DetailsDisplay { 315 316 private boolean mCalled = false; 317 318 @Override 319 public void accept(DocumentInfo info) { 320 mCalled = true; 321 } 322 323 @Override 324 public void setChildrenCount(int count) { 325 } 326 327 public void assertCalled() { 328 Assert.assertTrue(mCalled); 329 } 330 331 public void assertNotCalled() { 332 Assert.assertFalse(mCalled); 333 } 334 } 335 }