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