1 /* 2 * Copyright (C) 2016 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 com.android.internal.app; 18 19 import static android.app.Activity.RESULT_OK; 20 21 import static androidx.test.espresso.Espresso.onView; 22 import static androidx.test.espresso.action.ViewActions.click; 23 import static androidx.test.espresso.action.ViewActions.swipeUp; 24 import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist; 25 import static androidx.test.espresso.assertion.ViewAssertions.matches; 26 import static androidx.test.espresso.matcher.ViewMatchers.hasSibling; 27 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; 28 import static androidx.test.espresso.matcher.ViewMatchers.withId; 29 import static androidx.test.espresso.matcher.ViewMatchers.withText; 30 31 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_CHOOSER_TARGET; 32 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_DEFAULT; 33 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE; 34 import static com.android.internal.app.ChooserActivity.TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER; 35 import static com.android.internal.app.ChooserListAdapter.CALLER_TARGET_SCORE_BOOST; 36 import static com.android.internal.app.ChooserListAdapter.SHORTCUT_TARGET_SCORE_BOOST; 37 import static com.android.internal.app.MatcherUtils.first; 38 39 import static junit.framework.Assert.assertFalse; 40 import static junit.framework.Assert.assertNull; 41 import static junit.framework.Assert.assertTrue; 42 43 import static org.hamcrest.CoreMatchers.allOf; 44 import static org.hamcrest.CoreMatchers.is; 45 import static org.hamcrest.CoreMatchers.not; 46 import static org.hamcrest.CoreMatchers.notNullValue; 47 import static org.hamcrest.MatcherAssert.assertThat; 48 import static org.hamcrest.Matchers.greaterThan; 49 import static org.junit.Assert.assertEquals; 50 import static org.mockito.ArgumentMatchers.any; 51 import static org.mockito.ArgumentMatchers.anyInt; 52 import static org.mockito.ArgumentMatchers.eq; 53 import static org.mockito.Mockito.atLeastOnce; 54 import static org.mockito.Mockito.mock; 55 import static org.mockito.Mockito.times; 56 import static org.mockito.Mockito.verify; 57 import static org.mockito.Mockito.when; 58 59 import android.app.usage.UsageStatsManager; 60 import android.content.ClipData; 61 import android.content.ClipDescription; 62 import android.content.ClipboardManager; 63 import android.content.ComponentName; 64 import android.content.Context; 65 import android.content.Intent; 66 import android.content.pm.ActivityInfo; 67 import android.content.pm.ApplicationInfo; 68 import android.content.pm.PackageManager; 69 import android.content.pm.ResolveInfo; 70 import android.content.pm.ShortcutInfo; 71 import android.content.pm.ShortcutManager.ShareShortcutInfo; 72 import android.content.res.Configuration; 73 import android.database.Cursor; 74 import android.graphics.Bitmap; 75 import android.graphics.Canvas; 76 import android.graphics.Color; 77 import android.graphics.Paint; 78 import android.graphics.drawable.Icon; 79 import android.metrics.LogMaker; 80 import android.net.Uri; 81 import android.os.UserHandle; 82 import android.provider.DeviceConfig; 83 import android.service.chooser.ChooserTarget; 84 import android.util.Pair; 85 import android.view.View; 86 87 import androidx.annotation.CallSuper; 88 import androidx.test.espresso.matcher.BoundedDiagnosingMatcher; 89 import androidx.test.platform.app.InstrumentationRegistry; 90 import androidx.test.rule.ActivityTestRule; 91 92 import com.android.internal.R; 93 import com.android.internal.app.ChooserActivity.ServiceResultInfo; 94 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo; 95 import com.android.internal.app.chooser.DisplayResolveInfo; 96 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; 97 import com.android.internal.logging.MetricsLogger; 98 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 99 import com.android.internal.util.FrameworkStatsLog; 100 import com.android.internal.widget.GridLayoutManager; 101 import com.android.internal.widget.RecyclerView; 102 103 import org.hamcrest.Description; 104 import org.hamcrest.Matcher; 105 import org.hamcrest.Matchers; 106 import org.junit.Before; 107 import org.junit.Ignore; 108 import org.junit.Rule; 109 import org.junit.Test; 110 import org.junit.runner.RunWith; 111 import org.junit.runners.Parameterized; 112 import org.mockito.ArgumentCaptor; 113 import org.mockito.Mockito; 114 115 import java.util.ArrayList; 116 import java.util.Arrays; 117 import java.util.Collection; 118 import java.util.HashMap; 119 import java.util.List; 120 import java.util.Map; 121 import java.util.function.Function; 122 123 /** 124 * Instrumentation tests for chooser activities that derive from the system 125 * {@code com.android.internal.ChooserActivity}. This class is used directly to test the system 126 * implementation, but clients can inherit from this test to apply the same suite of chooser tests 127 * to their own ChooserActivity implementations. Clients should override 128 * #getConcreteIntentForLaunch() to configure an intent that will launch their concrete 129 * ChooserActivity subtype. Tests will assume that this subtype implements the IChooserWrapper 130 * interface, which is only appropriate for testing. Clients will typically create their own 131 * "ChooserWrapperActivity" by copy-and-pasting the system implementation, parenting to their own 132 * ChooserActivity subclass instead of directly to the system implementation. Code comments in this 133 * file provide direction for developers creating derived test suites, and eventually for removing 134 * the extra complexity once we no longer need to support parallel ChooserActivity implementations. 135 */ 136 @RunWith(Parameterized.class) 137 public class ChooserActivityTest { 138 139 /* -------- 140 * Subclasses should copy the following section verbatim (or alternatively could specify some 141 * additional @Parameterized.Parameters, as long as the correct parameters are used to 142 * initialize the ChooserActivityTest). The subclasses should also be @RunWith the 143 * `Parameterized` runner. 144 * -------- 145 */ 146 147 private static final Function<PackageManager, PackageManager> DEFAULT_PM = pm -> pm; 148 private static final Function<PackageManager, PackageManager> NO_APP_PREDICTION_SERVICE_PM = 149 pm -> { 150 PackageManager mock = Mockito.spy(pm); 151 when(mock.getAppPredictionServicePackageName()).thenReturn(null); 152 return mock; 153 }; 154 155 @Parameterized.Parameters packageManagers()156 public static Collection packageManagers() { 157 return Arrays.asList(new Object[][] { 158 {0, "Default PackageManager", DEFAULT_PM}, 159 {1, "No App Prediction Service", NO_APP_PREDICTION_SERVICE_PM} 160 }); 161 } 162 163 /* -------- 164 * Subclasses can override the following methods to customize test behavior. 165 * -------- 166 */ 167 168 /** 169 * Perform any necessary per-test initialization steps (subclasses may add additional steps 170 * before and/or after calling up to the superclass implementation). 171 */ 172 @CallSuper setup()173 protected void setup() { 174 cleanOverrideData(); 175 } 176 177 /** 178 * Given an intent that was constructed in a test, perform any additional configuration to 179 * specify the appropriate concrete ChooserActivity subclass. The activity launched by this 180 * intent must descend from android.internal.app.ChooserActivity (for our ActivityTestRule), and 181 * must also implement the android.internal.app.IChooserWrapper interface (since test code will 182 * assume the ability to make unsafe downcasts). 183 */ getConcreteIntentForLaunch(Intent clientIntent)184 protected Intent getConcreteIntentForLaunch(Intent clientIntent) { 185 clientIntent.setClass( 186 InstrumentationRegistry.getInstrumentation().getTargetContext(), 187 com.android.internal.app.ChooserWrapperActivity.class); 188 return clientIntent; 189 } 190 191 /** 192 * Whether {@code #testIsAppPredictionServiceAvailable} should verify the behavior after 193 * changing the availability conditions at runtime. In the unbundled chooser, the availability 194 * is cached at start and will never be re-evaluated. 195 * TODO: remove when we no longer want to test the system's on-the-fly evaluation. 196 */ shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime()197 protected boolean shouldTestTogglingAppPredictionServiceAvailabilityAtRuntime() { 198 return false; 199 } 200 201 /* -------- 202 * The code in this section is unorthodox and can be simplified/reverted when we no longer need 203 * to support the parallel chooser implementations. 204 * -------- 205 */ 206 207 // Shared test code references the activity under test as ChooserActivity, the common ancestor 208 // of any (inheritance-based) chooser implementation. For testing purposes, that activity will 209 // usually be cast to IChooserWrapper to expose instrumentation. 210 @Rule 211 public ActivityTestRule<ChooserActivity> mActivityRule = 212 new ActivityTestRule<>(ChooserActivity.class, false, false) { 213 @Override 214 public ChooserActivity launchActivity(Intent clientIntent) { 215 return super.launchActivity(getConcreteIntentForLaunch(clientIntent)); 216 } 217 }; 218 219 @Before doPolymorphicSetup()220 public final void doPolymorphicSetup() { 221 // The base class needs a @Before-annotated setup for when it runs against the system 222 // chooser, while subclasses need to be able to specify their own setup behavior. Notably 223 // the unbundled chooser, running in user-space, needs to take additional steps before it 224 // can run #cleanOverrideData() (which writes to DeviceConfig). 225 setup(); 226 } 227 228 /* -------- 229 * Subclasses can ignore the remaining code and inherit the full suite of tests. 230 * -------- 231 */ 232 233 private static final String TEST_MIME_TYPE = "application/TestType"; 234 235 private static final int CONTENT_PREVIEW_IMAGE = 1; 236 private static final int CONTENT_PREVIEW_FILE = 2; 237 private static final int CONTENT_PREVIEW_TEXT = 3; 238 private Function<PackageManager, PackageManager> mPackageManagerOverride; 239 private int mTestNum; 240 241 ChooserActivityTest( int testNum, String testName, Function<PackageManager, PackageManager> packageManagerOverride)242 public ChooserActivityTest( 243 int testNum, 244 String testName, 245 Function<PackageManager, PackageManager> packageManagerOverride) { 246 mPackageManagerOverride = packageManagerOverride; 247 mTestNum = testNum; 248 } 249 cleanOverrideData()250 public void cleanOverrideData() { 251 ChooserActivityOverrideData.getInstance().reset(); 252 ChooserActivityOverrideData.getInstance().createPackageManager = mPackageManagerOverride; 253 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 254 SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI, 255 Boolean.toString(true), 256 true /* makeDefault*/); 257 } 258 259 @Test customTitle()260 public void customTitle() throws InterruptedException { 261 Intent viewIntent = createViewTextIntent(); 262 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 263 264 when( 265 ChooserActivityOverrideData 266 .getInstance() 267 .resolverListController 268 .getResolversForIntent( 269 Mockito.anyBoolean(), 270 Mockito.anyBoolean(), 271 Mockito.anyBoolean(), 272 Mockito.isA(List.class))) 273 .thenReturn(resolvedComponentInfos); 274 final IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity( 275 Intent.createChooser(viewIntent, "chooser test")); 276 277 waitForIdle(); 278 assertThat(activity.getAdapter().getCount(), is(2)); 279 assertThat(activity.getAdapter().getServiceTargetCount(), is(0)); 280 onView(withIdFromRuntimeResource("title")).check(matches(withText("chooser test"))); 281 } 282 283 @Test customTitleIgnoredForSendIntents()284 public void customTitleIgnoredForSendIntents() throws InterruptedException { 285 Intent sendIntent = createSendTextIntent(); 286 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 287 288 when( 289 ChooserActivityOverrideData 290 .getInstance() 291 .resolverListController 292 .getResolversForIntent( 293 Mockito.anyBoolean(), 294 Mockito.anyBoolean(), 295 Mockito.anyBoolean(), 296 Mockito.isA(List.class))) 297 .thenReturn(resolvedComponentInfos); 298 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "chooser test")); 299 waitForIdle(); 300 onView(withIdFromRuntimeResource("title")) 301 .check(matches(withTextFromRuntimeResource("whichSendApplication"))); 302 } 303 304 @Test emptyTitle()305 public void emptyTitle() throws InterruptedException { 306 Intent sendIntent = createSendTextIntent(); 307 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 308 309 when( 310 ChooserActivityOverrideData 311 .getInstance() 312 .resolverListController 313 .getResolversForIntent( 314 Mockito.anyBoolean(), 315 Mockito.anyBoolean(), 316 Mockito.anyBoolean(), 317 Mockito.isA(List.class))) 318 .thenReturn(resolvedComponentInfos); 319 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 320 waitForIdle(); 321 onView(withIdFromRuntimeResource("title")) 322 .check(matches(withTextFromRuntimeResource("whichSendApplication"))); 323 } 324 325 @Test emptyPreviewTitleAndThumbnail()326 public void emptyPreviewTitleAndThumbnail() throws InterruptedException { 327 Intent sendIntent = createSendTextIntentWithPreview(null, null); 328 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 329 330 when( 331 ChooserActivityOverrideData 332 .getInstance() 333 .resolverListController 334 .getResolversForIntent( 335 Mockito.anyBoolean(), 336 Mockito.anyBoolean(), 337 Mockito.anyBoolean(), 338 Mockito.isA(List.class))) 339 .thenReturn(resolvedComponentInfos); 340 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 341 waitForIdle(); 342 onView(withIdFromRuntimeResource("content_preview_title")) 343 .check(matches(not(isDisplayed()))); 344 onView(withIdFromRuntimeResource("content_preview_thumbnail")) 345 .check(matches(not(isDisplayed()))); 346 } 347 348 @Test visiblePreviewTitleWithoutThumbnail()349 public void visiblePreviewTitleWithoutThumbnail() throws InterruptedException { 350 String previewTitle = "My Content Preview Title"; 351 Intent sendIntent = createSendTextIntentWithPreview(previewTitle, null); 352 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 353 354 when( 355 ChooserActivityOverrideData 356 .getInstance() 357 .resolverListController 358 .getResolversForIntent( 359 Mockito.anyBoolean(), 360 Mockito.anyBoolean(), 361 Mockito.anyBoolean(), 362 Mockito.isA(List.class))) 363 .thenReturn(resolvedComponentInfos); 364 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 365 waitForIdle(); 366 onView(withIdFromRuntimeResource("content_preview_title")) 367 .check(matches(isDisplayed())); 368 onView(withIdFromRuntimeResource("content_preview_title")) 369 .check(matches(withText(previewTitle))); 370 onView(withIdFromRuntimeResource("content_preview_thumbnail")) 371 .check(matches(not(isDisplayed()))); 372 } 373 374 @Test visiblePreviewTitleWithInvalidThumbnail()375 public void visiblePreviewTitleWithInvalidThumbnail() throws InterruptedException { 376 String previewTitle = "My Content Preview Title"; 377 Intent sendIntent = createSendTextIntentWithPreview(previewTitle, 378 Uri.parse("tel:(+49)12345789")); 379 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 380 381 when( 382 ChooserActivityOverrideData 383 .getInstance() 384 .resolverListController 385 .getResolversForIntent( 386 Mockito.anyBoolean(), 387 Mockito.anyBoolean(), 388 Mockito.anyBoolean(), 389 Mockito.isA(List.class))) 390 .thenReturn(resolvedComponentInfos); 391 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 392 waitForIdle(); 393 onView(withIdFromRuntimeResource("content_preview_title")).check(matches(isDisplayed())); 394 onView(withIdFromRuntimeResource("content_preview_thumbnail")) 395 .check(matches(not(isDisplayed()))); 396 } 397 398 @Test visiblePreviewTitleAndThumbnail()399 public void visiblePreviewTitleAndThumbnail() throws InterruptedException { 400 String previewTitle = "My Content Preview Title"; 401 Intent sendIntent = createSendTextIntentWithPreview(previewTitle, 402 Uri.parse("android.resource://com.android.frameworks.coretests/" 403 + com.android.frameworks.coretests.R.drawable.test320x240)); 404 ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap(); 405 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 406 407 when( 408 ChooserActivityOverrideData 409 .getInstance() 410 .resolverListController 411 .getResolversForIntent( 412 Mockito.anyBoolean(), 413 Mockito.anyBoolean(), 414 Mockito.anyBoolean(), 415 Mockito.isA(List.class))) 416 .thenReturn(resolvedComponentInfos); 417 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 418 waitForIdle(); 419 onView(withIdFromRuntimeResource("content_preview_title")).check(matches(isDisplayed())); 420 onView(withIdFromRuntimeResource("content_preview_thumbnail")) 421 .check(matches(isDisplayed())); 422 } 423 424 @Test @Ignore twoOptionsAndUserSelectsOne()425 public void twoOptionsAndUserSelectsOne() throws InterruptedException { 426 Intent sendIntent = createSendTextIntent(); 427 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 428 429 when( 430 ChooserActivityOverrideData 431 .getInstance() 432 .resolverListController 433 .getResolversForIntent( 434 Mockito.anyBoolean(), 435 Mockito.anyBoolean(), 436 Mockito.anyBoolean(), 437 Mockito.isA(List.class))) 438 .thenReturn(resolvedComponentInfos); 439 440 final IChooserWrapper activity = (IChooserWrapper) 441 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 442 waitForIdle(); 443 444 assertThat(activity.getAdapter().getCount(), is(2)); 445 onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist()); 446 447 ResolveInfo[] chosen = new ResolveInfo[1]; 448 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 449 chosen[0] = targetInfo.getResolveInfo(); 450 return true; 451 }; 452 453 ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0); 454 onView(withText(toChoose.activityInfo.name)) 455 .perform(click()); 456 waitForIdle(); 457 assertThat(chosen[0], is(toChoose)); 458 } 459 460 @Test @Ignore fourOptionsStackedIntoOneTarget()461 public void fourOptionsStackedIntoOneTarget() throws InterruptedException { 462 Intent sendIntent = createSendTextIntent(); 463 464 // create just enough targets to ensure the a-z list should be shown 465 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1); 466 467 // next create 4 targets in a single app that should be stacked into a single target 468 String packageName = "xxx.yyy"; 469 String appName = "aaa"; 470 ComponentName cn = new ComponentName(packageName, appName); 471 Intent intent = new Intent("fakeIntent"); 472 List<ResolvedComponentInfo> infosToStack = new ArrayList<>(); 473 for (int i = 0; i < 4; i++) { 474 ResolveInfo resolveInfo = ResolverDataProvider.createResolveInfo(i, 475 UserHandle.USER_CURRENT); 476 resolveInfo.activityInfo.applicationInfo.name = appName; 477 resolveInfo.activityInfo.applicationInfo.packageName = packageName; 478 resolveInfo.activityInfo.packageName = packageName; 479 resolveInfo.activityInfo.name = "ccc" + i; 480 infosToStack.add(new ResolvedComponentInfo(cn, intent, resolveInfo)); 481 } 482 resolvedComponentInfos.addAll(infosToStack); 483 484 when( 485 ChooserActivityOverrideData 486 .getInstance() 487 .resolverListController 488 .getResolversForIntent( 489 Mockito.anyBoolean(), 490 Mockito.anyBoolean(), 491 Mockito.anyBoolean(), 492 Mockito.isA(List.class))) 493 .thenReturn(resolvedComponentInfos); 494 495 final IChooserWrapper activity = (IChooserWrapper) 496 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 497 waitForIdle(); 498 499 // expect 1 unique targets + 1 group + 4 ranked app targets 500 assertThat(activity.getAdapter().getCount(), is(6)); 501 502 ResolveInfo[] chosen = new ResolveInfo[1]; 503 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 504 chosen[0] = targetInfo.getResolveInfo(); 505 return true; 506 }; 507 508 onView(allOf(withText(appName), hasSibling(withText("")))).perform(click()); 509 waitForIdle(); 510 511 // clicking will launch a dialog to choose the activity within the app 512 onView(withText(appName)).check(matches(isDisplayed())); 513 int i = 0; 514 for (ResolvedComponentInfo rci: infosToStack) { 515 onView(withText("ccc" + i)).check(matches(isDisplayed())); 516 ++i; 517 } 518 } 519 520 @Test @Ignore updateChooserCountsAndModelAfterUserSelection()521 public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException { 522 Intent sendIntent = createSendTextIntent(); 523 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 524 525 when( 526 ChooserActivityOverrideData 527 .getInstance() 528 .resolverListController 529 .getResolversForIntent( 530 Mockito.anyBoolean(), 531 Mockito.anyBoolean(), 532 Mockito.anyBoolean(), 533 Mockito.isA(List.class))) 534 .thenReturn(resolvedComponentInfos); 535 536 final IChooserWrapper activity = (IChooserWrapper) 537 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 538 waitForIdle(); 539 UsageStatsManager usm = activity.getUsageStatsManager(); 540 verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1)) 541 .topK(any(List.class), anyInt()); 542 assertThat(activity.getIsSelected(), is(false)); 543 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 544 return true; 545 }; 546 ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0); 547 onView(withText(toChoose.activityInfo.name)) 548 .perform(click()); 549 waitForIdle(); 550 verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1)) 551 .updateChooserCounts(Mockito.anyString(), anyInt(), Mockito.anyString()); 552 verify(ChooserActivityOverrideData.getInstance().resolverListController, times(1)) 553 .updateModel(toChoose.activityInfo.getComponentName()); 554 assertThat(activity.getIsSelected(), is(true)); 555 } 556 557 @Ignore // b/148158199 558 @Test noResultsFromPackageManager()559 public void noResultsFromPackageManager() { 560 when( 561 ChooserActivityOverrideData 562 .getInstance() 563 .resolverListController 564 .getResolversForIntent( 565 Mockito.anyBoolean(), 566 Mockito.anyBoolean(), 567 Mockito.anyBoolean(), 568 Mockito.isA(List.class))) 569 .thenReturn(null); 570 Intent sendIntent = createSendTextIntent(); 571 final ChooserActivity activity = 572 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 573 final IChooserWrapper wrapper = (IChooserWrapper) activity; 574 575 waitForIdle(); 576 assertThat(activity.isFinishing(), is(false)); 577 578 onView(withIdFromRuntimeResource("empty")).check(matches(isDisplayed())); 579 onView(withIdFromRuntimeResource("profile_pager")).check(matches(not(isDisplayed()))); 580 InstrumentationRegistry.getInstrumentation().runOnMainSync( 581 () -> wrapper.getAdapter().handlePackagesChanged() 582 ); 583 // backward compatibility. looks like we finish when data is empty after package change 584 assertThat(activity.isFinishing(), is(true)); 585 } 586 587 @Test autoLaunchSingleResult()588 public void autoLaunchSingleResult() throws InterruptedException { 589 ResolveInfo[] chosen = new ResolveInfo[1]; 590 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 591 chosen[0] = targetInfo.getResolveInfo(); 592 return true; 593 }; 594 595 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(1); 596 when( 597 ChooserActivityOverrideData 598 .getInstance() 599 .resolverListController 600 .getResolversForIntent( 601 Mockito.anyBoolean(), 602 Mockito.anyBoolean(), 603 Mockito.anyBoolean(), 604 Mockito.isA(List.class))) 605 .thenReturn(resolvedComponentInfos); 606 607 Intent sendIntent = createSendTextIntent(); 608 final ChooserActivity activity = 609 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 610 waitForIdle(); 611 612 assertThat(chosen[0], is(resolvedComponentInfos.get(0).getResolveInfoAt(0))); 613 assertThat(activity.isFinishing(), is(true)); 614 } 615 616 @Test @Ignore hasOtherProfileOneOption()617 public void hasOtherProfileOneOption() throws Exception { 618 // enable the work tab feature flag 619 ResolverActivity.ENABLE_TABBED_VIEW = true; 620 List<ResolvedComponentInfo> personalResolvedComponentInfos = 621 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10); 622 List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest(4); 623 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 624 markWorkProfileUserAvailable(); 625 626 ResolveInfo toChoose = personalResolvedComponentInfos.get(1).getResolveInfoAt(0); 627 Intent sendIntent = createSendTextIntent(); 628 final IChooserWrapper activity = (IChooserWrapper) 629 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 630 waitForIdle(); 631 632 // The other entry is filtered to the other profile slot 633 assertThat(activity.getAdapter().getCount(), is(1)); 634 635 ResolveInfo[] chosen = new ResolveInfo[1]; 636 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 637 chosen[0] = targetInfo.getResolveInfo(); 638 return true; 639 }; 640 641 // Make a stable copy of the components as the original list may be modified 642 List<ResolvedComponentInfo> stableCopy = 643 createResolvedComponentsForTestWithOtherProfile(2, /* userId= */ 10); 644 waitForIdle(); 645 Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs); 646 647 onView(first(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name))) 648 .perform(click()); 649 waitForIdle(); 650 assertThat(chosen[0], is(toChoose)); 651 } 652 653 @Test @Ignore hasOtherProfileTwoOptionsAndUserSelectsOne()654 public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception { 655 // enable the work tab feature flag 656 ResolverActivity.ENABLE_TABBED_VIEW = true; 657 658 Intent sendIntent = createSendTextIntent(); 659 List<ResolvedComponentInfo> resolvedComponentInfos = 660 createResolvedComponentsForTestWithOtherProfile(3); 661 ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0); 662 663 when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent( 664 Mockito.anyBoolean(), 665 Mockito.anyBoolean(), 666 Mockito.anyBoolean(), 667 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); 668 when(ChooserActivityOverrideData.getInstance().resolverListController.getLastChosen()) 669 .thenReturn(resolvedComponentInfos.get(0).getResolveInfoAt(0)); 670 671 final IChooserWrapper activity = (IChooserWrapper) 672 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 673 waitForIdle(); 674 675 // The other entry is filtered to the other profile slot 676 assertThat(activity.getAdapter().getCount(), is(2)); 677 678 ResolveInfo[] chosen = new ResolveInfo[1]; 679 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 680 chosen[0] = targetInfo.getResolveInfo(); 681 return true; 682 }; 683 684 // Make a stable copy of the components as the original list may be modified 685 List<ResolvedComponentInfo> stableCopy = 686 createResolvedComponentsForTestWithOtherProfile(3); 687 onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name)) 688 .perform(click()); 689 waitForIdle(); 690 assertThat(chosen[0], is(toChoose)); 691 } 692 693 @Test @Ignore hasLastChosenActivityAndOtherProfile()694 public void hasLastChosenActivityAndOtherProfile() throws Exception { 695 // enable the work tab feature flag 696 ResolverActivity.ENABLE_TABBED_VIEW = true; 697 698 Intent sendIntent = createSendTextIntent(); 699 List<ResolvedComponentInfo> resolvedComponentInfos = 700 createResolvedComponentsForTestWithOtherProfile(3); 701 ResolveInfo toChoose = resolvedComponentInfos.get(1).getResolveInfoAt(0); 702 703 when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent( 704 Mockito.anyBoolean(), 705 Mockito.anyBoolean(), 706 Mockito.anyBoolean(), 707 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); 708 709 final IChooserWrapper activity = (IChooserWrapper) 710 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 711 waitForIdle(); 712 713 // The other entry is filtered to the last used slot 714 assertThat(activity.getAdapter().getCount(), is(2)); 715 716 ResolveInfo[] chosen = new ResolveInfo[1]; 717 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 718 chosen[0] = targetInfo.getResolveInfo(); 719 return true; 720 }; 721 722 // Make a stable copy of the components as the original list may be modified 723 List<ResolvedComponentInfo> stableCopy = 724 createResolvedComponentsForTestWithOtherProfile(3); 725 onView(withText(stableCopy.get(1).getResolveInfoAt(0).activityInfo.name)) 726 .perform(click()); 727 waitForIdle(); 728 assertThat(chosen[0], is(toChoose)); 729 } 730 731 @Test copyTextToClipboard()732 public void copyTextToClipboard() throws Exception { 733 Intent sendIntent = createSendTextIntent(); 734 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 735 736 when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent( 737 Mockito.anyBoolean(), 738 Mockito.anyBoolean(), 739 Mockito.anyBoolean(), 740 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); 741 742 final ChooserActivity activity = 743 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 744 waitForIdle(); 745 746 onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed())); 747 onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click()); 748 ClipboardManager clipboard = (ClipboardManager) activity.getSystemService( 749 Context.CLIPBOARD_SERVICE); 750 ClipData clipData = clipboard.getPrimaryClip(); 751 assertThat("testing intent sending", is(clipData.getItemAt(0).getText())); 752 753 ClipDescription clipDescription = clipData.getDescription(); 754 assertThat("text/plain", is(clipDescription.getMimeType(0))); 755 756 assertEquals(mActivityRule.getActivityResult().getResultCode(), RESULT_OK); 757 } 758 759 @Test copyTextToClipboardLogging()760 public void copyTextToClipboardLogging() throws Exception { 761 Intent sendIntent = createSendTextIntent(); 762 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 763 764 when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent( 765 Mockito.anyBoolean(), 766 Mockito.anyBoolean(), 767 Mockito.anyBoolean(), 768 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); 769 770 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 771 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 772 773 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 774 waitForIdle(); 775 776 onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed())); 777 onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click()); 778 779 verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture()); 780 781 // The last captured event is the selection of the target. 782 assertThat(logMakerCaptor.getValue().getCategory(), 783 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SYSTEM_TARGET)); 784 assertThat(logMakerCaptor.getValue().getSubtype(), is(1)); 785 } 786 787 788 @Test 789 @Ignore testNearbyShareLogging()790 public void testNearbyShareLogging() throws Exception { 791 Intent sendIntent = createSendTextIntent(); 792 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 793 794 when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent( 795 Mockito.anyBoolean(), 796 Mockito.anyBoolean(), 797 Mockito.anyBoolean(), 798 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); 799 800 final IChooserWrapper activity = (IChooserWrapper) 801 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 802 waitForIdle(); 803 804 onView(withIdFromRuntimeResource("chooser_nearby_button")).check(matches(isDisplayed())); 805 onView(withIdFromRuntimeResource("chooser_nearby_button")).perform(click()); 806 807 ChooserActivityLoggerFake logger = 808 (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); 809 810 // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events. 811 logger.removeCallsForUiEventsOfType( 812 ChooserActivityLogger.SharesheetStandardEvent 813 .SHARESHEET_DIRECT_LOAD_COMPLETE.getId()); 814 815 // SHARESHEET_TRIGGERED: 816 assertThat(logger.event(0).getId(), 817 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); 818 819 // SHARESHEET_STARTED: 820 assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); 821 assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); 822 assertThat(logger.get(1).mimeType, is("text/plain")); 823 assertThat(logger.get(1).packageName, is( 824 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); 825 assertThat(logger.get(1).appProvidedApp, is(0)); 826 assertThat(logger.get(1).appProvidedDirect, is(0)); 827 assertThat(logger.get(1).isWorkprofile, is(false)); 828 assertThat(logger.get(1).previewType, is(3)); 829 830 // SHARESHEET_APP_LOAD_COMPLETE: 831 assertThat(logger.event(2).getId(), 832 is(ChooserActivityLogger 833 .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); 834 835 // Next are just artifacts of test set-up: 836 assertThat(logger.event(3).getId(), 837 is(ChooserActivityLogger 838 .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId())); 839 assertThat(logger.event(4).getId(), 840 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId())); 841 842 // SHARESHEET_NEARBY_TARGET_SELECTED: 843 assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); 844 assertThat(logger.get(5).targetType, 845 is(ChooserActivityLogger 846 .SharesheetTargetSelectedEvent.SHARESHEET_NEARBY_TARGET_SELECTED.getId())); 847 848 // No more events. 849 assertThat(logger.numCalls(), is(6)); 850 } 851 852 853 854 @Test @Ignore testEditImageLogs()855 public void testEditImageLogs() throws Exception { 856 Intent sendIntent = createSendImageIntent( 857 Uri.parse("android.resource://com.android.frameworks.coretests/" 858 + com.android.frameworks.coretests.R.drawable.test320x240)); 859 860 ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap(); 861 ChooserActivityOverrideData.getInstance().isImageType = true; 862 863 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 864 865 when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent( 866 Mockito.anyBoolean(), 867 Mockito.anyBoolean(), 868 Mockito.anyBoolean(), 869 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); 870 871 final IChooserWrapper activity = (IChooserWrapper) 872 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 873 waitForIdle(); 874 875 onView(withIdFromRuntimeResource("chooser_edit_button")).check(matches(isDisplayed())); 876 onView(withIdFromRuntimeResource("chooser_edit_button")).perform(click()); 877 878 ChooserActivityLoggerFake logger = 879 (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); 880 881 // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events. 882 logger.removeCallsForUiEventsOfType( 883 ChooserActivityLogger.SharesheetStandardEvent 884 .SHARESHEET_DIRECT_LOAD_COMPLETE.getId()); 885 886 // SHARESHEET_TRIGGERED: 887 assertThat(logger.event(0).getId(), 888 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); 889 890 // SHARESHEET_STARTED: 891 assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); 892 assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); 893 assertThat(logger.get(1).mimeType, is("image/png")); 894 assertThat(logger.get(1).packageName, is( 895 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); 896 assertThat(logger.get(1).appProvidedApp, is(0)); 897 assertThat(logger.get(1).appProvidedDirect, is(0)); 898 assertThat(logger.get(1).isWorkprofile, is(false)); 899 assertThat(logger.get(1).previewType, is(1)); 900 901 // SHARESHEET_APP_LOAD_COMPLETE: 902 assertThat(logger.event(2).getId(), 903 is(ChooserActivityLogger 904 .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); 905 906 // Next are just artifacts of test set-up: 907 assertThat(logger.event(3).getId(), 908 is(ChooserActivityLogger 909 .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId())); 910 assertThat(logger.event(4).getId(), 911 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId())); 912 913 // SHARESHEET_EDIT_TARGET_SELECTED: 914 assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); 915 assertThat(logger.get(5).targetType, 916 is(ChooserActivityLogger 917 .SharesheetTargetSelectedEvent.SHARESHEET_EDIT_TARGET_SELECTED.getId())); 918 919 // No more events. 920 assertThat(logger.numCalls(), is(6)); 921 } 922 923 924 @Test oneVisibleImagePreview()925 public void oneVisibleImagePreview() throws InterruptedException { 926 Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/" 927 + com.android.frameworks.coretests.R.drawable.test320x240); 928 929 ArrayList<Uri> uris = new ArrayList<>(); 930 uris.add(uri); 931 932 Intent sendIntent = createSendUriIntentWithPreview(uris); 933 ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap(); 934 ChooserActivityOverrideData.getInstance().isImageType = true; 935 936 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 937 938 when( 939 ChooserActivityOverrideData 940 .getInstance() 941 .resolverListController 942 .getResolversForIntent( 943 Mockito.anyBoolean(), 944 Mockito.anyBoolean(), 945 Mockito.anyBoolean(), 946 Mockito.isA(List.class))) 947 .thenReturn(resolvedComponentInfos); 948 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 949 waitForIdle(); 950 onView(withIdFromRuntimeResource("content_preview_image_1_large")) 951 .check(matches(isDisplayed())); 952 onView(withIdFromRuntimeResource("content_preview_image_2_large")) 953 .check(matches(not(isDisplayed()))); 954 onView(withIdFromRuntimeResource("content_preview_image_2_small")) 955 .check(matches(not(isDisplayed()))); 956 onView(withIdFromRuntimeResource("content_preview_image_3_small")) 957 .check(matches(not(isDisplayed()))); 958 } 959 960 @Test twoVisibleImagePreview()961 public void twoVisibleImagePreview() throws InterruptedException { 962 Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/" 963 + com.android.frameworks.coretests.R.drawable.test320x240); 964 965 ArrayList<Uri> uris = new ArrayList<>(); 966 uris.add(uri); 967 uris.add(uri); 968 969 Intent sendIntent = createSendUriIntentWithPreview(uris); 970 ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap(); 971 ChooserActivityOverrideData.getInstance().isImageType = true; 972 973 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 974 975 when( 976 ChooserActivityOverrideData 977 .getInstance() 978 .resolverListController 979 .getResolversForIntent( 980 Mockito.anyBoolean(), 981 Mockito.anyBoolean(), 982 Mockito.anyBoolean(), 983 Mockito.isA(List.class))) 984 .thenReturn(resolvedComponentInfos); 985 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 986 waitForIdle(); 987 onView(withIdFromRuntimeResource("content_preview_image_1_large")) 988 .check(matches(isDisplayed())); 989 onView(withIdFromRuntimeResource("content_preview_image_2_large")) 990 .check(matches(isDisplayed())); 991 onView(withIdFromRuntimeResource("content_preview_image_2_small")) 992 .check(matches(not(isDisplayed()))); 993 onView(withIdFromRuntimeResource("content_preview_image_3_small")) 994 .check(matches(not(isDisplayed()))); 995 } 996 997 @Test threeOrMoreVisibleImagePreview()998 public void threeOrMoreVisibleImagePreview() throws InterruptedException { 999 Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/" 1000 + com.android.frameworks.coretests.R.drawable.test320x240); 1001 1002 ArrayList<Uri> uris = new ArrayList<>(); 1003 uris.add(uri); 1004 uris.add(uri); 1005 uris.add(uri); 1006 uris.add(uri); 1007 uris.add(uri); 1008 1009 Intent sendIntent = createSendUriIntentWithPreview(uris); 1010 ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap(); 1011 ChooserActivityOverrideData.getInstance().isImageType = true; 1012 1013 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1014 1015 when( 1016 ChooserActivityOverrideData 1017 .getInstance() 1018 .resolverListController 1019 .getResolversForIntent( 1020 Mockito.anyBoolean(), 1021 Mockito.anyBoolean(), 1022 Mockito.anyBoolean(), 1023 Mockito.isA(List.class))) 1024 .thenReturn(resolvedComponentInfos); 1025 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1026 waitForIdle(); 1027 onView(withIdFromRuntimeResource("content_preview_image_1_large")) 1028 .check(matches(isDisplayed())); 1029 onView(withIdFromRuntimeResource("content_preview_image_2_large")) 1030 .check(matches(not(isDisplayed()))); 1031 onView(withIdFromRuntimeResource("content_preview_image_2_small")) 1032 .check(matches(isDisplayed())); 1033 onView(withIdFromRuntimeResource("content_preview_image_3_small")) 1034 .check(matches(isDisplayed())); 1035 } 1036 1037 @Test testOnCreateLogging()1038 public void testOnCreateLogging() { 1039 Intent sendIntent = createSendTextIntent(); 1040 sendIntent.setType(TEST_MIME_TYPE); 1041 1042 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 1043 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 1044 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test")); 1045 waitForIdle(); 1046 verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture()); 1047 assertThat(logMakerCaptor.getAllValues().get(0).getCategory(), 1048 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)); 1049 assertThat(logMakerCaptor 1050 .getAllValues().get(0) 1051 .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS), 1052 is(notNullValue())); 1053 assertThat(logMakerCaptor 1054 .getAllValues().get(0) 1055 .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE), 1056 is(TEST_MIME_TYPE)); 1057 assertThat(logMakerCaptor 1058 .getAllValues().get(0) 1059 .getSubtype(), 1060 is(MetricsEvent.PARENT_PROFILE)); 1061 } 1062 1063 @Test testOnCreateLoggingFromWorkProfile()1064 public void testOnCreateLoggingFromWorkProfile() { 1065 Intent sendIntent = createSendTextIntent(); 1066 sendIntent.setType(TEST_MIME_TYPE); 1067 ChooserActivityOverrideData.getInstance().alternateProfileSetting = 1068 MetricsEvent.MANAGED_PROFILE; 1069 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 1070 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 1071 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test")); 1072 waitForIdle(); 1073 verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture()); 1074 assertThat(logMakerCaptor.getAllValues().get(0).getCategory(), 1075 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)); 1076 assertThat(logMakerCaptor 1077 .getAllValues().get(0) 1078 .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS), 1079 is(notNullValue())); 1080 assertThat(logMakerCaptor 1081 .getAllValues().get(0) 1082 .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE), 1083 is(TEST_MIME_TYPE)); 1084 assertThat(logMakerCaptor 1085 .getAllValues().get(0) 1086 .getSubtype(), 1087 is(MetricsEvent.MANAGED_PROFILE)); 1088 } 1089 1090 @Test testEmptyPreviewLogging()1091 public void testEmptyPreviewLogging() { 1092 Intent sendIntent = createSendTextIntentWithPreview(null, null); 1093 1094 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 1095 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 1096 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "empty preview logger test")); 1097 waitForIdle(); 1098 1099 verify(mockLogger, Mockito.times(1)).write(logMakerCaptor.capture()); 1100 // First invocation is from onCreate 1101 assertThat(logMakerCaptor.getAllValues().get(0).getCategory(), 1102 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)); 1103 } 1104 1105 @Test testTitlePreviewLogging()1106 public void testTitlePreviewLogging() { 1107 Intent sendIntent = createSendTextIntentWithPreview("TestTitle", null); 1108 1109 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 1110 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 1111 1112 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1113 1114 when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent( 1115 Mockito.anyBoolean(), 1116 Mockito.anyBoolean(), 1117 Mockito.anyBoolean(), 1118 Mockito.isA(List.class))).thenReturn(resolvedComponentInfos); 1119 1120 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1121 waitForIdle(); 1122 // Second invocation is from onCreate 1123 verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture()); 1124 assertThat(logMakerCaptor.getAllValues().get(0).getSubtype(), 1125 is(CONTENT_PREVIEW_TEXT)); 1126 assertThat(logMakerCaptor.getAllValues().get(0).getCategory(), 1127 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)); 1128 } 1129 1130 @Test testImagePreviewLogging()1131 public void testImagePreviewLogging() { 1132 Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/" 1133 + com.android.frameworks.coretests.R.drawable.test320x240); 1134 1135 ArrayList<Uri> uris = new ArrayList<>(); 1136 uris.add(uri); 1137 1138 Intent sendIntent = createSendUriIntentWithPreview(uris); 1139 ChooserActivityOverrideData.getInstance().previewThumbnail = createBitmap(); 1140 ChooserActivityOverrideData.getInstance().isImageType = true; 1141 1142 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1143 1144 when( 1145 ChooserActivityOverrideData 1146 .getInstance() 1147 .resolverListController 1148 .getResolversForIntent( 1149 Mockito.anyBoolean(), 1150 Mockito.anyBoolean(), 1151 Mockito.anyBoolean(), 1152 Mockito.isA(List.class))) 1153 .thenReturn(resolvedComponentInfos); 1154 1155 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 1156 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 1157 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1158 waitForIdle(); 1159 verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture()); 1160 // First invocation is from onCreate 1161 assertThat(logMakerCaptor.getAllValues().get(0).getSubtype(), 1162 is(CONTENT_PREVIEW_IMAGE)); 1163 assertThat(logMakerCaptor.getAllValues().get(0).getCategory(), 1164 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)); 1165 } 1166 1167 @Test oneVisibleFilePreview()1168 public void oneVisibleFilePreview() throws InterruptedException { 1169 Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf"); 1170 1171 ArrayList<Uri> uris = new ArrayList<>(); 1172 uris.add(uri); 1173 1174 Intent sendIntent = createSendUriIntentWithPreview(uris); 1175 1176 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1177 1178 when( 1179 ChooserActivityOverrideData 1180 .getInstance() 1181 .resolverListController 1182 .getResolversForIntent( 1183 Mockito.anyBoolean(), 1184 Mockito.anyBoolean(), 1185 Mockito.anyBoolean(), 1186 Mockito.isA(List.class))) 1187 .thenReturn(resolvedComponentInfos); 1188 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1189 waitForIdle(); 1190 onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed())); 1191 onView(withIdFromRuntimeResource("content_preview_filename")) 1192 .check(matches(withText("app.pdf"))); 1193 onView(withIdFromRuntimeResource("content_preview_file_icon")) 1194 .check(matches(isDisplayed())); 1195 } 1196 1197 1198 @Test moreThanOneVisibleFilePreview()1199 public void moreThanOneVisibleFilePreview() throws InterruptedException { 1200 Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf"); 1201 1202 ArrayList<Uri> uris = new ArrayList<>(); 1203 uris.add(uri); 1204 uris.add(uri); 1205 uris.add(uri); 1206 1207 Intent sendIntent = createSendUriIntentWithPreview(uris); 1208 1209 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1210 1211 when( 1212 ChooserActivityOverrideData 1213 .getInstance() 1214 .resolverListController 1215 .getResolversForIntent( 1216 Mockito.anyBoolean(), 1217 Mockito.anyBoolean(), 1218 Mockito.anyBoolean(), 1219 Mockito.isA(List.class))) 1220 .thenReturn(resolvedComponentInfos); 1221 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1222 waitForIdle(); 1223 onView(withIdFromRuntimeResource("content_preview_filename")) 1224 .check(matches(isDisplayed())); 1225 onView(withIdFromRuntimeResource("content_preview_filename")) 1226 .check(matches(withText("app.pdf + 2 files"))); 1227 onView(withIdFromRuntimeResource("content_preview_file_icon")) 1228 .check(matches(isDisplayed())); 1229 } 1230 1231 @Test contentProviderThrowSecurityException()1232 public void contentProviderThrowSecurityException() throws InterruptedException { 1233 Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf"); 1234 1235 ArrayList<Uri> uris = new ArrayList<>(); 1236 uris.add(uri); 1237 1238 Intent sendIntent = createSendUriIntentWithPreview(uris); 1239 1240 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1241 when( 1242 ChooserActivityOverrideData 1243 .getInstance() 1244 .resolverListController 1245 .getResolversForIntent( 1246 Mockito.anyBoolean(), 1247 Mockito.anyBoolean(), 1248 Mockito.anyBoolean(), 1249 Mockito.isA(List.class))) 1250 .thenReturn(resolvedComponentInfos); 1251 1252 ChooserActivityOverrideData.getInstance().resolverForceException = true; 1253 1254 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1255 waitForIdle(); 1256 onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed())); 1257 onView(withIdFromRuntimeResource("content_preview_filename")) 1258 .check(matches(withText("app.pdf"))); 1259 onView(withIdFromRuntimeResource("content_preview_file_icon")) 1260 .check(matches(isDisplayed())); 1261 } 1262 1263 @Test contentProviderReturnsNoColumns()1264 public void contentProviderReturnsNoColumns() throws InterruptedException { 1265 Uri uri = Uri.parse("content://com.android.frameworks.coretests/app.pdf"); 1266 1267 ArrayList<Uri> uris = new ArrayList<>(); 1268 uris.add(uri); 1269 uris.add(uri); 1270 1271 Intent sendIntent = createSendUriIntentWithPreview(uris); 1272 1273 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1274 when( 1275 ChooserActivityOverrideData 1276 .getInstance() 1277 .resolverListController 1278 .getResolversForIntent( 1279 Mockito.anyBoolean(), 1280 Mockito.anyBoolean(), 1281 Mockito.anyBoolean(), 1282 Mockito.isA(List.class))) 1283 .thenReturn(resolvedComponentInfos); 1284 1285 Cursor cursor = mock(Cursor.class); 1286 when(cursor.getCount()).thenReturn(1); 1287 Mockito.doNothing().when(cursor).close(); 1288 when(cursor.moveToFirst()).thenReturn(true); 1289 when(cursor.getColumnIndex(Mockito.anyString())).thenReturn(-1); 1290 1291 ChooserActivityOverrideData.getInstance().resolverCursor = cursor; 1292 1293 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1294 waitForIdle(); 1295 onView(withIdFromRuntimeResource("content_preview_filename")).check(matches(isDisplayed())); 1296 onView(withIdFromRuntimeResource("content_preview_filename")) 1297 .check(matches(withText("app.pdf + 1 file"))); 1298 onView(withIdFromRuntimeResource("content_preview_file_icon")) 1299 .check(matches(isDisplayed())); 1300 } 1301 1302 @Test testGetBaseScore()1303 public void testGetBaseScore() { 1304 final float testBaseScore = 0.89f; 1305 1306 Intent sendIntent = createSendTextIntent(); 1307 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1308 1309 when( 1310 ChooserActivityOverrideData 1311 .getInstance() 1312 .resolverListController 1313 .getResolversForIntent( 1314 Mockito.anyBoolean(), 1315 Mockito.anyBoolean(), 1316 Mockito.anyBoolean(), 1317 Mockito.isA(List.class))) 1318 .thenReturn(resolvedComponentInfos); 1319 when( 1320 ChooserActivityOverrideData 1321 .getInstance() 1322 .resolverListController 1323 .getScore(Mockito.isA(DisplayResolveInfo.class))) 1324 .thenReturn(testBaseScore); 1325 1326 final IChooserWrapper activity = (IChooserWrapper) 1327 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1328 waitForIdle(); 1329 1330 final DisplayResolveInfo testDri = 1331 activity.createTestDisplayResolveInfo(sendIntent, 1332 ResolverDataProvider.createResolveInfo(3, 0), "testLabel", "testInfo", sendIntent, 1333 /* resolveInfoPresentationGetter */ null); 1334 final ChooserListAdapter adapter = activity.getAdapter(); 1335 1336 assertThat(adapter.getBaseScore(null, 0), is(CALLER_TARGET_SCORE_BOOST)); 1337 assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_DEFAULT), is(testBaseScore)); 1338 assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_CHOOSER_TARGET), is(testBaseScore)); 1339 assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE), 1340 is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST)); 1341 assertThat(adapter.getBaseScore(testDri, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER), 1342 is(testBaseScore * SHORTCUT_TARGET_SCORE_BOOST)); 1343 } 1344 1345 @Test testConvertToChooserTarget_predictionService()1346 public void testConvertToChooserTarget_predictionService() { 1347 Intent sendIntent = createSendTextIntent(); 1348 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1349 when( 1350 ChooserActivityOverrideData 1351 .getInstance() 1352 .resolverListController 1353 .getResolversForIntent( 1354 Mockito.anyBoolean(), 1355 Mockito.anyBoolean(), 1356 Mockito.anyBoolean(), 1357 Mockito.isA(List.class))) 1358 .thenReturn(resolvedComponentInfos); 1359 1360 final ChooserActivity activity = 1361 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1362 waitForIdle(); 1363 1364 List<ShareShortcutInfo> shortcuts = createShortcuts(activity); 1365 1366 int[] expectedOrderAllShortcuts = {0, 1, 2, 3}; 1367 float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.98f, 0.97f}; 1368 1369 List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, 1370 null, TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); 1371 assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, 1372 expectedOrderAllShortcuts, expectedScoreAllShortcuts); 1373 1374 List<ShareShortcutInfo> subset = new ArrayList<>(); 1375 subset.add(shortcuts.get(1)); 1376 subset.add(shortcuts.get(2)); 1377 subset.add(shortcuts.get(3)); 1378 1379 int[] expectedOrderSubset = {1, 2, 3}; 1380 float[] expectedScoreSubset = {0.99f, 0.98f, 0.97f}; 1381 1382 chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, 1383 TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE); 1384 assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, 1385 expectedOrderSubset, expectedScoreSubset); 1386 } 1387 1388 @Test testConvertToChooserTarget_shortcutManager()1389 public void testConvertToChooserTarget_shortcutManager() { 1390 Intent sendIntent = createSendTextIntent(); 1391 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1392 when( 1393 ChooserActivityOverrideData 1394 .getInstance() 1395 .resolverListController 1396 .getResolversForIntent( 1397 Mockito.anyBoolean(), 1398 Mockito.anyBoolean(), 1399 Mockito.anyBoolean(), 1400 Mockito.isA(List.class))) 1401 .thenReturn(resolvedComponentInfos); 1402 1403 final ChooserActivity activity = 1404 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1405 waitForIdle(); 1406 1407 List<ShareShortcutInfo> shortcuts = createShortcuts(activity); 1408 1409 int[] expectedOrderAllShortcuts = {2, 0, 3, 1}; 1410 float[] expectedScoreAllShortcuts = {1.0f, 0.99f, 0.99f, 0.98f}; 1411 1412 List<ChooserTarget> chooserTargets = activity.convertToChooserTarget(shortcuts, shortcuts, 1413 null, TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); 1414 assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, 1415 expectedOrderAllShortcuts, expectedScoreAllShortcuts); 1416 1417 List<ShareShortcutInfo> subset = new ArrayList<>(); 1418 subset.add(shortcuts.get(1)); 1419 subset.add(shortcuts.get(2)); 1420 subset.add(shortcuts.get(3)); 1421 1422 int[] expectedOrderSubset = {2, 3, 1}; 1423 float[] expectedScoreSubset = {1.0f, 0.99f, 0.98f}; 1424 1425 chooserTargets = activity.convertToChooserTarget(subset, shortcuts, null, 1426 TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER); 1427 assertCorrectShortcutToChooserTargetConversion(shortcuts, chooserTargets, 1428 expectedOrderSubset, expectedScoreSubset); 1429 } 1430 1431 // This test is too long and too slow and should not be taken as an example for future tests. 1432 @Test @Ignore testDirectTargetSelectionLogging()1433 public void testDirectTargetSelectionLogging() throws InterruptedException { 1434 Intent sendIntent = createSendTextIntent(); 1435 // We need app targets for direct targets to get displayed 1436 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1437 when( 1438 ChooserActivityOverrideData 1439 .getInstance() 1440 .resolverListController 1441 .getResolversForIntent( 1442 Mockito.anyBoolean(), 1443 Mockito.anyBoolean(), 1444 Mockito.anyBoolean(), 1445 Mockito.isA(List.class))) 1446 .thenReturn(resolvedComponentInfos); 1447 1448 // Set up resources 1449 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 1450 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 1451 // Create direct share target 1452 List<ChooserTarget> serviceTargets = createDirectShareTargets(1, ""); 1453 ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0); 1454 1455 // Start activity 1456 final IChooserWrapper activity = (IChooserWrapper) 1457 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1458 1459 // Insert the direct share target 1460 Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); 1461 directShareToShortcutInfos.put(serviceTargets.get(0), null); 1462 InstrumentationRegistry.getInstrumentation().runOnMainSync( 1463 () -> activity.getAdapter().addServiceResults( 1464 activity.createTestDisplayResolveInfo(sendIntent, 1465 ri, 1466 "testLabel", 1467 "testInfo", 1468 sendIntent, 1469 /* resolveInfoPresentationGetter */ null), 1470 serviceTargets, 1471 TARGET_TYPE_CHOOSER_TARGET, 1472 directShareToShortcutInfos) 1473 ); 1474 1475 // Thread.sleep shouldn't be a thing in an integration test but it's 1476 // necessary here because of the way the code is structured 1477 // TODO: restructure the tests b/129870719 1478 Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs); 1479 1480 assertThat("Chooser should have 3 targets (2 apps, 1 direct)", 1481 activity.getAdapter().getCount(), is(3)); 1482 assertThat("Chooser should have exactly one selectable direct target", 1483 activity.getAdapter().getSelectableServiceTargetCount(), is(1)); 1484 assertThat("The resolver info must match the resolver info used to create the target", 1485 activity.getAdapter().getItem(0).getResolveInfo(), is(ri)); 1486 1487 // Click on the direct target 1488 String name = serviceTargets.get(0).getTitle().toString(); 1489 onView(withText(name)) 1490 .perform(click()); 1491 waitForIdle(); 1492 1493 // Currently we're seeing 3 invocations 1494 // 1. ChooserActivity.onCreate() 1495 // 2. ChooserActivity$ChooserRowAdapter.createContentPreviewView() 1496 // 3. ChooserActivity.startSelected -- which is the one we're after 1497 verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture()); 1498 assertThat(logMakerCaptor.getAllValues().get(2).getCategory(), 1499 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET)); 1500 String hashedName = (String) logMakerCaptor 1501 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_HASHED_TARGET_NAME); 1502 assertThat("Hash is not predictable but must be obfuscated", 1503 hashedName, is(not(name))); 1504 assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor 1505 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1)); 1506 } 1507 1508 // This test is too long and too slow and should not be taken as an example for future tests. 1509 @Test @Ignore testDirectTargetLoggingWithRankedAppTarget()1510 public void testDirectTargetLoggingWithRankedAppTarget() throws InterruptedException { 1511 Intent sendIntent = createSendTextIntent(); 1512 // We need app targets for direct targets to get displayed 1513 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1514 when( 1515 ChooserActivityOverrideData 1516 .getInstance() 1517 .resolverListController 1518 .getResolversForIntent( 1519 Mockito.anyBoolean(), 1520 Mockito.anyBoolean(), 1521 Mockito.anyBoolean(), 1522 Mockito.isA(List.class))) 1523 .thenReturn(resolvedComponentInfos); 1524 1525 // Set up resources 1526 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 1527 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 1528 // Create direct share target 1529 List<ChooserTarget> serviceTargets = createDirectShareTargets(1, 1530 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName); 1531 ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0); 1532 1533 // Start activity 1534 final IChooserWrapper activity = (IChooserWrapper) 1535 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1536 1537 // Insert the direct share target 1538 Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); 1539 directShareToShortcutInfos.put(serviceTargets.get(0), null); 1540 InstrumentationRegistry.getInstrumentation().runOnMainSync( 1541 () -> activity.getAdapter().addServiceResults( 1542 activity.createTestDisplayResolveInfo(sendIntent, 1543 ri, 1544 "testLabel", 1545 "testInfo", 1546 sendIntent, 1547 /* resolveInfoPresentationGetter */ null), 1548 serviceTargets, 1549 TARGET_TYPE_CHOOSER_TARGET, 1550 directShareToShortcutInfos) 1551 ); 1552 // Thread.sleep shouldn't be a thing in an integration test but it's 1553 // necessary here because of the way the code is structured 1554 // TODO: restructure the tests b/129870719 1555 Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs); 1556 1557 assertThat("Chooser should have 3 targets (2 apps, 1 direct)", 1558 activity.getAdapter().getCount(), is(3)); 1559 assertThat("Chooser should have exactly one selectable direct target", 1560 activity.getAdapter().getSelectableServiceTargetCount(), is(1)); 1561 assertThat("The resolver info must match the resolver info used to create the target", 1562 activity.getAdapter().getItem(0).getResolveInfo(), is(ri)); 1563 1564 // Click on the direct target 1565 String name = serviceTargets.get(0).getTitle().toString(); 1566 onView(withText(name)) 1567 .perform(click()); 1568 waitForIdle(); 1569 1570 // Currently we're seeing 3 invocations 1571 // 1. ChooserActivity.onCreate() 1572 // 2. ChooserActivity$ChooserRowAdapter.createContentPreviewView() 1573 // 3. ChooserActivity.startSelected -- which is the one we're after 1574 verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture()); 1575 assertThat(logMakerCaptor.getAllValues().get(2).getCategory(), 1576 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET)); 1577 assertThat("The packages should match for app target and direct target", logMakerCaptor 1578 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0)); 1579 } 1580 1581 @Test @Ignore testShortcutTargetWithApplyAppLimits()1582 public void testShortcutTargetWithApplyAppLimits() throws InterruptedException { 1583 // Set up resources 1584 ChooserActivityOverrideData.getInstance().resources = Mockito.spy( 1585 InstrumentationRegistry.getInstrumentation().getContext().getResources()); 1586 when( 1587 ChooserActivityOverrideData 1588 .getInstance() 1589 .resources 1590 .getInteger( 1591 getRuntimeResourceId("config_maxShortcutTargetsPerApp", "integer"))) 1592 .thenReturn(1); 1593 Intent sendIntent = createSendTextIntent(); 1594 // We need app targets for direct targets to get displayed 1595 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1596 when( 1597 ChooserActivityOverrideData 1598 .getInstance() 1599 .resolverListController 1600 .getResolversForIntent( 1601 Mockito.anyBoolean(), 1602 Mockito.anyBoolean(), 1603 Mockito.anyBoolean(), 1604 Mockito.isA(List.class))) 1605 .thenReturn(resolvedComponentInfos); 1606 // Create direct share target 1607 List<ChooserTarget> serviceTargets = createDirectShareTargets(2, 1608 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName); 1609 ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0); 1610 1611 // Start activity 1612 final ChooserActivity activity = 1613 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1614 final IChooserWrapper wrapper = (IChooserWrapper) activity; 1615 1616 // Insert the direct share target 1617 Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); 1618 List<ShareShortcutInfo> shortcutInfos = createShortcuts(activity); 1619 directShareToShortcutInfos.put(serviceTargets.get(0), 1620 shortcutInfos.get(0).getShortcutInfo()); 1621 directShareToShortcutInfos.put(serviceTargets.get(1), 1622 shortcutInfos.get(1).getShortcutInfo()); 1623 InstrumentationRegistry.getInstrumentation().runOnMainSync( 1624 () -> wrapper.getAdapter().addServiceResults( 1625 wrapper.createTestDisplayResolveInfo(sendIntent, 1626 ri, 1627 "testLabel", 1628 "testInfo", 1629 sendIntent, 1630 /* resolveInfoPresentationGetter */ null), 1631 serviceTargets, 1632 TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE, 1633 directShareToShortcutInfos) 1634 ); 1635 // Thread.sleep shouldn't be a thing in an integration test but it's 1636 // necessary here because of the way the code is structured 1637 // TODO: restructure the tests b/129870719 1638 Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs); 1639 1640 assertThat("Chooser should have 3 targets (2 apps, 1 direct)", 1641 wrapper.getAdapter().getCount(), is(3)); 1642 assertThat("Chooser should have exactly one selectable direct target", 1643 wrapper.getAdapter().getSelectableServiceTargetCount(), is(1)); 1644 assertThat("The resolver info must match the resolver info used to create the target", 1645 wrapper.getAdapter().getItem(0).getResolveInfo(), is(ri)); 1646 assertThat("The display label must match", 1647 wrapper.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0")); 1648 } 1649 1650 @Test @Ignore testShortcutTargetWithoutApplyAppLimits()1651 public void testShortcutTargetWithoutApplyAppLimits() throws InterruptedException { 1652 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 1653 SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI, 1654 Boolean.toString(false), 1655 true /* makeDefault*/); 1656 // Set up resources 1657 ChooserActivityOverrideData.getInstance().resources = Mockito.spy( 1658 InstrumentationRegistry.getInstrumentation().getContext().getResources()); 1659 when( 1660 ChooserActivityOverrideData 1661 .getInstance() 1662 .resources 1663 .getInteger( 1664 getRuntimeResourceId("config_maxShortcutTargetsPerApp", "integer"))) 1665 .thenReturn(1); 1666 Intent sendIntent = createSendTextIntent(); 1667 // We need app targets for direct targets to get displayed 1668 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 1669 when( 1670 ChooserActivityOverrideData 1671 .getInstance() 1672 .resolverListController 1673 .getResolversForIntent( 1674 Mockito.anyBoolean(), 1675 Mockito.anyBoolean(), 1676 Mockito.anyBoolean(), 1677 Mockito.isA(List.class))) 1678 .thenReturn(resolvedComponentInfos); 1679 // Create direct share target 1680 List<ChooserTarget> serviceTargets = createDirectShareTargets(2, 1681 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName); 1682 ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0); 1683 1684 // Start activity 1685 final ChooserActivity activity = 1686 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1687 final IChooserWrapper wrapper = (IChooserWrapper) activity; 1688 1689 // Insert the direct share target 1690 Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); 1691 List<ShareShortcutInfo> shortcutInfos = createShortcuts(activity); 1692 directShareToShortcutInfos.put(serviceTargets.get(0), 1693 shortcutInfos.get(0).getShortcutInfo()); 1694 directShareToShortcutInfos.put(serviceTargets.get(1), 1695 shortcutInfos.get(1).getShortcutInfo()); 1696 InstrumentationRegistry.getInstrumentation().runOnMainSync( 1697 () -> wrapper.getAdapter().addServiceResults( 1698 wrapper.createTestDisplayResolveInfo(sendIntent, 1699 ri, 1700 "testLabel", 1701 "testInfo", 1702 sendIntent, 1703 /* resolveInfoPresentationGetter */ null), 1704 serviceTargets, 1705 TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE, 1706 directShareToShortcutInfos) 1707 ); 1708 // Thread.sleep shouldn't be a thing in an integration test but it's 1709 // necessary here because of the way the code is structured 1710 // TODO: restructure the tests b/129870719 1711 Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs); 1712 1713 assertThat("Chooser should have 4 targets (2 apps, 2 direct)", 1714 wrapper.getAdapter().getCount(), is(4)); 1715 assertThat("Chooser should have exactly two selectable direct target", 1716 wrapper.getAdapter().getSelectableServiceTargetCount(), is(2)); 1717 assertThat("The resolver info must match the resolver info used to create the target", 1718 wrapper.getAdapter().getItem(0).getResolveInfo(), is(ri)); 1719 assertThat("The display label must match", 1720 wrapper.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0")); 1721 assertThat("The display label must match", 1722 wrapper.getAdapter().getItem(1).getDisplayLabel(), is("testTitle1")); 1723 } 1724 1725 @Test testUpdateMaxTargetsPerRow_columnCountIsUpdated()1726 public void testUpdateMaxTargetsPerRow_columnCountIsUpdated() throws InterruptedException { 1727 updateMaxTargetsPerRowResource(/* targetsPerRow= */ 4); 1728 givenAppTargets(/* appCount= */ 16); 1729 Intent sendIntent = createSendTextIntent(); 1730 final ChooserActivity activity = 1731 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1732 1733 updateMaxTargetsPerRowResource(/* targetsPerRow= */ 6); 1734 InstrumentationRegistry.getInstrumentation() 1735 .runOnMainSync(() -> activity.onConfigurationChanged( 1736 InstrumentationRegistry.getInstrumentation() 1737 .getContext().getResources().getConfiguration())); 1738 1739 waitForIdle(); 1740 onView(withIdFromRuntimeResource("resolver_list")) 1741 .check(matches(withGridColumnCount(6))); 1742 } 1743 1744 // This test is too long and too slow and should not be taken as an example for future tests. 1745 @Test @Ignore testDirectTargetLoggingWithAppTargetNotRankedPortrait()1746 public void testDirectTargetLoggingWithAppTargetNotRankedPortrait() 1747 throws InterruptedException { 1748 testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_PORTRAIT, 4); 1749 } 1750 1751 @Test @Ignore testDirectTargetLoggingWithAppTargetNotRankedLandscape()1752 public void testDirectTargetLoggingWithAppTargetNotRankedLandscape() 1753 throws InterruptedException { 1754 testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_LANDSCAPE, 8); 1755 } 1756 testDirectTargetLoggingWithAppTargetNotRanked( int orientation, int appTargetsExpected )1757 private void testDirectTargetLoggingWithAppTargetNotRanked( 1758 int orientation, int appTargetsExpected 1759 ) throws InterruptedException { 1760 Configuration configuration = 1761 new Configuration(InstrumentationRegistry.getInstrumentation().getContext() 1762 .getResources().getConfiguration()); 1763 configuration.orientation = orientation; 1764 1765 ChooserActivityOverrideData.getInstance().resources = Mockito.spy( 1766 InstrumentationRegistry.getInstrumentation().getContext().getResources()); 1767 when( 1768 ChooserActivityOverrideData 1769 .getInstance() 1770 .resources 1771 .getConfiguration()) 1772 .thenReturn(configuration); 1773 1774 Intent sendIntent = createSendTextIntent(); 1775 // We need app targets for direct targets to get displayed 1776 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(15); 1777 when( 1778 ChooserActivityOverrideData 1779 .getInstance() 1780 .resolverListController 1781 .getResolversForIntent( 1782 Mockito.anyBoolean(), 1783 Mockito.anyBoolean(), 1784 Mockito.anyBoolean(), 1785 Mockito.isA(List.class))) 1786 .thenReturn(resolvedComponentInfos); 1787 1788 // Set up resources 1789 MetricsLogger mockLogger = ChooserActivityOverrideData.getInstance().metricsLogger; 1790 ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); 1791 // Create direct share target 1792 List<ChooserTarget> serviceTargets = createDirectShareTargets(1, 1793 resolvedComponentInfos.get(14).getResolveInfoAt(0).activityInfo.packageName); 1794 ResolveInfo ri = ResolverDataProvider.createResolveInfo(16, 0); 1795 1796 // Start activity 1797 final IChooserWrapper activity = (IChooserWrapper) 1798 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 1799 final IChooserWrapper wrapper = (IChooserWrapper) activity; 1800 // Insert the direct share target 1801 Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos = new HashMap<>(); 1802 directShareToShortcutInfos.put(serviceTargets.get(0), null); 1803 InstrumentationRegistry.getInstrumentation().runOnMainSync( 1804 () -> wrapper.getAdapter().addServiceResults( 1805 wrapper.createTestDisplayResolveInfo(sendIntent, 1806 ri, 1807 "testLabel", 1808 "testInfo", 1809 sendIntent, 1810 /* resolveInfoPresentationGetter */ null), 1811 serviceTargets, 1812 TARGET_TYPE_CHOOSER_TARGET, 1813 directShareToShortcutInfos) 1814 ); 1815 // Thread.sleep shouldn't be a thing in an integration test but it's 1816 // necessary here because of the way the code is structured 1817 // TODO: restructure the tests b/129870719 1818 Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs); 1819 1820 assertThat( 1821 String.format("Chooser should have %d targets (%d apps, 1 direct, 15 A-Z)", 1822 appTargetsExpected + 16, appTargetsExpected), 1823 wrapper.getAdapter().getCount(), is(appTargetsExpected + 16)); 1824 assertThat("Chooser should have exactly one selectable direct target", 1825 wrapper.getAdapter().getSelectableServiceTargetCount(), is(1)); 1826 assertThat("The resolver info must match the resolver info used to create the target", 1827 wrapper.getAdapter().getItem(0).getResolveInfo(), is(ri)); 1828 1829 // Click on the direct target 1830 String name = serviceTargets.get(0).getTitle().toString(); 1831 onView(withText(name)) 1832 .perform(click()); 1833 waitForIdle(); 1834 1835 // Currently we're seeing 3 invocations 1836 // 1. ChooserActivity.onCreate() 1837 // 2. ChooserActivity$ChooserRowAdapter.createContentPreviewView() 1838 // 3. ChooserActivity.startSelected -- which is the one we're after 1839 verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture()); 1840 assertThat(logMakerCaptor.getAllValues().get(2).getCategory(), 1841 is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET)); 1842 assertThat("The packages shouldn't match for app target and direct target", logMakerCaptor 1843 .getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(-1)); 1844 } 1845 1846 @Test testWorkTab_displayedWhenWorkProfileUserAvailable()1847 public void testWorkTab_displayedWhenWorkProfileUserAvailable() { 1848 // enable the work tab feature flag 1849 ResolverActivity.ENABLE_TABBED_VIEW = true; 1850 Intent sendIntent = createSendTextIntent(); 1851 sendIntent.setType(TEST_MIME_TYPE); 1852 markWorkProfileUserAvailable(); 1853 1854 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 1855 waitForIdle(); 1856 1857 onView(withIdFromRuntimeResource("tabs")).check(matches(isDisplayed())); 1858 } 1859 1860 @Test testWorkTab_hiddenWhenWorkProfileUserNotAvailable()1861 public void testWorkTab_hiddenWhenWorkProfileUserNotAvailable() { 1862 // enable the work tab feature flag 1863 ResolverActivity.ENABLE_TABBED_VIEW = true; 1864 Intent sendIntent = createSendTextIntent(); 1865 sendIntent.setType(TEST_MIME_TYPE); 1866 1867 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 1868 waitForIdle(); 1869 1870 onView(withIdFromRuntimeResource("tabs")).check(matches(not(isDisplayed()))); 1871 } 1872 1873 @Test testWorkTab_eachTabUsesExpectedAdapter()1874 public void testWorkTab_eachTabUsesExpectedAdapter() { 1875 // enable the work tab feature flag 1876 ResolverActivity.ENABLE_TABBED_VIEW = true; 1877 int personalProfileTargets = 3; 1878 int otherProfileTargets = 1; 1879 List<ResolvedComponentInfo> personalResolvedComponentInfos = 1880 createResolvedComponentsForTestWithOtherProfile( 1881 personalProfileTargets + otherProfileTargets, /* userID */ 10); 1882 int workProfileTargets = 4; 1883 List<ResolvedComponentInfo> workResolvedComponentInfos = createResolvedComponentsForTest( 1884 workProfileTargets); 1885 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 1886 Intent sendIntent = createSendTextIntent(); 1887 sendIntent.setType(TEST_MIME_TYPE); 1888 markWorkProfileUserAvailable(); 1889 1890 final IChooserWrapper activity = (IChooserWrapper) 1891 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 1892 waitForIdle(); 1893 1894 assertThat(activity.getCurrentUserHandle().getIdentifier(), is(0)); 1895 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 1896 assertThat(activity.getCurrentUserHandle().getIdentifier(), is(10)); 1897 assertThat(activity.getPersonalListAdapter().getCount(), is(personalProfileTargets)); 1898 assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets)); 1899 } 1900 1901 @Test testWorkTab_workProfileHasExpectedNumberOfTargets()1902 public void testWorkTab_workProfileHasExpectedNumberOfTargets() throws InterruptedException { 1903 // enable the work tab feature flag 1904 ResolverActivity.ENABLE_TABBED_VIEW = true; 1905 markWorkProfileUserAvailable(); 1906 int workProfileTargets = 4; 1907 List<ResolvedComponentInfo> personalResolvedComponentInfos = 1908 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 1909 List<ResolvedComponentInfo> workResolvedComponentInfos = 1910 createResolvedComponentsForTest(workProfileTargets); 1911 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 1912 Intent sendIntent = createSendTextIntent(); 1913 sendIntent.setType(TEST_MIME_TYPE); 1914 1915 final IChooserWrapper activity = (IChooserWrapper) 1916 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 1917 waitForIdle(); 1918 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 1919 waitForIdle(); 1920 1921 assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets)); 1922 } 1923 1924 @Test @Ignore testWorkTab_selectingWorkTabAppOpensAppInWorkProfile()1925 public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException { 1926 // enable the work tab feature flag 1927 ResolverActivity.ENABLE_TABBED_VIEW = true; 1928 markWorkProfileUserAvailable(); 1929 List<ResolvedComponentInfo> personalResolvedComponentInfos = 1930 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 1931 int workProfileTargets = 4; 1932 List<ResolvedComponentInfo> workResolvedComponentInfos = 1933 createResolvedComponentsForTest(workProfileTargets); 1934 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 1935 Intent sendIntent = createSendTextIntent(); 1936 sendIntent.setType(TEST_MIME_TYPE); 1937 ResolveInfo[] chosen = new ResolveInfo[1]; 1938 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 1939 chosen[0] = targetInfo.getResolveInfo(); 1940 return true; 1941 }; 1942 1943 final IChooserWrapper activity = (IChooserWrapper) 1944 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 1945 waitForIdle(); 1946 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 1947 waitForIdle(); 1948 // wait for the share sheet to expand 1949 Thread.sleep(((ChooserActivity) activity).mListViewUpdateDelayMs); 1950 1951 onView(first(allOf( 1952 withText(workResolvedComponentInfos.get(0) 1953 .getResolveInfoAt(0).activityInfo.applicationInfo.name), 1954 isDisplayed()))) 1955 .perform(click()); 1956 waitForIdle(); 1957 assertThat(chosen[0], is(workResolvedComponentInfos.get(0).getResolveInfoAt(0))); 1958 } 1959 1960 @Test testWorkTab_crossProfileIntentsDisabled_personalToWork_emptyStateShown()1961 public void testWorkTab_crossProfileIntentsDisabled_personalToWork_emptyStateShown() { 1962 // enable the work tab feature flag 1963 ResolverActivity.ENABLE_TABBED_VIEW = true; 1964 markWorkProfileUserAvailable(); 1965 int workProfileTargets = 4; 1966 List<ResolvedComponentInfo> personalResolvedComponentInfos = 1967 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 1968 List<ResolvedComponentInfo> workResolvedComponentInfos = 1969 createResolvedComponentsForTest(workProfileTargets); 1970 ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false; 1971 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 1972 Intent sendIntent = createSendTextIntent(); 1973 sendIntent.setType(TEST_MIME_TYPE); 1974 1975 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 1976 waitForIdle(); 1977 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 1978 waitForIdle(); 1979 onView(withIdFromRuntimeResource("contentPanel")) 1980 .perform(swipeUp()); 1981 1982 onView(withTextFromRuntimeResource("resolver_cross_profile_blocked")) 1983 .check(matches(isDisplayed())); 1984 } 1985 1986 @Test testWorkTab_workProfileDisabled_emptyStateShown()1987 public void testWorkTab_workProfileDisabled_emptyStateShown() { 1988 // enable the work tab feature flag 1989 markWorkProfileUserAvailable(); 1990 int workProfileTargets = 4; 1991 List<ResolvedComponentInfo> personalResolvedComponentInfos = 1992 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 1993 List<ResolvedComponentInfo> workResolvedComponentInfos = 1994 createResolvedComponentsForTest(workProfileTargets); 1995 ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true; 1996 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 1997 Intent sendIntent = createSendTextIntent(); 1998 sendIntent.setType(TEST_MIME_TYPE); 1999 2000 ResolverActivity.ENABLE_TABBED_VIEW = true; 2001 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2002 waitForIdle(); 2003 onView(withIdFromRuntimeResource("contentPanel")) 2004 .perform(swipeUp()); 2005 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2006 waitForIdle(); 2007 2008 onView(withTextFromRuntimeResource("resolver_turn_on_work_apps")) 2009 .check(matches(isDisplayed())); 2010 } 2011 2012 @Test testWorkTab_noWorkAppsAvailable_emptyStateShown()2013 public void testWorkTab_noWorkAppsAvailable_emptyStateShown() { 2014 // enable the work tab feature flag 2015 ResolverActivity.ENABLE_TABBED_VIEW = true; 2016 markWorkProfileUserAvailable(); 2017 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2018 createResolvedComponentsForTest(3); 2019 List<ResolvedComponentInfo> workResolvedComponentInfos = 2020 createResolvedComponentsForTest(0); 2021 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2022 Intent sendIntent = createSendTextIntent(); 2023 sendIntent.setType(TEST_MIME_TYPE); 2024 2025 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2026 waitForIdle(); 2027 onView(withIdFromRuntimeResource("contentPanel")) 2028 .perform(swipeUp()); 2029 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2030 waitForIdle(); 2031 2032 onView(withTextFromRuntimeResource("resolver_no_work_apps_available")) 2033 .check(matches(isDisplayed())); 2034 } 2035 2036 @Ignore // b/220067877 2037 @Test testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown()2038 public void testWorkTab_xProfileOff_noAppsAvailable_workOff_xProfileOffEmptyStateShown() { 2039 // enable the work tab feature flag 2040 ResolverActivity.ENABLE_TABBED_VIEW = true; 2041 markWorkProfileUserAvailable(); 2042 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2043 createResolvedComponentsForTest(3); 2044 List<ResolvedComponentInfo> workResolvedComponentInfos = 2045 createResolvedComponentsForTest(0); 2046 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2047 ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true; 2048 ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false; 2049 Intent sendIntent = createSendTextIntent(); 2050 sendIntent.setType(TEST_MIME_TYPE); 2051 2052 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2053 waitForIdle(); 2054 onView(withIdFromRuntimeResource("contentPanel")) 2055 .perform(swipeUp()); 2056 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2057 waitForIdle(); 2058 2059 onView(withTextFromRuntimeResource("resolver_cross_profile_blocked")) 2060 .check(matches(isDisplayed())); 2061 } 2062 2063 @Test testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown()2064 public void testWorkTab_noAppsAvailable_workOff_noAppsAvailableEmptyStateShown() { 2065 // enable the work tab feature flag 2066 ResolverActivity.ENABLE_TABBED_VIEW = true; 2067 markWorkProfileUserAvailable(); 2068 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2069 createResolvedComponentsForTest(3); 2070 List<ResolvedComponentInfo> workResolvedComponentInfos = 2071 createResolvedComponentsForTest(0); 2072 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2073 ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true; 2074 Intent sendIntent = createSendTextIntent(); 2075 sendIntent.setType(TEST_MIME_TYPE); 2076 2077 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2078 waitForIdle(); 2079 onView(withIdFromRuntimeResource("contentPanel")) 2080 .perform(swipeUp()); 2081 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2082 waitForIdle(); 2083 2084 onView(withTextFromRuntimeResource("resolver_no_work_apps_available")) 2085 .check(matches(isDisplayed())); 2086 } 2087 2088 @Test @Ignore("b/222124533") testAppTargetLogging()2089 public void testAppTargetLogging() throws InterruptedException { 2090 Intent sendIntent = createSendTextIntent(); 2091 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 2092 2093 when( 2094 ChooserActivityOverrideData 2095 .getInstance() 2096 .resolverListController 2097 .getResolversForIntent( 2098 Mockito.anyBoolean(), 2099 Mockito.anyBoolean(), 2100 Mockito.anyBoolean(), 2101 Mockito.isA(List.class))) 2102 .thenReturn(resolvedComponentInfos); 2103 2104 final IChooserWrapper activity = (IChooserWrapper) 2105 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 2106 waitForIdle(); 2107 2108 // TODO(b/222124533): other test cases use a timeout to make sure that the UI is fully 2109 // populated; without one, this test flakes. Ideally we should address the need for a 2110 // timeout everywhere instead of introducing one to fix this particular test. 2111 2112 assertThat(activity.getAdapter().getCount(), is(2)); 2113 onView(withIdFromRuntimeResource("profile_button")).check(doesNotExist()); 2114 2115 ResolveInfo[] chosen = new ResolveInfo[1]; 2116 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 2117 chosen[0] = targetInfo.getResolveInfo(); 2118 return true; 2119 }; 2120 2121 ResolveInfo toChoose = resolvedComponentInfos.get(0).getResolveInfoAt(0); 2122 onView(withText(toChoose.activityInfo.name)) 2123 .perform(click()); 2124 waitForIdle(); 2125 2126 ChooserActivityLoggerFake logger = 2127 (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); 2128 2129 // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events. 2130 logger.removeCallsForUiEventsOfType( 2131 ChooserActivityLogger.SharesheetStandardEvent 2132 .SHARESHEET_DIRECT_LOAD_COMPLETE.getId()); 2133 2134 // SHARESHEET_TRIGGERED: 2135 assertThat(logger.event(0).getId(), 2136 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); 2137 2138 // SHARESHEET_STARTED: 2139 assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); 2140 assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); 2141 assertThat(logger.get(1).mimeType, is("text/plain")); 2142 assertThat(logger.get(1).packageName, is( 2143 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); 2144 assertThat(logger.get(1).appProvidedApp, is(0)); 2145 assertThat(logger.get(1).appProvidedDirect, is(0)); 2146 assertThat(logger.get(1).isWorkprofile, is(false)); 2147 assertThat(logger.get(1).previewType, is(3)); 2148 2149 // SHARESHEET_APP_LOAD_COMPLETE: 2150 assertThat(logger.event(2).getId(), 2151 is(ChooserActivityLogger 2152 .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); 2153 2154 // Next are just artifacts of test set-up: 2155 assertThat(logger.event(3).getId(), 2156 is(ChooserActivityLogger 2157 .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId())); 2158 assertThat(logger.event(4).getId(), 2159 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId())); 2160 2161 // SHARESHEET_APP_TARGET_SELECTED: 2162 assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); 2163 assertThat(logger.get(5).targetType, 2164 is(ChooserActivityLogger 2165 .SharesheetTargetSelectedEvent.SHARESHEET_APP_TARGET_SELECTED.getId())); 2166 2167 // No more events. 2168 assertThat(logger.numCalls(), is(6)); 2169 } 2170 2171 @Test testDirectTargetLogging()2172 public void testDirectTargetLogging() { 2173 Intent sendIntent = createSendTextIntent(); 2174 // We need app targets for direct targets to get displayed 2175 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 2176 when( 2177 ChooserActivityOverrideData 2178 .getInstance() 2179 .resolverListController 2180 .getResolversForIntent( 2181 Mockito.anyBoolean(), 2182 Mockito.anyBoolean(), 2183 Mockito.anyBoolean(), 2184 Mockito.isA(List.class))) 2185 .thenReturn(resolvedComponentInfos); 2186 2187 // Create direct share target 2188 List<ChooserTarget> serviceTargets = createDirectShareTargets(1, 2189 resolvedComponentInfos.get(0).getResolveInfoAt(0).activityInfo.packageName); 2190 ResolveInfo ri = ResolverDataProvider.createResolveInfo(3, 0); 2191 2192 ChooserActivityOverrideData 2193 .getInstance() 2194 .directShareTargets = (activity, adapter) -> { 2195 DisplayResolveInfo displayInfo = activity.createTestDisplayResolveInfo( 2196 sendIntent, 2197 ri, 2198 "testLabel", 2199 "testInfo", 2200 sendIntent, 2201 /* resolveInfoPresentationGetter */ null); 2202 ServiceResultInfo[] results = { 2203 new ServiceResultInfo( 2204 displayInfo, 2205 serviceTargets, 2206 adapter.getUserHandle())}; 2207 // TODO: consider covering the other type. 2208 // Only 2 types are expected out of the shortcut loading logic: 2209 // - TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER, if shortcuts were loaded from 2210 // the ShortcutManager, and; 2211 // - TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE, if shortcuts were loaded 2212 // from AppPredictor. 2213 // Ideally, our tests should cover all of them. 2214 return new Pair<>(TARGET_TYPE_SHORTCUTS_FROM_SHORTCUT_MANAGER, results); 2215 }; 2216 2217 // Start activity 2218 final IChooserWrapper activity = (IChooserWrapper) 2219 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 2220 2221 assertThat("Chooser should have 3 targets (2 apps, 1 direct)", 2222 activity.getAdapter().getCount(), is(3)); 2223 assertThat("Chooser should have exactly one selectable direct target", 2224 activity.getAdapter().getSelectableServiceTargetCount(), is(1)); 2225 assertThat("The resolver info must match the resolver info used to create the target", 2226 activity.getAdapter().getItem(0).getResolveInfo(), is(ri)); 2227 2228 // Click on the direct target 2229 String name = serviceTargets.get(0).getTitle().toString(); 2230 onView(withText(name)) 2231 .perform(click()); 2232 waitForIdle(); 2233 2234 ChooserActivityLoggerFake logger = 2235 (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); 2236 assertThat(logger.numCalls(), is(6)); 2237 // first one should be SHARESHEET_TRIGGERED uievent 2238 assertThat(logger.get(0).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED)); 2239 assertThat(logger.get(0).event.getId(), 2240 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); 2241 // second one should be SHARESHEET_STARTED event 2242 assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); 2243 assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); 2244 assertThat(logger.get(1).mimeType, is("text/plain")); 2245 assertThat(logger.get(1).packageName, is( 2246 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); 2247 assertThat(logger.get(1).appProvidedApp, is(0)); 2248 assertThat(logger.get(1).appProvidedDirect, is(0)); 2249 assertThat(logger.get(1).isWorkprofile, is(false)); 2250 assertThat(logger.get(1).previewType, is(3)); 2251 // third one should be SHARESHEET_APP_LOAD_COMPLETE uievent 2252 assertThat(logger.get(2).atomId, is(FrameworkStatsLog.UI_EVENT_REPORTED)); 2253 assertThat(logger.get(2).event.getId(), 2254 is(ChooserActivityLogger 2255 .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); 2256 // fourth and fifth are just artifacts of test set-up 2257 // sixth one should be ranking atom with SHARESHEET_COPY_TARGET_SELECTED event 2258 assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); 2259 assertThat(logger.get(5).targetType, 2260 is(ChooserActivityLogger 2261 .SharesheetTargetSelectedEvent.SHARESHEET_SERVICE_TARGET_SELECTED.getId())); 2262 } 2263 2264 @Test @Ignore testEmptyDirectRowLogging()2265 public void testEmptyDirectRowLogging() throws InterruptedException { 2266 Intent sendIntent = createSendTextIntent(); 2267 // We need app targets for direct targets to get displayed 2268 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 2269 when( 2270 ChooserActivityOverrideData 2271 .getInstance() 2272 .resolverListController 2273 .getResolversForIntent( 2274 Mockito.anyBoolean(), 2275 Mockito.anyBoolean(), 2276 Mockito.anyBoolean(), 2277 Mockito.isA(List.class))) 2278 .thenReturn(resolvedComponentInfos); 2279 2280 // Start activity 2281 final IChooserWrapper activity = (IChooserWrapper) 2282 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 2283 2284 // Thread.sleep shouldn't be a thing in an integration test but it's 2285 // necessary here because of the way the code is structured 2286 Thread.sleep(3000); 2287 2288 assertThat("Chooser should have 2 app targets", 2289 activity.getAdapter().getCount(), is(2)); 2290 assertThat("Chooser should have no direct targets", 2291 activity.getAdapter().getSelectableServiceTargetCount(), is(0)); 2292 2293 ChooserActivityLoggerFake logger = 2294 (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); 2295 2296 // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events. 2297 logger.removeCallsForUiEventsOfType( 2298 ChooserActivityLogger.SharesheetStandardEvent 2299 .SHARESHEET_DIRECT_LOAD_COMPLETE.getId()); 2300 2301 // SHARESHEET_TRIGGERED: 2302 assertThat(logger.event(0).getId(), 2303 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); 2304 2305 // SHARESHEET_STARTED: 2306 assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); 2307 assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); 2308 assertThat(logger.get(1).mimeType, is("text/plain")); 2309 assertThat(logger.get(1).packageName, is( 2310 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); 2311 assertThat(logger.get(1).appProvidedApp, is(0)); 2312 assertThat(logger.get(1).appProvidedDirect, is(0)); 2313 assertThat(logger.get(1).isWorkprofile, is(false)); 2314 assertThat(logger.get(1).previewType, is(3)); 2315 2316 // SHARESHEET_APP_LOAD_COMPLETE: 2317 assertThat(logger.event(2).getId(), 2318 is(ChooserActivityLogger 2319 .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); 2320 2321 // SHARESHEET_EMPTY_DIRECT_SHARE_ROW: 2322 assertThat(logger.event(3).getId(), 2323 is(ChooserActivityLogger 2324 .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId())); 2325 2326 // Next is just an artifact of test set-up: 2327 assertThat(logger.event(4).getId(), 2328 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId())); 2329 2330 assertThat(logger.numCalls(), is(5)); 2331 } 2332 2333 @Ignore // b/220067877 2334 @Test testCopyTextToClipboardLogging()2335 public void testCopyTextToClipboardLogging() throws Exception { 2336 Intent sendIntent = createSendTextIntent(); 2337 List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2); 2338 2339 when( 2340 ChooserActivityOverrideData 2341 .getInstance() 2342 .resolverListController 2343 .getResolversForIntent( 2344 Mockito.anyBoolean(), 2345 Mockito.anyBoolean(), 2346 Mockito.anyBoolean(), 2347 Mockito.isA(List.class))) 2348 .thenReturn(resolvedComponentInfos); 2349 2350 final IChooserWrapper activity = (IChooserWrapper) 2351 mActivityRule.launchActivity(Intent.createChooser(sendIntent, null)); 2352 waitForIdle(); 2353 2354 onView(withIdFromRuntimeResource("chooser_copy_button")).check(matches(isDisplayed())); 2355 onView(withIdFromRuntimeResource("chooser_copy_button")).perform(click()); 2356 2357 ChooserActivityLoggerFake logger = 2358 (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); 2359 2360 // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events. 2361 logger.removeCallsForUiEventsOfType( 2362 ChooserActivityLogger.SharesheetStandardEvent 2363 .SHARESHEET_DIRECT_LOAD_COMPLETE.getId()); 2364 2365 // SHARESHEET_TRIGGERED: 2366 assertThat(logger.event(0).getId(), 2367 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); 2368 2369 // SHARESHEET_STARTED: 2370 assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); 2371 assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); 2372 assertThat(logger.get(1).mimeType, is("text/plain")); 2373 assertThat(logger.get(1).packageName, is( 2374 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); 2375 assertThat(logger.get(1).appProvidedApp, is(0)); 2376 assertThat(logger.get(1).appProvidedDirect, is(0)); 2377 assertThat(logger.get(1).isWorkprofile, is(false)); 2378 assertThat(logger.get(1).previewType, is(3)); 2379 2380 // SHARESHEET_APP_LOAD_COMPLETE: 2381 assertThat(logger.event(2).getId(), 2382 is(ChooserActivityLogger 2383 .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); 2384 2385 // Next are just artifacts of test set-up: 2386 assertThat(logger.event(3).getId(), 2387 is(ChooserActivityLogger 2388 .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId())); 2389 assertThat(logger.event(4).getId(), 2390 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_EXPANDED.getId())); 2391 2392 // SHARESHEET_COPY_TARGET_SELECTED: 2393 assertThat(logger.get(5).atomId, is(FrameworkStatsLog.RANKING_SELECTED)); 2394 assertThat(logger.get(5).targetType, 2395 is(ChooserActivityLogger 2396 .SharesheetTargetSelectedEvent.SHARESHEET_COPY_TARGET_SELECTED.getId())); 2397 2398 // No more events. 2399 assertThat(logger.numCalls(), is(6)); 2400 } 2401 2402 @Test @Ignore("b/222124533") testSwitchProfileLogging()2403 public void testSwitchProfileLogging() throws InterruptedException { 2404 // enable the work tab feature flag 2405 ResolverActivity.ENABLE_TABBED_VIEW = true; 2406 markWorkProfileUserAvailable(); 2407 int workProfileTargets = 4; 2408 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2409 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 2410 List<ResolvedComponentInfo> workResolvedComponentInfos = 2411 createResolvedComponentsForTest(workProfileTargets); 2412 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2413 Intent sendIntent = createSendTextIntent(); 2414 sendIntent.setType(TEST_MIME_TYPE); 2415 2416 final IChooserWrapper activity = (IChooserWrapper) 2417 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2418 waitForIdle(); 2419 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2420 waitForIdle(); 2421 onView(withTextFromRuntimeResource("resolver_personal_tab")).perform(click()); 2422 waitForIdle(); 2423 2424 ChooserActivityLoggerFake logger = 2425 (ChooserActivityLoggerFake) activity.getChooserActivityLogger(); 2426 2427 // TODO(b/211669337): Determine the expected SHARESHEET_DIRECT_LOAD_COMPLETE events. 2428 logger.removeCallsForUiEventsOfType( 2429 ChooserActivityLogger.SharesheetStandardEvent 2430 .SHARESHEET_DIRECT_LOAD_COMPLETE.getId()); 2431 2432 // SHARESHEET_TRIGGERED: 2433 assertThat(logger.event(0).getId(), 2434 is(ChooserActivityLogger.SharesheetStandardEvent.SHARESHEET_TRIGGERED.getId())); 2435 2436 // SHARESHEET_STARTED: 2437 assertThat(logger.get(1).atomId, is(FrameworkStatsLog.SHARESHEET_STARTED)); 2438 assertThat(logger.get(1).intent, is(Intent.ACTION_SEND)); 2439 assertThat(logger.get(1).mimeType, is(TEST_MIME_TYPE)); 2440 assertThat(logger.get(1).packageName, is( 2441 InstrumentationRegistry.getInstrumentation().getTargetContext().getPackageName())); 2442 assertThat(logger.get(1).appProvidedApp, is(0)); 2443 assertThat(logger.get(1).appProvidedDirect, is(0)); 2444 assertThat(logger.get(1).isWorkprofile, is(false)); 2445 assertThat(logger.get(1).previewType, is(3)); 2446 2447 // SHARESHEET_APP_LOAD_COMPLETE: 2448 assertThat(logger.event(2).getId(), 2449 is(ChooserActivityLogger 2450 .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); 2451 2452 // Next is just an artifact of test set-up: 2453 assertThat(logger.event(3).getId(), 2454 is(ChooserActivityLogger 2455 .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId())); 2456 2457 // SHARESHEET_PROFILE_CHANGED: 2458 assertThat(logger.event(4).getId(), 2459 is(ChooserActivityLogger.SharesheetStandardEvent 2460 .SHARESHEET_PROFILE_CHANGED.getId())); 2461 2462 // Repeat the loading steps in the new profile: 2463 2464 // SHARESHEET_APP_LOAD_COMPLETE: 2465 assertThat(logger.event(5).getId(), 2466 is(ChooserActivityLogger 2467 .SharesheetStandardEvent.SHARESHEET_APP_LOAD_COMPLETE.getId())); 2468 2469 // Next is again an artifact of test set-up: 2470 assertThat(logger.event(6).getId(), 2471 is(ChooserActivityLogger 2472 .SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId())); 2473 2474 // SHARESHEET_PROFILE_CHANGED: 2475 assertThat(logger.event(7).getId(), 2476 is(ChooserActivityLogger.SharesheetStandardEvent 2477 .SHARESHEET_PROFILE_CHANGED.getId())); 2478 2479 // No more events (this profile was already loaded). 2480 assertThat(logger.numCalls(), is(8)); 2481 } 2482 2483 @Test testAutolaunch_singleTarget_wifthWorkProfileAndTabbedViewOff_noAutolaunch()2484 public void testAutolaunch_singleTarget_wifthWorkProfileAndTabbedViewOff_noAutolaunch() { 2485 ResolverActivity.ENABLE_TABBED_VIEW = false; 2486 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2487 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10); 2488 when( 2489 ChooserActivityOverrideData 2490 .getInstance() 2491 .resolverListController 2492 .getResolversForIntent( 2493 Mockito.anyBoolean(), 2494 Mockito.anyBoolean(), 2495 Mockito.anyBoolean(), 2496 Mockito.isA(List.class))) 2497 .thenReturn(new ArrayList<>(personalResolvedComponentInfos)); 2498 Intent sendIntent = createSendTextIntent(); 2499 sendIntent.setType(TEST_MIME_TYPE); 2500 ResolveInfo[] chosen = new ResolveInfo[1]; 2501 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 2502 chosen[0] = targetInfo.getResolveInfo(); 2503 return true; 2504 }; 2505 waitForIdle(); 2506 2507 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2508 waitForIdle(); 2509 2510 assertTrue(chosen[0] == null); 2511 } 2512 2513 @Test testAutolaunch_singleTarget_noWorkProfile_autolaunch()2514 public void testAutolaunch_singleTarget_noWorkProfile_autolaunch() { 2515 ResolverActivity.ENABLE_TABBED_VIEW = false; 2516 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2517 createResolvedComponentsForTest(1); 2518 when( 2519 ChooserActivityOverrideData 2520 .getInstance() 2521 .resolverListController 2522 .getResolversForIntent( 2523 Mockito.anyBoolean(), 2524 Mockito.anyBoolean(), 2525 Mockito.anyBoolean(), 2526 Mockito.isA(List.class))) 2527 .thenReturn(new ArrayList<>(personalResolvedComponentInfos)); 2528 Intent sendIntent = createSendTextIntent(); 2529 sendIntent.setType(TEST_MIME_TYPE); 2530 ResolveInfo[] chosen = new ResolveInfo[1]; 2531 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 2532 chosen[0] = targetInfo.getResolveInfo(); 2533 return true; 2534 }; 2535 waitForIdle(); 2536 2537 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2538 waitForIdle(); 2539 2540 assertThat(chosen[0], is(personalResolvedComponentInfos.get(0).getResolveInfoAt(0))); 2541 } 2542 2543 @Test testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch()2544 public void testWorkTab_onePersonalTarget_emptyStateOnWorkTarget_autolaunch() { 2545 // enable the work tab feature flag 2546 ResolverActivity.ENABLE_TABBED_VIEW = true; 2547 markWorkProfileUserAvailable(); 2548 int workProfileTargets = 4; 2549 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2550 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10); 2551 List<ResolvedComponentInfo> workResolvedComponentInfos = 2552 createResolvedComponentsForTest(workProfileTargets); 2553 ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false; 2554 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2555 Intent sendIntent = createSendTextIntent(); 2556 ResolveInfo[] chosen = new ResolveInfo[1]; 2557 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 2558 chosen[0] = targetInfo.getResolveInfo(); 2559 return true; 2560 }; 2561 2562 mActivityRule.launchActivity(sendIntent); 2563 waitForIdle(); 2564 2565 assertThat(chosen[0], is(personalResolvedComponentInfos.get(1).getResolveInfoAt(0))); 2566 } 2567 2568 @Test testOneInitialIntent_noAutolaunch()2569 public void testOneInitialIntent_noAutolaunch() { 2570 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2571 createResolvedComponentsForTest(1); 2572 when( 2573 ChooserActivityOverrideData 2574 .getInstance() 2575 .resolverListController 2576 .getResolversForIntent( 2577 Mockito.anyBoolean(), 2578 Mockito.anyBoolean(), 2579 Mockito.anyBoolean(), 2580 Mockito.isA(List.class))) 2581 .thenReturn(new ArrayList<>(personalResolvedComponentInfos)); 2582 Intent chooserIntent = createChooserIntent(createSendTextIntent(), 2583 new Intent[] {new Intent("action.fake")}); 2584 ResolveInfo[] chosen = new ResolveInfo[1]; 2585 ChooserActivityOverrideData.getInstance().onSafelyStartCallback = targetInfo -> { 2586 chosen[0] = targetInfo.getResolveInfo(); 2587 return true; 2588 }; 2589 ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class); 2590 ResolveInfo ri = createFakeResolveInfo(); 2591 when( 2592 ChooserActivityOverrideData 2593 .getInstance().packageManager 2594 .resolveActivity(any(Intent.class), anyInt())) 2595 .thenReturn(ri); 2596 waitForIdle(); 2597 2598 IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent); 2599 waitForIdle(); 2600 2601 assertNull(chosen[0]); 2602 assertThat(activity 2603 .getPersonalListAdapter().getCallerTargetCount(), is(1)); 2604 } 2605 2606 @Test testWorkTab_withInitialIntents_workTabDoesNotIncludePersonalInitialIntents()2607 public void testWorkTab_withInitialIntents_workTabDoesNotIncludePersonalInitialIntents() { 2608 // enable the work tab feature flag 2609 ResolverActivity.ENABLE_TABBED_VIEW = true; 2610 markWorkProfileUserAvailable(); 2611 int workProfileTargets = 1; 2612 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2613 createResolvedComponentsForTestWithOtherProfile(2, /* userId */ 10); 2614 List<ResolvedComponentInfo> workResolvedComponentInfos = 2615 createResolvedComponentsForTest(workProfileTargets); 2616 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2617 Intent[] initialIntents = { 2618 new Intent("action.fake1"), 2619 new Intent("action.fake2") 2620 }; 2621 Intent chooserIntent = createChooserIntent(createSendTextIntent(), initialIntents); 2622 ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class); 2623 when( 2624 ChooserActivityOverrideData 2625 .getInstance() 2626 .packageManager 2627 .resolveActivity(any(Intent.class), anyInt())) 2628 .thenReturn(createFakeResolveInfo()); 2629 waitForIdle(); 2630 2631 IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent); 2632 waitForIdle(); 2633 2634 assertThat(activity.getPersonalListAdapter().getCallerTargetCount(), is(2)); 2635 assertThat(activity.getWorkListAdapter().getCallerTargetCount(), is(0)); 2636 } 2637 2638 @Test testWorkTab_xProfileIntentsDisabled_personalToWork_nonSendIntent_emptyStateShown()2639 public void testWorkTab_xProfileIntentsDisabled_personalToWork_nonSendIntent_emptyStateShown() { 2640 // enable the work tab feature flag 2641 ResolverActivity.ENABLE_TABBED_VIEW = true; 2642 markWorkProfileUserAvailable(); 2643 int workProfileTargets = 4; 2644 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2645 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 2646 List<ResolvedComponentInfo> workResolvedComponentInfos = 2647 createResolvedComponentsForTest(workProfileTargets); 2648 ChooserActivityOverrideData.getInstance().hasCrossProfileIntents = false; 2649 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2650 Intent[] initialIntents = { 2651 new Intent("action.fake1"), 2652 new Intent("action.fake2") 2653 }; 2654 Intent chooserIntent = createChooserIntent(new Intent(), initialIntents); 2655 ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class); 2656 when( 2657 ChooserActivityOverrideData 2658 .getInstance() 2659 .packageManager 2660 .resolveActivity(any(Intent.class), anyInt())) 2661 .thenReturn(createFakeResolveInfo()); 2662 2663 mActivityRule.launchActivity(chooserIntent); 2664 waitForIdle(); 2665 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2666 waitForIdle(); 2667 onView(withIdFromRuntimeResource("contentPanel")) 2668 .perform(swipeUp()); 2669 2670 onView(withTextFromRuntimeResource("resolver_cross_profile_blocked")) 2671 .check(matches(isDisplayed())); 2672 } 2673 2674 @Test testWorkTab_noWorkAppsAvailable_nonSendIntent_emptyStateShown()2675 public void testWorkTab_noWorkAppsAvailable_nonSendIntent_emptyStateShown() { 2676 // enable the work tab feature flag 2677 ResolverActivity.ENABLE_TABBED_VIEW = true; 2678 markWorkProfileUserAvailable(); 2679 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2680 createResolvedComponentsForTest(3); 2681 List<ResolvedComponentInfo> workResolvedComponentInfos = 2682 createResolvedComponentsForTest(0); 2683 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2684 Intent[] initialIntents = { 2685 new Intent("action.fake1"), 2686 new Intent("action.fake2") 2687 }; 2688 Intent chooserIntent = createChooserIntent(new Intent(), initialIntents); 2689 ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class); 2690 when( 2691 ChooserActivityOverrideData 2692 .getInstance() 2693 .packageManager 2694 .resolveActivity(any(Intent.class), anyInt())) 2695 .thenReturn(createFakeResolveInfo()); 2696 2697 mActivityRule.launchActivity(chooserIntent); 2698 waitForIdle(); 2699 onView(withIdFromRuntimeResource("contentPanel")) 2700 .perform(swipeUp()); 2701 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2702 waitForIdle(); 2703 2704 onView(withTextFromRuntimeResource("resolver_no_work_apps_available")) 2705 .check(matches(isDisplayed())); 2706 } 2707 2708 @Test testDeduplicateCallerTargetRankedTarget()2709 public void testDeduplicateCallerTargetRankedTarget() { 2710 // Create 4 ranked app targets. 2711 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2712 createResolvedComponentsForTest(4); 2713 when(ChooserActivityOverrideData.getInstance().resolverListController.getResolversForIntent( 2714 Mockito.anyBoolean(), 2715 Mockito.anyBoolean(), 2716 Mockito.anyBoolean(), 2717 Mockito.isA(List.class))) 2718 .thenReturn(new ArrayList<>(personalResolvedComponentInfos)); 2719 // Create caller target which is duplicate with one of app targets 2720 Intent chooserIntent = createChooserIntent(createSendTextIntent(), 2721 new Intent[] {new Intent("action.fake")}); 2722 ChooserActivityOverrideData.getInstance().packageManager = mock(PackageManager.class); 2723 ResolveInfo ri = ResolverDataProvider.createResolveInfo(0, 2724 UserHandle.USER_CURRENT); 2725 when( 2726 ChooserActivityOverrideData 2727 .getInstance() 2728 .packageManager 2729 .resolveActivity(any(Intent.class), anyInt())) 2730 .thenReturn(ri); 2731 waitForIdle(); 2732 2733 IChooserWrapper activity = (IChooserWrapper) mActivityRule.launchActivity(chooserIntent); 2734 waitForIdle(); 2735 2736 // Total 4 targets (1 caller target, 3 ranked targets) 2737 assertThat(activity.getAdapter().getCount(), is(4)); 2738 assertThat(activity.getAdapter().getCallerTargetCount(), is(1)); 2739 assertThat(activity.getAdapter().getRankedTargetCount(), is(3)); 2740 } 2741 2742 @Test testWorkTab_selectingWorkTabWithPausedWorkProfile_directShareTargetsNotQueried()2743 public void testWorkTab_selectingWorkTabWithPausedWorkProfile_directShareTargetsNotQueried() { 2744 // enable the work tab feature flag 2745 ResolverActivity.ENABLE_TABBED_VIEW = true; 2746 markWorkProfileUserAvailable(); 2747 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2748 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 2749 List<ResolvedComponentInfo> workResolvedComponentInfos = 2750 createResolvedComponentsForTest(3); 2751 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2752 ChooserActivityOverrideData.getInstance().isQuietModeEnabled = true; 2753 boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false }; 2754 ChooserActivityOverrideData.getInstance().onQueryDirectShareTargets = 2755 chooserListAdapter -> { 2756 isQueryDirectShareCalledOnWorkProfile[0] = 2757 (chooserListAdapter.getUserHandle().getIdentifier() == 10); 2758 return null; 2759 }; 2760 Intent sendIntent = createSendTextIntent(); 2761 sendIntent.setType(TEST_MIME_TYPE); 2762 2763 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2764 waitForIdle(); 2765 onView(withIdFromRuntimeResource("contentPanel")) 2766 .perform(swipeUp()); 2767 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2768 waitForIdle(); 2769 2770 assertFalse("Direct share targets were queried on a paused work profile", 2771 isQueryDirectShareCalledOnWorkProfile[0]); 2772 } 2773 2774 @Test testWorkTab_selectingWorkTabWithNotRunningWorkUser_directShareTargetsNotQueried()2775 public void testWorkTab_selectingWorkTabWithNotRunningWorkUser_directShareTargetsNotQueried() { 2776 // enable the work tab feature flag 2777 ResolverActivity.ENABLE_TABBED_VIEW = true; 2778 markWorkProfileUserAvailable(); 2779 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2780 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 2781 List<ResolvedComponentInfo> workResolvedComponentInfos = 2782 createResolvedComponentsForTest(3); 2783 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2784 ChooserActivityOverrideData.getInstance().isWorkProfileUserRunning = false; 2785 boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false }; 2786 ChooserActivityOverrideData.getInstance().onQueryDirectShareTargets = 2787 chooserListAdapter -> { 2788 isQueryDirectShareCalledOnWorkProfile[0] = 2789 (chooserListAdapter.getUserHandle().getIdentifier() == 10); 2790 return null; 2791 }; 2792 Intent sendIntent = createSendTextIntent(); 2793 sendIntent.setType(TEST_MIME_TYPE); 2794 2795 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2796 waitForIdle(); 2797 onView(withIdFromRuntimeResource("contentPanel")) 2798 .perform(swipeUp()); 2799 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2800 waitForIdle(); 2801 2802 assertFalse("Direct share targets were queried on a locked work profile user", 2803 isQueryDirectShareCalledOnWorkProfile[0]); 2804 } 2805 2806 @Test testWorkTab_workUserNotRunning_workTargetsShown()2807 public void testWorkTab_workUserNotRunning_workTargetsShown() { 2808 // enable the work tab feature flag 2809 ResolverActivity.ENABLE_TABBED_VIEW = true; 2810 markWorkProfileUserAvailable(); 2811 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2812 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 2813 List<ResolvedComponentInfo> workResolvedComponentInfos = 2814 createResolvedComponentsForTest(3); 2815 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2816 Intent sendIntent = createSendTextIntent(); 2817 sendIntent.setType(TEST_MIME_TYPE); 2818 ChooserActivityOverrideData.getInstance().isWorkProfileUserRunning = false; 2819 2820 final ChooserActivity activity = 2821 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2822 final IChooserWrapper wrapper = (IChooserWrapper) activity; 2823 waitForIdle(); 2824 onView(withIdFromRuntimeResource("contentPanel")).perform(swipeUp()); 2825 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2826 waitForIdle(); 2827 2828 assertEquals(3, wrapper.getWorkListAdapter().getCount()); 2829 } 2830 2831 @Test testWorkTab_selectingWorkTabWithLockedWorkUser_directShareTargetsNotQueried()2832 public void testWorkTab_selectingWorkTabWithLockedWorkUser_directShareTargetsNotQueried() { 2833 // enable the work tab feature flag 2834 ResolverActivity.ENABLE_TABBED_VIEW = true; 2835 markWorkProfileUserAvailable(); 2836 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2837 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 2838 List<ResolvedComponentInfo> workResolvedComponentInfos = 2839 createResolvedComponentsForTest(3); 2840 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2841 ChooserActivityOverrideData.getInstance().isWorkProfileUserUnlocked = false; 2842 boolean[] isQueryDirectShareCalledOnWorkProfile = new boolean[] { false }; 2843 ChooserActivityOverrideData.getInstance().onQueryDirectShareTargets = 2844 chooserListAdapter -> { 2845 isQueryDirectShareCalledOnWorkProfile[0] = 2846 (chooserListAdapter.getUserHandle().getIdentifier() == 10); 2847 return null; 2848 }; 2849 Intent sendIntent = createSendTextIntent(); 2850 sendIntent.setType(TEST_MIME_TYPE); 2851 2852 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2853 waitForIdle(); 2854 onView(withIdFromRuntimeResource("contentPanel")) 2855 .perform(swipeUp()); 2856 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2857 waitForIdle(); 2858 2859 assertFalse("Direct share targets were queried on a locked work profile user", 2860 isQueryDirectShareCalledOnWorkProfile[0]); 2861 } 2862 2863 @Test testWorkTab_workUserLocked_workTargetsShown()2864 public void testWorkTab_workUserLocked_workTargetsShown() { 2865 // enable the work tab feature flag 2866 ResolverActivity.ENABLE_TABBED_VIEW = true; 2867 markWorkProfileUserAvailable(); 2868 List<ResolvedComponentInfo> personalResolvedComponentInfos = 2869 createResolvedComponentsForTestWithOtherProfile(3, /* userId */ 10); 2870 List<ResolvedComponentInfo> workResolvedComponentInfos = 2871 createResolvedComponentsForTest(3); 2872 setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos); 2873 Intent sendIntent = createSendTextIntent(); 2874 sendIntent.setType(TEST_MIME_TYPE); 2875 ChooserActivityOverrideData.getInstance().isWorkProfileUserUnlocked = false; 2876 2877 final ChooserActivity activity = 2878 mActivityRule.launchActivity(Intent.createChooser(sendIntent, "work tab test")); 2879 final IChooserWrapper wrapper = (IChooserWrapper) activity; 2880 waitForIdle(); 2881 onView(withIdFromRuntimeResource("contentPanel")) 2882 .perform(swipeUp()); 2883 onView(withTextFromRuntimeResource("resolver_work_tab")).perform(click()); 2884 waitForIdle(); 2885 2886 assertEquals(3, wrapper.getWorkListAdapter().getCount()); 2887 } 2888 createChooserIntent(Intent intent, Intent[] initialIntents)2889 private Intent createChooserIntent(Intent intent, Intent[] initialIntents) { 2890 Intent chooserIntent = new Intent(); 2891 chooserIntent.setAction(Intent.ACTION_CHOOSER); 2892 chooserIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending"); 2893 chooserIntent.putExtra(Intent.EXTRA_TITLE, "some title"); 2894 chooserIntent.putExtra(Intent.EXTRA_INTENT, intent); 2895 chooserIntent.setType("text/plain"); 2896 if (initialIntents != null) { 2897 chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, initialIntents); 2898 } 2899 return chooserIntent; 2900 } 2901 createFakeResolveInfo()2902 private ResolveInfo createFakeResolveInfo() { 2903 ResolveInfo ri = new ResolveInfo(); 2904 ri.activityInfo = new ActivityInfo(); 2905 ri.activityInfo.name = "FakeActivityName"; 2906 ri.activityInfo.packageName = "fake.package.name"; 2907 ri.activityInfo.applicationInfo = new ApplicationInfo(); 2908 ri.activityInfo.applicationInfo.packageName = "fake.package.name"; 2909 return ri; 2910 } 2911 createSendTextIntent()2912 private Intent createSendTextIntent() { 2913 Intent sendIntent = new Intent(); 2914 sendIntent.setAction(Intent.ACTION_SEND); 2915 sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending"); 2916 sendIntent.setType("text/plain"); 2917 return sendIntent; 2918 } 2919 createSendImageIntent(Uri imageThumbnail)2920 private Intent createSendImageIntent(Uri imageThumbnail) { 2921 Intent sendIntent = new Intent(); 2922 sendIntent.setAction(Intent.ACTION_SEND); 2923 sendIntent.putExtra(Intent.EXTRA_STREAM, imageThumbnail); 2924 sendIntent.setType("image/png"); 2925 if (imageThumbnail != null) { 2926 ClipData.Item clipItem = new ClipData.Item(imageThumbnail); 2927 sendIntent.setClipData(new ClipData("Clip Label", new String[]{"image/png"}, clipItem)); 2928 } 2929 2930 return sendIntent; 2931 } 2932 createSendTextIntentWithPreview(String title, Uri imageThumbnail)2933 private Intent createSendTextIntentWithPreview(String title, Uri imageThumbnail) { 2934 Intent sendIntent = new Intent(); 2935 sendIntent.setAction(Intent.ACTION_SEND); 2936 sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending"); 2937 sendIntent.putExtra(Intent.EXTRA_TITLE, title); 2938 if (imageThumbnail != null) { 2939 ClipData.Item clipItem = new ClipData.Item(imageThumbnail); 2940 sendIntent.setClipData(new ClipData("Clip Label", new String[]{"image/png"}, clipItem)); 2941 } 2942 2943 return sendIntent; 2944 } 2945 createSendUriIntentWithPreview(ArrayList<Uri> uris)2946 private Intent createSendUriIntentWithPreview(ArrayList<Uri> uris) { 2947 Intent sendIntent = new Intent(); 2948 2949 if (uris.size() > 1) { 2950 sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE); 2951 sendIntent.putExtra(Intent.EXTRA_STREAM, uris); 2952 } else { 2953 sendIntent.setAction(Intent.ACTION_SEND); 2954 sendIntent.putExtra(Intent.EXTRA_STREAM, uris.get(0)); 2955 } 2956 2957 return sendIntent; 2958 } 2959 createViewTextIntent()2960 private Intent createViewTextIntent() { 2961 Intent viewIntent = new Intent(); 2962 viewIntent.setAction(Intent.ACTION_VIEW); 2963 viewIntent.putExtra(Intent.EXTRA_TEXT, "testing intent viewing"); 2964 return viewIntent; 2965 } 2966 createResolvedComponentsForTest(int numberOfResults)2967 private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) { 2968 List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults); 2969 for (int i = 0; i < numberOfResults; i++) { 2970 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i)); 2971 } 2972 return infoList; 2973 } 2974 createResolvedComponentsForTestWithOtherProfile( int numberOfResults)2975 private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile( 2976 int numberOfResults) { 2977 List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults); 2978 for (int i = 0; i < numberOfResults; i++) { 2979 if (i == 0) { 2980 infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i)); 2981 } else { 2982 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i)); 2983 } 2984 } 2985 return infoList; 2986 } 2987 createResolvedComponentsForTestWithOtherProfile( int numberOfResults, int userId)2988 private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile( 2989 int numberOfResults, int userId) { 2990 List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults); 2991 for (int i = 0; i < numberOfResults; i++) { 2992 if (i == 0) { 2993 infoList.add( 2994 ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId)); 2995 } else { 2996 infoList.add(ResolverDataProvider.createResolvedComponentInfo(i)); 2997 } 2998 } 2999 return infoList; 3000 } 3001 createResolvedComponentsForTestWithUserId( int numberOfResults, int userId)3002 private List<ResolvedComponentInfo> createResolvedComponentsForTestWithUserId( 3003 int numberOfResults, int userId) { 3004 List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults); 3005 for (int i = 0; i < numberOfResults; i++) { 3006 infoList.add(ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId)); 3007 } 3008 return infoList; 3009 } 3010 createDirectShareTargets(int numberOfResults, String packageName)3011 private List<ChooserTarget> createDirectShareTargets(int numberOfResults, String packageName) { 3012 Icon icon = Icon.createWithBitmap(createBitmap()); 3013 String testTitle = "testTitle"; 3014 List<ChooserTarget> targets = new ArrayList<>(); 3015 for (int i = 0; i < numberOfResults; i++) { 3016 ComponentName componentName; 3017 if (packageName.isEmpty()) { 3018 componentName = ResolverDataProvider.createComponentName(i); 3019 } else { 3020 componentName = new ComponentName(packageName, packageName + ".class"); 3021 } 3022 ChooserTarget tempTarget = new ChooserTarget( 3023 testTitle + i, 3024 icon, 3025 (float) (1 - ((i + 1) / 10.0)), 3026 componentName, 3027 null); 3028 targets.add(tempTarget); 3029 } 3030 return targets; 3031 } 3032 waitForIdle()3033 private void waitForIdle() { 3034 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 3035 } 3036 createBitmap()3037 private Bitmap createBitmap() { 3038 int width = 200; 3039 int height = 200; 3040 Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 3041 Canvas canvas = new Canvas(bitmap); 3042 3043 Paint paint = new Paint(); 3044 paint.setColor(Color.RED); 3045 paint.setStyle(Paint.Style.FILL); 3046 canvas.drawPaint(paint); 3047 3048 paint.setColor(Color.WHITE); 3049 paint.setAntiAlias(true); 3050 paint.setTextSize(14.f); 3051 paint.setTextAlign(Paint.Align.CENTER); 3052 canvas.drawText("Hi!", (width / 2.f), (height / 2.f), paint); 3053 3054 return bitmap; 3055 } 3056 createShortcuts(Context context)3057 private List<ShareShortcutInfo> createShortcuts(Context context) { 3058 Intent testIntent = new Intent("TestIntent"); 3059 3060 List<ShareShortcutInfo> shortcuts = new ArrayList<>(); 3061 shortcuts.add(new ShareShortcutInfo( 3062 new ShortcutInfo.Builder(context, "shortcut1") 3063 .setIntent(testIntent).setShortLabel("label1").setRank(3).build(), // 0 2 3064 new ComponentName("package1", "class1"))); 3065 shortcuts.add(new ShareShortcutInfo( 3066 new ShortcutInfo.Builder(context, "shortcut2") 3067 .setIntent(testIntent).setShortLabel("label2").setRank(7).build(), // 1 3 3068 new ComponentName("package2", "class2"))); 3069 shortcuts.add(new ShareShortcutInfo( 3070 new ShortcutInfo.Builder(context, "shortcut3") 3071 .setIntent(testIntent).setShortLabel("label3").setRank(1).build(), // 2 0 3072 new ComponentName("package3", "class3"))); 3073 shortcuts.add(new ShareShortcutInfo( 3074 new ShortcutInfo.Builder(context, "shortcut4") 3075 .setIntent(testIntent).setShortLabel("label4").setRank(3).build(), // 3 2 3076 new ComponentName("package4", "class4"))); 3077 3078 return shortcuts; 3079 } 3080 assertCorrectShortcutToChooserTargetConversion(List<ShareShortcutInfo> shortcuts, List<ChooserTarget> chooserTargets, int[] expectedOrder, float[] expectedScores)3081 private void assertCorrectShortcutToChooserTargetConversion(List<ShareShortcutInfo> shortcuts, 3082 List<ChooserTarget> chooserTargets, int[] expectedOrder, float[] expectedScores) { 3083 assertEquals(expectedOrder.length, chooserTargets.size()); 3084 for (int i = 0; i < chooserTargets.size(); i++) { 3085 ChooserTarget ct = chooserTargets.get(i); 3086 ShortcutInfo si = shortcuts.get(expectedOrder[i]).getShortcutInfo(); 3087 ComponentName cn = shortcuts.get(expectedOrder[i]).getTargetComponent(); 3088 3089 assertEquals(si.getId(), ct.getIntentExtras().getString(Intent.EXTRA_SHORTCUT_ID)); 3090 assertEquals(si.getShortLabel(), ct.getTitle()); 3091 assertThat(Math.abs(expectedScores[i] - ct.getScore()) < 0.000001, is(true)); 3092 assertEquals(cn.flattenToString(), ct.getComponentName().flattenToString()); 3093 } 3094 } 3095 3096 private void markWorkProfileUserAvailable() { 3097 ChooserActivityOverrideData.getInstance().workProfileUserHandle = UserHandle.of(10); 3098 } 3099 3100 private void setupResolverControllers( 3101 List<ResolvedComponentInfo> personalResolvedComponentInfos, 3102 List<ResolvedComponentInfo> workResolvedComponentInfos) { 3103 when( 3104 ChooserActivityOverrideData 3105 .getInstance() 3106 .resolverListController 3107 .getResolversForIntent( 3108 Mockito.anyBoolean(), 3109 Mockito.anyBoolean(), 3110 Mockito.anyBoolean(), 3111 Mockito.isA(List.class))) 3112 .thenReturn(new ArrayList<>(personalResolvedComponentInfos)); 3113 when( 3114 ChooserActivityOverrideData 3115 .getInstance() 3116 .workResolverListController 3117 .getResolversForIntent( 3118 Mockito.anyBoolean(), 3119 Mockito.anyBoolean(), 3120 Mockito.anyBoolean(), 3121 Mockito.isA(List.class))) 3122 .thenReturn(new ArrayList<>(workResolvedComponentInfos)); 3123 when( 3124 ChooserActivityOverrideData 3125 .getInstance() 3126 .workResolverListController 3127 .getResolversForIntentAsUser( 3128 Mockito.anyBoolean(), 3129 Mockito.anyBoolean(), 3130 Mockito.anyBoolean(), 3131 Mockito.isA(List.class), 3132 eq(UserHandle.SYSTEM))) 3133 .thenReturn(new ArrayList<>(personalResolvedComponentInfos)); 3134 } 3135 3136 private Matcher<View> withIdFromRuntimeResource(String id) { 3137 return withId(getRuntimeResourceId(id, "id")); 3138 } 3139 3140 private Matcher<View> withTextFromRuntimeResource(String id) { 3141 return withText(getRuntimeResourceId(id, "string")); 3142 } 3143 3144 private static GridRecyclerSpanCountMatcher withGridColumnCount(int columnCount) { 3145 return new GridRecyclerSpanCountMatcher(Matchers.is(columnCount)); 3146 } 3147 3148 private static class GridRecyclerSpanCountMatcher extends 3149 BoundedDiagnosingMatcher<View, RecyclerView> { 3150 3151 private final Matcher<Integer> mIntegerMatcher; 3152 3153 private GridRecyclerSpanCountMatcher(Matcher<Integer> integerMatcher) { 3154 super(RecyclerView.class); 3155 this.mIntegerMatcher = integerMatcher; 3156 } 3157 3158 @Override 3159 protected void describeMoreTo(Description description) { 3160 description.appendText("RecyclerView grid layout span count to match: "); 3161 this.mIntegerMatcher.describeTo(description); 3162 } 3163 3164 @Override 3165 protected boolean matchesSafely(RecyclerView view, Description mismatchDescription) { 3166 int spanCount = ((GridLayoutManager) view.getLayoutManager()).getSpanCount(); 3167 if (this.mIntegerMatcher.matches(spanCount)) { 3168 return true; 3169 } else { 3170 mismatchDescription.appendText("RecyclerView grid layout span count was ") 3171 .appendValue(spanCount); 3172 return false; 3173 } 3174 } 3175 } 3176 3177 private void givenAppTargets(int appCount) { 3178 List<ResolvedComponentInfo> resolvedComponentInfos = 3179 createResolvedComponentsForTest(appCount); 3180 when( 3181 ChooserActivityOverrideData 3182 .getInstance() 3183 .resolverListController 3184 .getResolversForIntent( 3185 Mockito.anyBoolean(), 3186 Mockito.anyBoolean(), 3187 Mockito.anyBoolean(), 3188 Mockito.isA(List.class))) 3189 .thenReturn(resolvedComponentInfos); 3190 } 3191 3192 private void updateMaxTargetsPerRowResource(int targetsPerRow) { 3193 ChooserActivityOverrideData.getInstance().resources = Mockito.spy( 3194 InstrumentationRegistry.getInstrumentation().getContext().getResources()); 3195 when( 3196 ChooserActivityOverrideData 3197 .getInstance() 3198 .resources 3199 .getInteger(R.integer.config_chooser_max_targets_per_row)) 3200 .thenReturn(targetsPerRow); 3201 } 3202 3203 // ChooserWrapperActivity inherits from the framework ChooserActivity, so if the framework 3204 // resources have been updated since the framework was last built/pushed, the inherited behavior 3205 // (which is the focus of our testing) will still be implemented in terms of the old resource 3206 // IDs; then when we try to assert those IDs in tests (e.g. `onView(withText(R.string.foo))`), 3207 // the expected values won't match. The tests can instead call this method (with the same 3208 // general semantics as Resources#getIdentifier() e.g. `getRuntimeResourceId("foo", "string")`) 3209 // to refer to the resource by that name in the runtime chooser, regardless of whether the 3210 // framework code on the device is up-to-date. 3211 // TODO: is there a better way to do this? (Other than abandoning inheritance-based DI wrapper?) 3212 private int getRuntimeResourceId(String name, String defType) { 3213 int id = -1; 3214 if (ChooserActivityOverrideData.getInstance().resources != null) { 3215 id = ChooserActivityOverrideData.getInstance().resources.getIdentifier( 3216 name, defType, "android"); 3217 } else { 3218 id = mActivityRule.getActivity().getResources().getIdentifier(name, defType, "android"); 3219 } 3220 assertThat(id, greaterThan(0)); 3221 3222 return id; 3223 } 3224 } 3225