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