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