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