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