diff options
29 files changed, 2991 insertions, 651 deletions
@@ -34,6 +34,7 @@ java_defaults { strict_updatability_linting: false, extra_check_modules: ["SystemUILintChecker"], warning_checks: ["MissingApacheLicenseDetector"], + baseline_filename: "lint-baseline.xml", }, } diff --git a/aconfig/FeatureFlags.aconfig b/aconfig/FeatureFlags.aconfig index 02f1c872..4d787ea2 100644 --- a/aconfig/FeatureFlags.aconfig +++ b/aconfig/FeatureFlags.aconfig @@ -42,3 +42,13 @@ flag { description: "Enable private profile support" bug: "328029692" } + +flag { + name: "refine_system_actions" + namespace: "intentresolver" + description: "This flag enables sending system actions to the caller refinement flow" + bug: "331206205" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/java/res/drawable/resolver_profile_tab_bg.xml b/java/res/drawable/resolver_profile_tab_bg.xml index 8bb23a53..97f3b7e2 100644 --- a/java/res/drawable/resolver_profile_tab_bg.xml +++ b/java/res/drawable/resolver_profile_tab_bg.xml @@ -25,7 +25,7 @@ </item> <item> - <selector android:enterFadeDuration="100"> + <selector> <item android:state_selected="false"> <shape android:shape="rectangle"> <corners android:radius="12dp" /> diff --git a/java/res/layout/chooser_grid_preview_file.xml b/java/res/layout/chooser_grid_preview_file.xml index 90832d23..4e8cf7ba 100644 --- a/java/res/layout/chooser_grid_preview_file.xml +++ b/java/res/layout/chooser_grid_preview_file.xml @@ -26,14 +26,6 @@ android:orientation="vertical" android:background="?androidprv:attr/materialColorSurfaceContainer"> - <ViewStub - android:id="@+id/chooser_headline_row_stub" - android:layout="@layout/chooser_headline_row" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingHorizontal="@dimen/chooser_edge_margin_normal" - android:layout_marginBottom="@dimen/chooser_view_spacing" /> - <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/java/res/layout/chooser_grid_preview_files_text.xml b/java/res/layout/chooser_grid_preview_files_text.xml index e7747496..2756e800 100644 --- a/java/res/layout/chooser_grid_preview_files_text.xml +++ b/java/res/layout/chooser_grid_preview_files_text.xml @@ -25,14 +25,6 @@ android:orientation="vertical" android:background="?androidprv:attr/materialColorSurfaceContainer"> - <ViewStub - android:id="@+id/chooser_headline_row_stub" - android:layout="@layout/chooser_headline_row" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingHorizontal="@dimen/chooser_edge_margin_normal" - android:layout_marginBottom="@dimen/chooser_view_spacing" /> - <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/java/res/layout/chooser_grid_preview_text.xml b/java/res/layout/chooser_grid_preview_text.xml index f3045c34..ee54c0ae 100644 --- a/java/res/layout/chooser_grid_preview_text.xml +++ b/java/res/layout/chooser_grid_preview_text.xml @@ -27,14 +27,6 @@ android:orientation="vertical" android:background="?androidprv:attr/materialColorSurfaceContainer"> - <ViewStub - android:id="@+id/chooser_headline_row_stub" - android:layout="@layout/chooser_headline_row" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:paddingHorizontal="@dimen/chooser_edge_margin_normal" - android:layout_marginBottom="@dimen/chooser_view_spacing" /> - <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content" @@ -122,4 +114,3 @@ <include layout="@layout/chooser_action_row" /> </LinearLayout> - diff --git a/java/res/values-en-rCA/strings.xml b/java/res/values-en-rCA/strings.xml index 21fcd488..537606cc 100644 --- a/java/res/values-en-rCA/strings.xml +++ b/java/res/values-en-rCA/strings.xml @@ -90,8 +90,7 @@ <string name="resolver_switch_on_work" msgid="8678893259344318807">"Unpause"</string> <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"No work apps"</string> <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"No personal apps"</string> - <!-- no translation found for resolver_no_private_apps_available (4164473548027417456) --> - <skip /> + <string name="resolver_no_private_apps_available" msgid="4164473548027417456">"No private apps"</string> <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string> <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string> <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Use personal browser"</string> diff --git a/java/res/values-en-rXC/strings.xml b/java/res/values-en-rXC/strings.xml index 08787d02..70cafe8e 100644 --- a/java/res/values-en-rXC/strings.xml +++ b/java/res/values-en-rXC/strings.xml @@ -90,8 +90,7 @@ <string name="resolver_switch_on_work" msgid="8678893259344318807">"Unpause"</string> <string name="resolver_no_work_apps_available" msgid="6139818641313189903">"No work apps"</string> <string name="resolver_no_personal_apps_available" msgid="8479033344701050767">"No personal apps"</string> - <!-- no translation found for resolver_no_private_apps_available (4164473548027417456) --> - <skip /> + <string name="resolver_no_private_apps_available" msgid="4164473548027417456">"No private apps"</string> <string name="miniresolver_open_in_personal" msgid="8397377137465016575">"Open <xliff:g id="APP">%s</xliff:g> in your personal profile?"</string> <string name="miniresolver_open_in_work" msgid="4271638122142624693">"Open <xliff:g id="APP">%s</xliff:g> in your work profile?"</string> <string name="miniresolver_use_personal_browser" msgid="1428911732509069292">"Use personal browser"</string> diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java index b712edf4..56873302 100644 --- a/java/src/com/android/intentresolver/ChooserActivity.java +++ b/java/src/com/android/intentresolver/ChooserActivity.java @@ -98,6 +98,7 @@ import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.ViewPager; +import com.android.intentresolver.ChooserRefinementManager.RefinementType; import com.android.intentresolver.chooser.DisplayResolveInfo; import com.android.intentresolver.chooser.MultiDisplayResolveInfo; import com.android.intentresolver.chooser.TargetInfo; @@ -508,6 +509,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements mRequest.getInitialIntents(), mMaxTargetsPerRow); + maybeDisableRecentsScreenshot(mProfiles, mProfileAvailability); + if (!configureContentView(mTargetDataLoader)) { mPersonalPackageMonitor = createPackageMonitor( mChooserMultiProfilePagerAdapter.getPersonalListAdapter()); @@ -567,23 +570,52 @@ public class ChooserActivity extends Hilt_ChooserActivity implements mRefinementManager = new ViewModelProvider(this).get(ChooserRefinementManager.class); mRefinementManager.getRefinementCompletion().observe(this, completion -> { if (completion.consume()) { - TargetInfo targetInfo = completion.getTargetInfo(); - // targetInfo is non-null if the refinement process was successful. - if (targetInfo != null) { - maybeRemoveSharedText(targetInfo); - - // We already block suspended targets from going to refinement, and we probably - // can't recover a Chooser session if that's the reason the refined target fails - // to launch now. Fire-and-forget the refined launch; ignore the return value - // and just make sure the Sharesheet session gets cleaned up regardless. - final ResolveInfo ri = targetInfo.getResolveInfo(); - final Intent intent1 = targetInfo.getResolvedIntent(); - - safelyStartActivity(targetInfo); - - // Rely on the ActivityManager to pop up a dialog regarding app suspension - // and return false - targetInfo.isSuspended(); + if (completion.getRefinedIntent() == null) { + finish(); + return; + } + + // Prepare to regenerate our "system actions" based on the refined intent. + // TODO: optimize if needed. `TARGET_INFO` cases don't require a new action + // factory at all. And if we break up `ChooserActionFactory`, we could avoid + // resolving a new editor intent unless we're handling an `EDIT_ACTION`. + ChooserActionFactory refinedActionFactory = + createChooserActionFactory(completion.getRefinedIntent()); + switch (completion.getType()) { + case TARGET_INFO: { + TargetInfo refinedTarget = completion + .getOriginalTargetInfo() + .tryToCloneWithAppliedRefinement( + completion.getRefinedIntent()); + if (refinedTarget == null) { + Log.e(TAG, "Failed to apply refinement to any matching source intent"); + } else { + maybeRemoveSharedText(refinedTarget); + + // We already block suspended targets from going to refinement, and we + // probably can't recover a Chooser session if that's the reason the + // refined target fails to launch now. Fire-and-forget the refined + // launch, and make sure Sharesheet gets cleaned up regardless of the + // outcome of that launch.launch; ignore + + safelyStartActivity(refinedTarget); + } + } + break; + + case COPY_ACTION: { + if (refinedActionFactory.getCopyButtonRunnable() != null) { + refinedActionFactory.getCopyButtonRunnable().run(); + } + } + break; + + case EDIT_ACTION: { + if (refinedActionFactory.getEditButtonRunnable() != null) { + refinedActionFactory.getEditButtonRunnable().run(); + } + } + break; } finish(); @@ -596,12 +628,15 @@ public class ChooserActivity extends Hilt_ChooserActivity implements mRequest.getTargetIntent(), mRequest.getAdditionalContentUri(), mChooserServiceFeatureFlags.chooserPayloadToggling()); + ChooserContentPreviewUi.ActionFactory actionFactory = + decorateActionFactoryWithRefinement( + createChooserActionFactory(mRequest.getTargetIntent())); mChooserContentPreviewUi = new ChooserContentPreviewUi( getCoroutineScope(getLifecycle()), previewViewModel.getPreviewDataProvider(), mRequest.getTargetIntent(), previewViewModel.getImageLoader(), - createChooserActionFactory(), + actionFactory, createModifyShareActionFactory(), mEnterTransitionAnimationDelegate, new HeadlineGeneratorImpl(this), @@ -609,9 +644,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements mRequest.getMetadataText(), mChooserServiceFeatureFlags.chooserPayloadToggling()); updateStickyContentPreview(); - if (shouldShowStickyContentPreview() - || mChooserMultiProfilePagerAdapter - .getCurrentRootAdapter().getSystemRowCount() != 0) { + if (shouldShowStickyContentPreview()) { getEventLog().logActionShareWithPreview( mChooserContentPreviewUi.getPreferredContentPreview()); } @@ -646,6 +679,20 @@ public class ChooserActivity extends Hilt_ChooserActivity implements Tracer.INSTANCE.markLaunched(); } + private void maybeDisableRecentsScreenshot( + ProfileHelper profileHelper, ProfileAvailability profileAvailability) { + for (Profile profile : profileHelper.getProfiles()) { + if (profile.getType() == Profile.Type.PRIVATE) { + if (profileAvailability.isAvailable(profile)) { + // Show blank screen in Recent preview if private profile is available + // to not leak its presence. + setRecentsScreenshotEnabled(false); + } + return; + } + } + } + private void onChooserRequestChanged(ChooserRequest chooserRequest) { // intentional reference comparison if (mRequest == chooserRequest) { @@ -1569,7 +1616,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements getResources(), getLayoutInflater(), parent, - findViewById(R.id.chooser_headline_row_container)); + requireViewById(R.id.chooser_headline_row_container)); if (layout != null) { adjustPreviewWidth(getResources().getConfiguration().orientation, layout); @@ -1977,16 +2024,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements context, new ChooserGridAdapter.ChooserActivityDelegate() { @Override - public boolean shouldShowTabs() { - return mProfiles.getWorkProfilePresent(); - } - - @Override - public View buildContentPreview(ViewGroup parent) { - return createContentPreviewView(parent); - } - - @Override public void onTargetSelected(int itemIndex) { startSelected(itemIndex, false, true); } @@ -2106,10 +2143,67 @@ public class ChooserActivity extends Hilt_ChooserActivity implements return PreviewViewModel.Companion.getFactory(); } - private ChooserActionFactory createChooserActionFactory() { + private ChooserContentPreviewUi.ActionFactory decorateActionFactoryWithRefinement( + ChooserContentPreviewUi.ActionFactory originalFactory) { + if (!mFeatureFlags.refineSystemActions()) { + return originalFactory; + } + + return new ChooserContentPreviewUi.ActionFactory() { + @Override + @Nullable + public Runnable getEditButtonRunnable() { + return () -> { + if (!mRefinementManager.maybeHandleSelection( + RefinementType.EDIT_ACTION, + List.of(mRequest.getTargetIntent()), + null, + mRequest.getRefinementIntentSender(), + getApplication(), + getMainThreadHandler())) { + originalFactory.getEditButtonRunnable().run(); + } + }; + } + + @Override + @Nullable + public Runnable getCopyButtonRunnable() { + return () -> { + if (!mRefinementManager.maybeHandleSelection( + RefinementType.COPY_ACTION, + List.of(mRequest.getTargetIntent()), + null, + mRequest.getRefinementIntentSender(), + getApplication(), + getMainThreadHandler())) { + originalFactory.getCopyButtonRunnable().run(); + } + }; + } + + @Override + public List<ActionRow.Action> createCustomActions() { + return originalFactory.createCustomActions(); + } + + @Override + @Nullable + public ActionRow.Action getModifyShareAction() { + return originalFactory.getModifyShareAction(); + } + + @Override + public Consumer<Boolean> getExcludeSharedTextAction() { + return originalFactory.getExcludeSharedTextAction(); + } + }; + } + + private ChooserActionFactory createChooserActionFactory(Intent targetIntent) { return new ChooserActionFactory( this, - mRequest.getTargetIntent(), + targetIntent, mRequest.getLaunchedFromPackage(), mRequest.getChooserActions(), mImageEditor, @@ -2229,8 +2323,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements int top, int bottom, RecyclerView recyclerView, ChooserGridAdapter gridAdapter) { int offset = mSystemWindowInsets != null ? mSystemWindowInsets.bottom : 0; - int rowsToShow = gridAdapter.getSystemRowCount() - + gridAdapter.getServiceTargetRowCount() + int rowsToShow = gridAdapter.getServiceTargetRowCount() + gridAdapter.getCallerAndRankedTargetRowCount(); // then this is most likely not a SEND_* action, so check diff --git a/java/src/com/android/intentresolver/ChooserRefinementManager.java b/java/src/com/android/intentresolver/ChooserRefinementManager.java index 79484240..5c828a8e 100644 --- a/java/src/com/android/intentresolver/ChooserRefinementManager.java +++ b/java/src/com/android/intentresolver/ChooserRefinementManager.java @@ -59,22 +59,58 @@ public final class ChooserRefinementManager extends ViewModel { private boolean mConfigurationChangeInProgress = false; /** + * The types of selections that may be sent to refinement. + * + * The refinement flow results in a refined intent, but the interpretation of that intent + * depends on the type of selection that prompted the refinement. + */ + public enum RefinementType { + TARGET_INFO, // A normal (`TargetInfo`) target. + + // System actions derived from the refined intent (from `ChooserActionFactory`). + COPY_ACTION, + EDIT_ACTION + } + + /** * A token for the completion of a refinement process that can be consumed exactly once. */ public static class RefinementCompletion { private TargetInfo mTargetInfo; private boolean mConsumed; + private final RefinementType mType; - RefinementCompletion(TargetInfo targetInfo) { - mTargetInfo = targetInfo; + @Nullable + private final TargetInfo mOriginalTargetInfo; + + @Nullable + private final Intent mRefinedIntent; + + RefinementCompletion( + @Nullable RefinementType type, + @Nullable TargetInfo originalTargetInfo, + @Nullable Intent refinedIntent) { + mType = type; + mOriginalTargetInfo = originalTargetInfo; + mRefinedIntent = refinedIntent; + } + + public RefinementType getType() { + return mType; + } + + @Nullable + public TargetInfo getOriginalTargetInfo() { + return mOriginalTargetInfo; } /** * @return The output of the completed refinement process. Null if the process was aborted * or failed. */ - public TargetInfo getTargetInfo() { - return mTargetInfo; + @Nullable + public Intent getRefinedIntent() { + return mRefinedIntent; } /** @@ -105,14 +141,11 @@ public final class ChooserRefinementManager extends ViewModel { * @return true if the selection should wait for a now-started refinement flow, or false if it * can proceed by the default (non-refinement) logic. */ - public boolean maybeHandleSelection(TargetInfo selectedTarget, - IntentSender refinementIntentSender, Application application, Handler mainHandler) { - if (refinementIntentSender == null) { - return false; - } - if (selectedTarget.getAllSourceIntents().isEmpty()) { - return false; - } + public boolean maybeHandleSelection( + TargetInfo selectedTarget, + IntentSender refinementIntentSender, + Application application, + Handler mainHandler) { if (selectedTarget.isSuspended()) { // We expect all launches to fail for this target, so don't make the user go through the // refinement flow first. Besides, the default (non-refinement) handling displays a @@ -121,27 +154,57 @@ public final class ChooserRefinementManager extends ViewModel { return false; } + return maybeHandleSelection( + RefinementType.TARGET_INFO, + selectedTarget.getAllSourceIntents(), + selectedTarget, + refinementIntentSender, + application, + mainHandler); + } + + /** + * Delegate the user's selection of targets (with one or more matching {@code sourceIntents} to + * the refinement flow, if possible. + * @return true if the selection should wait for a now-started refinement flow, or false if it + * can proceed by the default (non-refinement) logic. + */ + public boolean maybeHandleSelection( + RefinementType refinementType, + List<Intent> sourceIntents, + @Nullable TargetInfo originalTargetInfo, + IntentSender refinementIntentSender, + Application application, + Handler mainHandler) { + // Our requests have a non-null `originalTargetInfo` in exactly the + // cases when `refinementType == TARGET_INFO`. + assert ((originalTargetInfo == null) == (refinementType == RefinementType.TARGET_INFO)); + + if (refinementIntentSender == null) { + return false; + } + if (sourceIntents.isEmpty()) { + return false; + } + destroy(); // Terminate any prior sessions. mRefinementResultReceiver = new RefinementResultReceiver( + refinementType, refinedIntent -> { destroy(); - - TargetInfo refinedTarget = - selectedTarget.tryToCloneWithAppliedRefinement(refinedIntent); - if (refinedTarget != null) { - mRefinementCompletion.setValue(new RefinementCompletion(refinedTarget)); - } else { - Log.e(TAG, "Failed to apply refinement to any matching source intent"); - mRefinementCompletion.setValue(new RefinementCompletion(null)); - } + mRefinementCompletion.setValue( + new RefinementCompletion( + refinementType, originalTargetInfo, refinedIntent)); }, () -> { destroy(); - mRefinementCompletion.setValue(new RefinementCompletion(null)); + mRefinementCompletion.setValue( + new RefinementCompletion( + refinementType, originalTargetInfo, null)); }, mainHandler); - Intent refinementRequest = makeRefinementRequest(mRefinementResultReceiver, selectedTarget); + Intent refinementRequest = makeRefinementRequest(mRefinementResultReceiver, sourceIntents); try { refinementIntentSender.sendIntent(application, 0, refinementRequest, null, null); return true; @@ -167,7 +230,7 @@ public final class ChooserRefinementManager extends ViewModel { // into a valid Chooser session, so we'll treat it as a cancellation instead. Log.w(TAG, "Chooser resumed while awaiting refinement result; aborting"); destroy(); - mRefinementCompletion.setValue(new RefinementCompletion(null)); + mRefinementCompletion.setValue(new RefinementCompletion(null, null, null)); } } } @@ -187,9 +250,8 @@ public final class ChooserRefinementManager extends ViewModel { } private static Intent makeRefinementRequest( - RefinementResultReceiver resultReceiver, TargetInfo originalTarget) { + RefinementResultReceiver resultReceiver, List<Intent> sourceIntents) { final Intent fillIn = new Intent(); - final List<Intent> sourceIntents = originalTarget.getAllSourceIntents(); fillIn.putExtra(Intent.EXTRA_INTENT, sourceIntents.get(0)); final int sourceIntentCount = sourceIntents.size(); if (sourceIntentCount > 1) { @@ -204,16 +266,19 @@ public final class ChooserRefinementManager extends ViewModel { } private static class RefinementResultReceiver extends ResultReceiver { + private final RefinementType mType; private final Consumer<Intent> mOnSelectionRefined; private final Runnable mOnRefinementCancelled; private boolean mDestroyed; RefinementResultReceiver( + RefinementType type, Consumer<Intent> onSelectionRefined, Runnable onRefinementCancelled, Handler handler) { super(handler); + mType = type; mOnSelectionRefined = onSelectionRefined; mOnRefinementCancelled = onRefinementCancelled; } diff --git a/java/src/com/android/intentresolver/ResolverListAdapter.java b/java/src/com/android/intentresolver/ResolverListAdapter.java index 9843cf8d..2a8fcfa4 100644 --- a/java/src/com/android/intentresolver/ResolverListAdapter.java +++ b/java/src/com/android/intentresolver/ResolverListAdapter.java @@ -840,7 +840,7 @@ public class ResolverListAdapter extends BaseAdapter { userHandle); } - public final List<Intent> getIntents() { + public List<Intent> getIntents() { // TODO: immutable copy? return mIntents; } diff --git a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java index 4cb30341..4b955c49 100644 --- a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java @@ -97,7 +97,6 @@ public final class ChooserContentPreviewUi { @VisibleForTesting final ContentPreviewUi mContentPreviewUi; private final Supplier</*@Nullable*/ActionRow.Action> mModifyShareActionFactory; - @Nullable private View mHeadlineParent; public ChooserContentPreviewUi( @@ -226,15 +225,12 @@ public final class ChooserContentPreviewUi { Resources resources, LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent) { + View headlineViewParent) { ViewGroup layout = mContentPreviewUi.display(resources, layoutInflater, parent, headlineViewParent); - mHeadlineParent = headlineViewParent == null ? layout : headlineViewParent; - if (mHeadlineParent != null) { - ContentPreviewUi.displayModifyShareAction( - mHeadlineParent, mModifyShareActionFactory.get()); - } + mHeadlineParent = headlineViewParent; + ContentPreviewUi.displayModifyShareAction(mHeadlineParent, mModifyShareActionFactory.get()); return layout; } @@ -242,10 +238,7 @@ public final class ChooserContentPreviewUi { * Update Modify Share Action, if it is inflated. */ public void updateModifyShareAction() { - if (mHeadlineParent != null) { - ContentPreviewUi.displayModifyShareAction( - mHeadlineParent, mModifyShareActionFactory.get()); - } + ContentPreviewUi.displayModifyShareAction(mHeadlineParent, mModifyShareActionFactory.get()); } private static TextContentPreviewUi createTextPreview( diff --git a/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java index 71d5fc0b..8eaf3568 100644 --- a/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java @@ -48,7 +48,7 @@ public abstract class ContentPreviewUi { Resources resources, LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent); + View headlineViewParent); protected static void updateViewWithImage(ImageView imageView, Bitmap image) { if (image == null) { diff --git a/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java index d127d929..1749c6f7 100644 --- a/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java @@ -76,7 +76,7 @@ class FileContentPreviewUi extends ContentPreviewUi { Resources resources, LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent) { + View headlineViewParent) { return displayInternal(resources, layoutInflater, parent, headlineViewParent); } @@ -84,12 +84,9 @@ class FileContentPreviewUi extends ContentPreviewUi { Resources resources, LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent) { + View headlineViewParent) { mContentPreview = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_file, parent, false); - if (headlineViewParent == null) { - headlineViewParent = mContentPreview; - } inflateHeadline(headlineViewParent); displayHeadline(headlineViewParent, mHeadlineGenerator.getFilesHeadline(mFileCount)); diff --git a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java index 0367e9d5..b50f5bc8 100644 --- a/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java @@ -108,7 +108,7 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi { Resources resources, LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent) { + View headlineViewParent) { return displayInternal(layoutInflater, parent, headlineViewParent); } @@ -133,10 +133,10 @@ class FilesPlusTextContentPreviewUi extends ContentPreviewUi { private ViewGroup displayInternal( LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent) { + View headlineViewParent) { mContentPreviewView = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_files_text, parent, false); - mHeadliveView = headlineViewParent == null ? mContentPreviewView : headlineViewParent; + mHeadliveView = headlineViewParent; inflateHeadline(mHeadliveView); final ActionRow actionRow = diff --git a/java/src/com/android/intentresolver/contentpreview/NoContextPreviewUi.kt b/java/src/com/android/intentresolver/contentpreview/NoContextPreviewUi.kt index 31a7006c..924e6499 100644 --- a/java/src/com/android/intentresolver/contentpreview/NoContextPreviewUi.kt +++ b/java/src/com/android/intentresolver/contentpreview/NoContextPreviewUi.kt @@ -29,7 +29,7 @@ internal class NoContextPreviewUi(private val type: Int) : ContentPreviewUi() { resources: Resources?, layoutInflater: LayoutInflater?, parent: ViewGroup?, - headlineViewParent: View?, + headlineViewParent: View, ): ViewGroup? { Log.e(TAG, "Unexpected content preview type: $type") return null diff --git a/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt b/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt index 5fce711c..57a51239 100644 --- a/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt +++ b/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt @@ -45,21 +45,17 @@ class ShareouselContentPreviewUi : ContentPreviewUi() { resources: Resources, layoutInflater: LayoutInflater, parent: ViewGroup, - headlineViewParent: View?, + headlineViewParent: View, ): ViewGroup = displayInternal(parent, headlineViewParent) - private fun displayInternal(parent: ViewGroup, headlineViewParent: View?): ViewGroup { - if (headlineViewParent != null) { - inflateHeadline(headlineViewParent) - } + private fun displayInternal(parent: ViewGroup, headlineViewParent: View): ViewGroup { + inflateHeadline(headlineViewParent) return ComposeView(parent.context).apply { setContent { val vm: ChooserViewModel = viewModel() val viewModel: ShareouselViewModel = vm.shareouselViewModel - headlineViewParent?.let { - LaunchedEffect(viewModel) { bindHeader(viewModel, headlineViewParent) } - } + LaunchedEffect(viewModel) { bindHeader(viewModel, headlineViewParent) } MaterialTheme( colorScheme = diff --git a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java index a7ae81b0..ae7ddcd9 100644 --- a/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java @@ -82,19 +82,16 @@ class TextContentPreviewUi extends ContentPreviewUi { Resources resources, LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent) { + View headlineViewParent) { return displayInternal(layoutInflater, parent, headlineViewParent); } private ViewGroup displayInternal( LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent) { + View headlineViewParent) { ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_text, parent, false); - if (headlineViewParent == null) { - headlineViewParent = contentPreviewLayout; - } inflateHeadline(headlineViewParent); final ActionRow actionRow = diff --git a/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java index 77252112..88311016 100644 --- a/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java +++ b/java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java @@ -54,7 +54,6 @@ class UnifiedContentPreviewUi extends ContentPreviewUi { private List<FileInfo> mFiles; @Nullable private ViewGroup mContentPreviewView; - @Nullable private View mHeadlineView; UnifiedContentPreviewUi( @@ -93,7 +92,7 @@ class UnifiedContentPreviewUi extends ContentPreviewUi { Resources resources, LayoutInflater layoutInflater, ViewGroup parent, - @Nullable View headlineViewParent) { + View headlineViewParent) { return displayInternal(layoutInflater, parent, headlineViewParent); } @@ -109,10 +108,10 @@ class UnifiedContentPreviewUi extends ContentPreviewUi { } private ViewGroup displayInternal( - LayoutInflater layoutInflater, ViewGroup parent, @Nullable View headlineViewParent) { + LayoutInflater layoutInflater, ViewGroup parent, View headlineViewParent) { mContentPreviewView = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_image, parent, false); - mHeadlineView = headlineViewParent == null ? mContentPreviewView : headlineViewParent; + mHeadlineView = headlineViewParent; inflateHeadline(mHeadlineView); final ActionRow actionRow = diff --git a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt index 0cb7306d..0a431c2a 100644 --- a/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt +++ b/java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt @@ -45,9 +45,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.RectangleShape import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.dimensionResource @@ -68,6 +66,7 @@ fun Shareousel(viewModel: ShareouselViewModel) { } else { Spacer( Modifier.height(dimensionResource(R.dimen.chooser_preview_image_height_tall) + 64.dp) + .background(MaterialTheme.colorScheme.surfaceContainer) ) } } @@ -130,12 +129,7 @@ private fun ShareouselCard(viewModel: ShareouselPreviewViewModel) { } ?: run { // TODO: look at ScrollableImagePreviewView.setLoading() - Box( - modifier = - Modifier.fillMaxHeight() - .aspectRatio(2f / 5f) - .border(1.dp, Color.Red, RectangleShape) - ) + Box(modifier = Modifier.fillMaxHeight().aspectRatio(2f / 5f)) } }, contentType = contentType, diff --git a/java/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProvider.java b/java/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProvider.java index e6d5d1c4..2b4a7ada 100644 --- a/java/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProvider.java +++ b/java/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProvider.java @@ -34,8 +34,8 @@ import com.android.intentresolver.shared.model.User; import java.util.List; /** - * Empty state provider that does not allow cross profile sharing, it will return a blocker - * in case if the profile of the current tab is not the same as the profile of the calling app. + * Empty state provider that informs about a lack of cross profile sharing. It will return + * an empty state in case there are no intents which can be forwarded to another profile. */ public class NoCrossProfileEmptyStateProvider implements EmptyStateProvider { @@ -79,7 +79,8 @@ public class NoCrossProfileEmptyStateProvider implements EmptyStateProvider { // Allow access to the tab when launched by the same user as the tab owner // or when there is at least one target which is permitted for cross-profile. - if (launchedAsSameUser || anyCrossProfileAllowedIntents(adapter, tabOwnerHandle)) { + if (launchedAsSameUser || anyCrossProfileAllowedIntents(adapter, + /* source = */ launchedAs.getHandle())) { return null; } diff --git a/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java b/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java index cda69b9e..7cf9d2e9 100644 --- a/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java +++ b/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java @@ -66,15 +66,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView. * out of `ChooserGridAdapter` altogether. */ public interface ChooserActivityDelegate { - /** @return whether we're showing a tabbed (multi-profile) UI. */ - boolean shouldShowTabs(); - - /** - * @return a content preview {@link View} that's appropriate for the caller's share - * content, constructed for display in the provided {@code parent} group. - */ - View buildContentPreview(ViewGroup parent); - /** Notify the client that the item with the selected {@code itemIndex} was selected. */ void onTargetSelected(int itemIndex); @@ -87,7 +78,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView. private static final int VIEW_TYPE_DIRECT_SHARE = 0; private static final int VIEW_TYPE_NORMAL = 1; - private static final int VIEW_TYPE_CONTENT_PREVIEW = 2; private static final int VIEW_TYPE_AZ_LABEL = 4; private static final int VIEW_TYPE_CALLER_AND_RANK = 5; private static final int VIEW_TYPE_FOOTER = 6; @@ -195,8 +185,7 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView. public int getRowCount() { return (int) ( - getSystemRowCount() - + getServiceTargetRowCount() + getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() + getAzLabelRowCount() + Math.ceil( @@ -205,14 +194,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView. ); } - /** - * Whether the "system" row of targets is displayed. - * This area includes the content preview (if present) and action row. - */ - public int getSystemRowCount() { - return 0; - } - public int getFooterRowCount() { return 1; } @@ -243,15 +224,13 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView. return -1; } - return getSystemRowCount() - + getServiceTargetRowCount() + return getServiceTargetRowCount() + getCallerAndRankedTargetRowCount(); } @Override public int getItemCount() { - return getSystemRowCount() - + getServiceTargetRowCount() + return getServiceTargetRowCount() + getCallerAndRankedTargetRowCount() + getAzLabelRowCount() + mChooserListAdapter.getAlphaTargetCount() @@ -262,12 +241,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView. @Override public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { switch (viewType) { - case VIEW_TYPE_CONTENT_PREVIEW: - return new ItemViewHolder( - mChooserActivityDelegate.buildContentPreview(parent), - viewType, - null, - null); case VIEW_TYPE_AZ_LABEL: return new ItemViewHolder( createAzLabelView(parent), @@ -338,10 +311,8 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView. @Override public int getItemViewType(int position) { - int count; - - int countSum = (count = getSystemRowCount()); - if (count > 0 && position < countSum) return VIEW_TYPE_CONTENT_PREVIEW; + int count = 0; + int countSum = count; countSum += (count = getServiceTargetRowCount()); if (count > 0 && position < countSum) return VIEW_TYPE_DIRECT_SHARE; @@ -538,8 +509,6 @@ public final class ChooserGridAdapter extends RecyclerView.Adapter<RecyclerView. } int getListPosition(int position) { - position -= getSystemRowCount(); - final int serviceCount = mChooserListAdapter.getServiceTargetCount(); final int serviceRows = (int) Math.ceil((float) serviceCount / mMaxTargetsPerRow); if (position < serviceRows) { diff --git a/lint-baseline.xml b/lint-baseline.xml new file mode 100644 index 00000000..c970b7a7 --- /dev/null +++ b/lint-baseline.xml @@ -0,0 +1,2425 @@ +<?xml version="1.0" encoding="UTF-8"?> +<issues format="6" by="lint 8.4.0-alpha08" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha08"> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="421" + column="21"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="431" + column="25"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="517" + column="21"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="526" + column="25"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="722" + column="17"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="733" + column="21"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainThreadHandler())) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1684" + column="17"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainThreadHandler().post(() -> {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="2199" + column="13"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" context.getMainExecutor()," + errorLine2=" ~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="192" + column="25"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" }, getApplicationContext().getMainExecutor());" + errorLine2=" ~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/IntentForwarderActivity.java" + line="161" + column="44"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="297" + column="21"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="307" + column="25"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="374" + column="17"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" getMainLooper()," + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="383" + column="21"/> + </issue> + + <issue + id="NonInjectedMainThread" + message="Replace with injected `@Main Executor`." + errorLine1=" runnable -> context.getMainThreadHandler().post(runnable));" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverListAdapter.java" + line="127" + column="37"/> + </issue> + + <issue + id="WrongCommentType" + message="This block comment looks like it was intended to be a javadoc comment" + errorLine1=" * {@link MultiProfilePagerAdapter.OnProfileSelectedListener}. The only apparent distinctions" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="821" + column="8"/> + </issue> + + <issue + id="CleanArchitectureDependencyViolation" + message="The ui layer may not depend on the data layer." + errorLine1="import com.android.intentresolver.data.model.ANDROID_APP_SCHEME" + errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ui/model/ActivityModel.kt" + line="23" + column="1"/> + </issue> + + <issue + id="CleanArchitectureDependencyViolation" + message="The ui layer may not depend on the data layer." + errorLine1="import com.android.intentresolver.data.model.ChooserRequest" + errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ui/viewmodel/ChooserRequestReader.kt" + line="45" + column="1"/> + </issue> + + <issue + id="CleanArchitectureDependencyViolation" + message="The ui layer may not depend on the data layer." + errorLine1="import com.android.intentresolver.data.model.ChooserRequest" + errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ui/viewmodel/ChooserViewModel.kt" + line="25" + column="1"/> + </issue> + + <issue + id="CleanArchitectureDependencyViolation" + message="The ui layer may not depend on the data layer." + errorLine1="import com.android.intentresolver.data.repository.ChooserRequestRepository" + errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ui/viewmodel/ChooserViewModel.kt" + line="26" + column="1"/> + </issue> + + <issue + id="CleanArchitectureDependencyViolation" + message="The ui layer may not depend on the data layer." + errorLine1="import com.android.intentresolver.data.repository.DevicePolicyResources" + errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ui/ProfilePagerResources.kt" + line="21" + column="1"/> + </issue> + + <issue + id="CleanArchitectureDependencyViolation" + message="The domain layer may not depend on the ui layer." + errorLine1="import com.android.intentresolver.ui.viewmodel.readAlternateIntents" + errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/update/SelectionChangeCallback.kt" + line="40" + column="1"/> + </issue> + + <issue + id="CleanArchitectureDependencyViolation" + message="The domain layer may not depend on the ui layer." + errorLine1="import com.android.intentresolver.ui.viewmodel.readChooserActions" + errorLine2="~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/contentpreview/payloadtoggle/domain/update/SelectionChangeCallback.kt" + line="41" + column="1"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" (UsageStatsManager) userContext.getSystemService(Context.USAGE_STATS_SERVICE));" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/model/AbstractResolverComparator.java" + line="136" + column="53"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" .getSystemService(AppPredictionManager::class.java)" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/shortcuts/AppPredictorFactory.kt" + line="66" + column="14"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" (UserManager) context.getSystemService(Context.USER_SERVICE);" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="289" + column="47"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" getContext().getSystemService(LauncherApps.class).pinShortcuts(" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java" + line="226" + column="22"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" List<ShortcutManager.ShareShortcutInfo> targets = contextAsUser.getSystemService(" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java" + line="233" + column="73"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" .getSystemService(ACTIVITY_SERVICE);" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java" + line="279" + column="18"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" context.getSystemService(ActivityManager::class.java)?.launcherLargeIconDensity" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/icons/DefaultTargetDataLoader.kt" + line="47" + column="21"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" return getSystemService(DevicePolicyManager.class).getResources().getString(" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/IntentForwarderActivity.java" + line="165" + column="16"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" return getSystemService(DevicePolicyManager.class).getResources().getString(" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/IntentForwarderActivity.java" + line="171" + column="16"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" return getSystemService(UserManager.class);" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/IntentForwarderActivity.java" + line="402" + column="20"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" LauncherApps launcherApps = context.getSystemService(LauncherApps.class);" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/icons/LoadDirectShareIconTask.java" + line="100" + column="49"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" return mContext.getSystemService(DevicePolicyManager.class).getResources().getString(" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProvider.java" + line="127" + column="29"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" return mContext.getSystemService(DevicePolicyManager.class).getResources().getString(" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProvider.java" + line="135" + column="29"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" (UserManager) mContext.getSystemService(Context.USER_SERVICE);" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverListAdapter.java" + line="503" + column="52"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" private val userManager = context.getSystemService(Context.USER_SERVICE) as UserManager" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt" + line="77" + column="39"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" selectedProfileContext.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager?" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt" + line="209" + column="36"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" final ActivityManager am = (ActivityManager) ctx.getSystemService(ACTIVITY_SERVICE);" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/SimpleIconFactory.java" + line="98" + column="62"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" return requireNotNull(context.getSystemService(serviceType.java))" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/data/repository/UserScopedService.kt" + line="65" + column="39"/> + </issue> + + <issue + id="NonInjectedService" + message="Use `@Inject` to get system-level service handles instead of `Context.getSystemService()`" + errorLine1=" String title = mContext.getSystemService(DevicePolicyManager.class)" + errorLine2=" ~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/emptystate/WorkProfilePausedEmptyStateProvider.java" + line="83" + column="33"/> + </issue> + + <issue + id="StaticSettingsProvider" + message="`@Inject` a GlobalSettings instead" + errorLine1=" return Settings.Global.getInt(getContentResolver()," + errorLine2=" ~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/IntentForwarderActivity.java" + line="280" + column="32"/> + </issue> + + <issue + id="StaticSettingsProvider" + message="`@Inject` a SecureSettings instead" + errorLine1=" return Settings.Secure.getString(resolver, name)" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/platform/PlatformSecureSettings.kt" + line="32" + column="32"/> + </issue> + + <issue + id="StaticSettingsProvider" + message="`@Inject` a SecureSettings instead" + errorLine1=" return runCatching { Settings.Secure.getInt(resolver, name) }.getOrNull()" + errorLine2=" ~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/platform/PlatformSecureSettings.kt" + line="36" + column="46"/> + </issue> + + <issue + id="StaticSettingsProvider" + message="`@Inject` a SecureSettings instead" + errorLine1=" return runCatching { Settings.Secure.getLong(resolver, name) }.getOrNull()" + errorLine2=" ~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/platform/PlatformSecureSettings.kt" + line="40" + column="46"/> + </issue> + + <issue + id="StaticSettingsProvider" + message="`@Inject` a SecureSettings instead" + errorLine1=" return runCatching { Settings.Secure.getFloat(resolver, name) }.getOrNull()" + errorLine2=" ~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/platform/PlatformSecureSettings.kt" + line="44" + column="46"/> + </issue> + + <issue + id="StaticSettingsProvider" + message="`@Inject` a SecureSettings instead" + errorLine1=" return Settings.Secure.getString(resolver, name)" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/SecureSettings.kt" + line="25" + column="32"/> + </issue> + + <issue + id="CanvasSize" + message="Calling `Canvas.getWidth()` is usually wrong; you should be calling `getWidth()` instead" + errorLine1=" int xPos = canvas.getWidth() / 2;" + errorLine2=" ~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/widget/RoundedRectImageView.java" + line="134" + column="24"/> + </issue> + + <issue + id="CanvasSize" + message="Calling `Canvas.getHeight()` is usually wrong; you should be calling `getHeight()` instead" + errorLine1=" int yPos = (int) ((canvas.getHeight() / 2.0f)" + errorLine2=" ~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/widget/RoundedRectImageView.java" + line="135" + column="32"/> + </issue> + + <issue + id="CustomViewStyleable" + message="By convention, the declare-styleable (`ResolverDrawerLayout_LayoutParams`) for a layout parameter class (`LayoutParams`) is expected to be the surrounding class (`ResolverDrawerLayout`) plus "`_Layout`", e.g. `ResolverDrawerLayout_Layout`. (Various editor features rely on this convention.)" + errorLine1=" R.styleable.ResolverDrawerLayout_LayoutParams);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/widget/ResolverDrawerLayout.java" + line="1222" + column="21"/> + </issue> + + <issue + id="InconsistentLayout" + message="The id "edit" in layout "image_preview_image_item" is missing from the following layout configurations: layout (present in layout-h480dp)" + errorLine1=" android:id="@+id/edit"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout-h480dp/image_preview_image_item.xml" + line="58" + column="9" + message="Occurrence in layout-h480dp"/> + </issue> + + <issue + id="MissingConstraints" + message="This view is not constrained vertically: at runtime it will jump to the top unless you add a vertical constraint" + errorLine1=" <TextView" + errorLine2=" ~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_headline_row.xml" + line="27" + column="6"/> + </issue> + + <issue + id="MissingConstraints" + message="This view is not constrained horizontally: at runtime it will jump to the left unless you add a horizontal constraint" + errorLine1=" <com.android.intentresolver.widget.RoundedRectImageView" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout-h480dp/image_preview_image_item.xml" + line="24" + column="6"/> + </issue> + + <issue + id="InflateParams" + message="Avoid passing `null` as the view root (needed to resolve layout parameters on the inflated layout's root element)" + errorLine1=" R.layout.resolver_different_item_header, null, false);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1197" + column="62"/> + </issue> + + <issue + id="InflateParams" + message="Avoid passing `null` as the view root (needed to resolve layout parameters on the inflated layout's root element)" + errorLine1=" ? (ViewGroup) inflater.inflate(R.layout.chooser_list_per_profile_wrap, null, false)" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/profiles/ChooserMultiProfilePagerAdapter.java" + line="123" + column="88"/> + </issue> + + <issue + id="InflateParams" + message="Avoid passing `null` as the view root (needed to resolve layout parameters on the inflated layout's root element)" + errorLine1=" : (ViewGroup) inflater.inflate(R.layout.chooser_list_per_profile, null, false);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/profiles/ChooserMultiProfilePagerAdapter.java" + line="124" + column="83"/> + </issue> + + <issue + id="InflateParams" + message="Avoid passing `null` as the view root (needed to resolve layout parameters on the inflated layout's root element)" + errorLine1=" R.layout.resolver_different_item_header, null, false);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="853" + column="62"/> + </issue> + + <issue + id="InflateParams" + message="Avoid passing `null` as the view root (needed to resolve layout parameters on the inflated layout's root element)" + errorLine1=" R.layout.resolver_list_per_profile, null, false)," + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/profiles/ResolverMultiProfilePagerAdapter.java" + line="80" + column="69"/> + </issue> + + <issue + id="ManifestOrder" + message="`<uses-sdk>` tag appears after `<application>` tag" + errorLine1=" <uses-sdk android:minSdkVersion="VanillaIceCream" android:targetSdkVersion="16"/>" + errorLine2=" ~~~~~~~~"> + <location + file="./out/soong/.intermediates/packages/modules/IntentResolver/IntentResolver-core/android_common/e18b8e8d84cb9f664aa09a397b08c165/manifest_fixer/AndroidManifest.xml" + line="22" + column="6"/> + </issue> + + <issue + id="MissingInflatedId" + message="`@layout/chooser_dialog` does not contain a declaration with id `title`" + errorLine1=" TextView title = v.findViewById(com.android.internal.R.id.title);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java" + line="133" + column="41"/> + </issue> + + <issue + id="MissingInflatedId" + message="`@layout/chooser_dialog` does not contain a declaration with id `icon`" + errorLine1=" ImageView icon = v.findViewById(com.android.internal.R.id.icon);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java" + line="134" + column="41"/> + </issue> + + <issue + id="MissingInflatedId" + message="`@layout/chooser_dialog` does not contain a declaration with id `listContainer`" + errorLine1=" RecyclerView rv = v.findViewById(com.android.internal.R.id.listContainer);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserTargetActionsDialogFragment.java" + line="135" + column="42"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="437" + column="42"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="559" + column="54"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" int count = mChooserMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="761" + column="54"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (mChooserMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile() != null) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="766" + column="46"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" final TargetInfo target = mChooserMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="771" + column="68"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter().getFilteredPosition() >= 0;" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="900" + column="50"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" .getActiveListAdapter().getFilteredItem()))" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="909" + column="38"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" int count = mChooserMultiProfilePagerAdapter.getActiveListAdapter().getCount();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1133" + column="54"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" TargetInfo target = mChooserMultiProfilePagerAdapter.getActiveListAdapter().getItem(i);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1136" + column="66"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (mChooserMultiProfilePagerAdapter.getActiveListAdapter() == null) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1155" + column="46"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1206" + column="50"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" int count = mChooserMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1217" + column="54"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1483" + column="42"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter().addServiceResults(" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1623" + column="50"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1699" + column="50"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" TargetInfo target = mChooserMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1724" + column="62"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1731" + column="58"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1801" + column="50"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getActiveListAdapter();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1838" + column="58"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getCurrentUserHandle());" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1886" + column="50"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mChooserMultiProfilePagerAdapter.getCurrentUserHandle());" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1914" + column="50"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" .getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="1981" + column="34"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (mChooserMultiProfilePagerAdapter.getCurrentUserHandle().equals(" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="2041" + column="46"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (listProfileUserHandle.equals(mChooserMultiProfilePagerAdapter.getCurrentUserHandle())) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="2288" + column="75"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (mChooserMultiProfilePagerAdapter.getActiveListAdapter() == adapter) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserActivity.java" + line="2351" + column="46"/> + </issue> + + <issue + id="VisibleForTests" + message="This class should only be accessed from tests or within private scope" + errorLine1=" final ViewHolder vh = (ViewHolder) v.getTag();" + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java" + line="414" + column="23"/> + </issue> + + <issue + id="VisibleForTests" + message="This class should only be accessed from tests or within private scope" + errorLine1=" final ViewHolder vh = (ViewHolder) v.getTag();" + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java" + line="414" + column="40"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" vh.text.setLines(2);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java" + line="415" + column="20"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" vh.text.setHorizontallyScrolling(false);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java" + line="416" + column="20"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" vh.text2.setVisibility(View.GONE);" + errorLine2=" ~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java" + line="417" + column="20"/> + </issue> + + <issue + id="VisibleForTests" + message="This class should only be accessed from tests or within private scope" + errorLine1=" private void resetViewHolder(ViewHolder holder) {" + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="432" + column="34"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.reset();" + errorLine2=" ~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="433" + column="16"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.itemView.setBackground(holder.defaultItemViewBackground);" + errorLine2=" ~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="434" + column="16"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.itemView.setBackground(holder.defaultItemViewBackground);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="434" + column="46"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ((BadgeTextView) holder.text).setBadgeDrawable(null);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="437" + column="37"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.text.setBackground(null);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="439" + column="16"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.text.setPaddingRelative(0, 0, 0, 0);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="440" + column="16"/> + </issue> + + <issue + id="VisibleForTests" + message="This class should only be accessed from tests or within private scope" + errorLine1=" private void updateContentDescription(ViewHolder holder, String description) {" + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="443" + column="43"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.itemView.setContentDescription(description);" + errorLine2=" ~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="444" + column="16"/> + </issue> + + <issue + id="VisibleForTests" + message="This class should only be accessed from tests or within private scope" + errorLine1=" private void bindPlaceholder(ViewHolder holder) {" + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="447" + column="34"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.itemView.setBackground(null);" + errorLine2=" ~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="448" + column="16"/> + </issue> + + <issue + id="VisibleForTests" + message="This class should only be accessed from tests or within private scope" + errorLine1=" private void bindGroupIndicator(ViewHolder holder, Drawable indicator) {" + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="451" + column="37"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ((BadgeTextView) holder.text).setBadgeDrawable(indicator);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="453" + column="37"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.text.setPaddingRelative(0, 0, /*end = */indicator.getIntrinsicWidth(), 0);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="455" + column="20"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.text.setBackground(indicator);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="456" + column="20"/> + </issue> + + <issue + id="VisibleForTests" + message="This class should only be accessed from tests or within private scope" + errorLine1=" private void bindPinnedIndicator(ViewHolder holder, Drawable indicator) {" + errorLine2=" ~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="460" + column="38"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.text.setPaddingRelative(/*start = */indicator.getIntrinsicWidth(), 0, 0, 0);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="461" + column="16"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" holder.text.setBackground(indicator);" + errorLine2=" ~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="462" + column="16"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" getPageAdapterForIndex(i).setAzLabelVisibility(!isCollapsed);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/profiles/ChooserMultiProfilePagerAdapter.java" + line="115" + column="13"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" getActiveListAdapter().notifyDataSetChanged();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/profiles/ChooserMultiProfilePagerAdapter.java" + line="135" + column="9"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" getPageAdapterForIndex(i).setFooterHeight(height);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/profiles/ChooserMultiProfilePagerAdapter.java" + line="150" + column="13"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ChooserGridAdapter adapter = getPageAdapterForIndex(i);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/profiles/ChooserMultiProfilePagerAdapter.java" + line="157" + column="42"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" /* instance_id = 3 */ mInstanceId.getId()," + errorLine2=" ~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/logging/EventLogImpl.java" + line="96" + column="51"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" /* instance_id = 3 */ mInstanceId.getId()," + errorLine2=" ~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/logging/EventLogImpl.java" + line="118" + column="51"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" /* instance_id = 3 */ mInstanceId.getId()," + errorLine2=" ~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/logging/EventLogImpl.java" + line="142" + column="51"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" /* instance_id = 3 */ mInstanceId.getId()," + errorLine2=" ~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/logging/EventLogImpl.java" + line="200" + column="51"/> + </issue> + + <issue + id="VisibleForTests" + message="This class should only be accessed from tests or within private scope" + errorLine1=" private final ResolverListAdapter.ViewHolder mWrappedViewHolder;" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ItemViewHolder.java" + line="36" + column="19"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mWrappedViewHolder = new ResolverListAdapter.ViewHolder(itemView);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ItemViewHolder.java" + line="46" + column="30"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="313" + column="35"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" && mMultiProfilePagerAdapter.getActiveListAdapter() != null) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="323" + column="46"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mMultiProfilePagerAdapter.getActiveListAdapter().onDestroy();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="324" + column="39"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" MetricsLogger.action(this, mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="415" + column="62"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="540" + column="35"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ResolverListAdapter currentListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="560" + column="76"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ResolveInfo ri = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="572" + column="52"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="582" + column="55"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mMultiProfilePagerAdapter.getActiveListAdapter().hasFilteredItem()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="596" + column="47"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" && mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredResolveList()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="627" + column="46"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" final int N = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="713" + column="57"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile() != null;" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="720" + column="51"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ResolveInfo r = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="729" + column="63"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" set[N] = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="737" + column="56"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" final int otherProfileMatch = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="739" + column="77"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="761" + column="51"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" .mResolverListController.setLastChosen(intent, filter, bestMatch);" + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="762" + column="58"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mMultiProfilePagerAdapter.getActiveListAdapter();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="868" + column="43"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" int count = mMultiProfilePagerAdapter.getActiveListAdapter().getCount();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1143" + column="47"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter().getItem(i);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1146" + column="59"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mMultiProfilePagerAdapter.getActiveListAdapter().getFilteredPosition() >= 0;" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1172" + column="43"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" .getActiveListAdapter().getFilteredItem()))" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1181" + column="42"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (!mMultiProfilePagerAdapter.getCurrentUserHandle().equals(getUser())) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1217" + column="40"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ri = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1233" + column="44"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" startActivityAsUser(in, mMultiProfilePagerAdapter.getCurrentUserHandle());" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1326" + column="59"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (mMultiProfilePagerAdapter.getActiveListAdapter() == null) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1334" + column="39"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" new ResolverListAdapter.ViewHolder(icon).bindIcon(otherProfileResolveInfo);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1399" + column="25"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" new ResolverListAdapter.ViewHolder(icon).bindIcon(otherProfileResolveInfo);" + errorLine2=" ~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1399" + column="66"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1472" + column="47"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" int count = mMultiProfilePagerAdapter.getActiveListAdapter().getUnfilteredCount();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1534" + column="47"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (mMultiProfilePagerAdapter.getActiveListAdapter().getOtherProfile() != null) {" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1539" + column="39"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" final TargetInfo target = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1544" + column="61"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ResolverListAdapter activeListAdapter = mMultiProfilePagerAdapter.getActiveListAdapter();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1687" + column="75"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" int filteredPosition = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1754" + column="58"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" if (mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1795" + column="43"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" ResolveInfo ri = mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1828" + column="56"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" final TargetInfo ti = ra.mMultiProfilePagerAdapter.getActiveListAdapter()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverActivity.java" + line="1896" + column="68"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" return mResolverListController.getScore(target);" + errorLine2=" ~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverListAdapter.java" + line="212" + column="40"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mResolverListController.addResolveListDedupe(currentResolveList," + errorLine2=" ~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverListAdapter.java" + line="329" + column="37"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mResolverListController.filterIneligibleActivities(currentResolveList, true);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverListAdapter.java" + line="362" + column="41"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" return mResolverListController.filterLowPriority(" + errorLine2=" ~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverListAdapter.java" + line="384" + column="40"/> + </issue> + + <issue + id="VisibleForTests" + message="This method should only be accessed from tests or within private scope" + errorLine1=" mLastChosen = mResolverListController.getLastChosen();" + errorLine2=" ~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ResolverListAdapter.java" + line="410" + column="55"/> + </issue> + + <issue + id="SupportAnnotationUsage" + message="This annotation does not apply for type java.lang.Object; expected int" + errorLine1=" @ContentPreviewType" + errorLine2=" ~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt" + line="230" + column="5"/> + </issue> + + <issue + id="ExpiredTargetSdkVersion" + message="Google Play requires that apps target API level 33 or higher." + errorLine1=" <uses-sdk android:minSdkVersion="VanillaIceCream" android:targetSdkVersion="16"/>" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="./out/soong/.intermediates/packages/modules/IntentResolver/IntentResolver-core/android_common/e18b8e8d84cb9f664aa09a397b08c165/manifest_fixer/AndroidManifest.xml" + line="22" + column="55"/> + </issue> + + <issue + id="BindServiceOnMainThread" + message="This method should be annotated with `@WorkerThread` because it calls unbindService" + errorLine1=" mContext.unbindService(mConnection);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/model/ResolverRankerServiceResolverComparator.java" + line="308" + column="13"/> + </issue> + + <issue + id="BindServiceOnMainThread" + message="This method should be annotated with `@WorkerThread` because it calls bindServiceAsUser" + errorLine1=" context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM);" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/model/ResolverRankerServiceResolverComparator.java" + line="333" + column="9"/> + </issue> + + <issue + id="NotifyDataSetChanged" + message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + errorLine1=" notifyDataSetChanged();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java" + line="139" + column="17"/> + </issue> + + <issue + id="NotifyDataSetChanged" + message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + errorLine1=" notifyDataSetChanged();" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/grid/ChooserGridAdapter.java" + line="145" + column="17"/> + </issue> + + <issue + id="NotifyDataSetChanged" + message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + errorLine1=" notifyDataSetChanged()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/widget/ScrollableActionRow.kt" + line="94" + column="13"/> + </issue> + + <issue + id="NotifyDataSetChanged" + message="It will always be more efficient to use more specific change events if you can. Rely on `notifyDataSetChanged` as a last resort." + errorLine1=" notifyDataSetChanged()" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt" + line="316" + column="13"/> + </issue> + + <issue + id="RegisterReceiverViaContext" + message="Register `BroadcastReceiver` using `BroadcastDispatcher` instead of `Context`" + errorLine1=" context.registerReceiverAsUser(" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/data/BroadcastSubscriber.kt" + line="63" + column="17"/> + </issue> + + <issue + id="RegisterReceiverViaContext" + message="Register `BroadcastReceiver` using `BroadcastDispatcher` instead of `Context`" + errorLine1=" context.registerReceiverAsUser(" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/WorkProfileAvailabilityManager.java" + line="74" + column="17"/> + </issue> + + <issue + id="SharedFlowCreation" + message="`MutableSharedFlow()` creates a new shared flow, which has poor performance characteristics" + errorLine1=" MutableSharedFlow<FileInfo>(replay = records.size).apply {" + errorLine2=" ~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt" + line="91" + column="9"/> + </issue> + + <issue + id="SharedFlowCreation" + message="`MutableSharedFlow()` creates a new shared flow, which has poor performance characteristics" + errorLine1=" val reportFlow = MutableSharedFlow<Any>(replay = 2)" + errorLine2=" ~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/widget/ScrollableImagePreviewView.kt" + line="660" + column="30"/> + </issue> + + <issue + id="SharedFlowCreation" + message="`MutableSharedFlow()` creates a new shared flow, which has poor performance characteristics" + errorLine1=" MutableSharedFlow<Array<DisplayResolveInfo>?>(" + errorLine2=" ~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt" + line="82" + column="9"/> + </issue> + + <issue + id="SharedFlowCreation" + message="`MutableSharedFlow()` creates a new shared flow, which has poor performance characteristics" + errorLine1=" MutableSharedFlow<ShortcutData?>(replay = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)" + errorLine2=" ~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt" + line="87" + column="9"/> + </issue> + + <issue + id="SlowUserIdQuery" + message="Use `UserTracker.getUserId()` instead of `ActivityManager.getCurrentUser()`" + errorLine1=" userHandle == UserHandle.of(ActivityManager.getCurrentUser())," + errorLine2=" ~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/shortcuts/ShortcutLoader.kt" + line="104" + column="53"/> + </issue> + + <issue + id="SlowUserInfoQuery" + message="Use `UserTracker.getUserInfo()` instead of `UserManager.getUserInfo()`" + errorLine1=" val originUserInfo = userManager.getUserInfo(contentUserHint)" + errorLine2=" ~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/IntentForwarding.kt" + line="51" + column="46"/> + </issue> + + <issue + id="SlowUserInfoQuery" + message="Use `UserTracker.getUserInfo()` instead of `UserManager.getUserInfo()`" + errorLine1=" withContext(backgroundDispatcher) { userManager.getUserInfo(user.identifier) }" + errorLine2=" ~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/data/repository/UserRepository.kt" + line="267" + column="61"/> + </issue> + + <issue + id="SoftwareBitmap" + message="Replace software bitmap with `Config.HARDWARE`" + errorLine1=" mBitmap = Bitmap.createBitmap(mMaxSize, mMaxSize, Bitmap.Config.ALPHA_8);" + errorLine2=" ~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/SimpleIconFactory.java" + line="172" + column="73"/> + </issue> + + <issue + id="SoftwareBitmap" + message="Replace software bitmap with `Config.HARDWARE`" + errorLine1=" bitmap.getHeight(), Bitmap.Config.ARGB_8888);" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/SimpleIconFactory.java" + line="297" + column="51"/> + </issue> + + <issue + id="SoftwareBitmap" + message="Replace software bitmap with `Config.HARDWARE`" + errorLine1=" Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/SimpleIconFactory.java" + line="343" + column="71"/> + </issue> + + <issue + id="ObsoleteLayoutParam" + message="Invalid layout param in a `LinearLayout`: `layout_alignParentTop`" + errorLine1=" android:layout_alignParentTop="true"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_scrollable_preview.xml" + line="99" + column="17"/> + </issue> + + <issue + id="ObsoleteLayoutParam" + message="Invalid layout param in a `LinearLayout`: `layout_centerHorizontal`" + errorLine1=" android:layout_centerHorizontal="true"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_scrollable_preview.xml" + line="100" + column="17"/> + </issue> + + <issue + id="StaticFieldLeak" + message="This field leaks a context object" + errorLine1=" protected final Context mContext;" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/icons/BaseLoadIconTask.java" + line="29" + column="5"/> + </issue> + + <issue + id="StaticFieldLeak" + message="This `AsyncTask` class should be static or leaks might occur (anonymous android.os.AsyncTask)" + errorLine1=" new AsyncTask<Void, Void, List<DisplayResolveInfo>>() {" + errorLine2=" ^"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/ChooserListAdapter.java" + line="488" + column="9"/> + </issue> + + <issue + id="StaticFieldLeak" + message="This field leaks a context object" + errorLine1=" private final Context mContext;" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/icons/LoadLabelTask.java" + line="32" + column="5"/> + </issue> + + <issue + id="UseCompoundDrawables" + message="This tag and its children can be replaced by one `<TextView/>` and a compound drawable" + errorLine1=" <LinearLayout" + errorLine2=" ~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_dialog.xml" + line="29" + column="6"/> + </issue> + + <issue + id="Overdraw" + message="Possible overdraw: Root element paints background `?androidprv:attr/materialColorSurfaceContainer` with a theme that also paints a background (inferred theme is `@android:style/Theme.Holo`)" + errorLine1=" android:background="?androidprv:attr/materialColorSurfaceContainer">" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_preview_file.xml" + line="27" + column="5"/> + </issue> + + <issue + id="Overdraw" + message="Possible overdraw: Root element paints background `?androidprv:attr/materialColorSurfaceContainer` with a theme that also paints a background (inferred theme is `@android:style/Theme.Holo`)" + errorLine1=" android:background="?androidprv:attr/materialColorSurfaceContainer">" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_preview_files_text.xml" + line="26" + column="5"/> + </issue> + + <issue + id="Overdraw" + message="Possible overdraw: Root element paints background `?androidprv:attr/materialColorSurfaceContainer` with a theme that also paints a background (inferred theme is `@android:style/Theme.Holo`)" + errorLine1=" android:background="?androidprv:attr/materialColorSurfaceContainer">" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_preview_image.xml" + line="27" + column="5"/> + </issue> + + <issue + id="Overdraw" + message="Possible overdraw: Root element paints background `?androidprv:attr/materialColorSurfaceContainer` with a theme that also paints a background (inferred theme is `@android:style/Theme.Holo`)" + errorLine1=" android:background="?androidprv:attr/materialColorSurfaceContainer">" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_preview_text.xml" + line="28" + column="5"/> + </issue> + + <issue + id="RedundantNamespace" + message="This namespace declaration is redundant" + errorLine1=" <vector xmlns:android="http://schemas.android.com/apk/res/android"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/drawable/chooser_direct_share_icon_placeholder.xml" + line="20" + column="17"/> + </issue> + + <issue + id="RedundantNamespace" + message="This namespace declaration is redundant" + errorLine1=" xmlns:aapt="http://schemas.android.com/aapt"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/drawable/chooser_direct_share_icon_placeholder.xml" + line="21" + column="17"/> + </issue> + + <issue + id="RedundantNamespace" + message="This namespace declaration is redundant" + errorLine1=" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/resolve_list_item.xml" + line="40" + column="19"/> + </issue> + + <issue + id="RedundantNamespace" + message="This namespace declaration is redundant" + errorLine1=" xmlns:android="http://schemas.android.com/apk/res/android"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/resolver_list_per_profile.xml" + line="23" + column="9"/> + </issue> + + <issue + id="UnusedNamespace" + message="Unused namespace declaration xmlns:android; already declared on the root element" + errorLine1=" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/resolve_list_item.xml" + line="40" + column="19"/> + </issue> + + <issue + id="UnusedNamespace" + message="Unused namespace declaration xmlns:android; already declared on the root element" + errorLine1=" xmlns:android="http://schemas.android.com/apk/res/android"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/resolver_list_per_profile.xml" + line="23" + column="9"/> + </issue> + + <issue + id="TypographyEllipsis" + message="Replace "..." with ellipsis character (…, &#8230;) ?" + errorLine1=" <string name="whichApplication" msgid="2309561338625872614">"... በመጠቀም ድርጊቱን አጠናቅ"</string>" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/values-am/strings.xml" + line="19" + column="65"/> + </issue> + + <issue + id="TypographyEllipsis" + message="Replace "..." with ellipsis character (…, &#8230;) ?" + errorLine1=" <string name="whichApplication" msgid="2309561338625872614">"Wykonaj czynność przez..."</string>" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/values-pl/strings.xml" + line="19" + column="65"/> + </issue> + + <issue + id="TypographyEllipsis" + message="Replace "..." with ellipsis character (…, &#8230;) ?" + errorLine1=" <string name="whichViewApplication" msgid="7660051361612888119">"...ဖြင့် ဖွင့်မည်"</string>" + errorLine2=" ~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/values-my/strings.xml" + line="22" + column="69"/> + </issue> + + <issue + id="TypographyEllipsis" + message="Replace "..." with ellipsis character (…, &#8230;) ?" + errorLine1=" <string name="whichEditApplication" msgid="5097563012157950614">"...နှင့် တည်းဖြတ်ရန်"</string>" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/values-my/strings.xml" + line="30" + column="69"/> + </issue> + + <issue + id="TypographyEllipsis" + message="Replace "..." with ellipsis character (…, &#8230;) ?" + errorLine1=" <string name="whichSendToApplication" msgid="2724450540348806267">"Sūtīšana, izmantojot..."</string>" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/values-lv/strings.xml" + line="36" + column="71"/> + </issue> + + <issue + id="ClickableViewAccessibility" + message="Custom view `ResolverDrawerLayout` overrides `onTouchEvent` but not `performClick`" + errorLine1=" public boolean onTouchEvent(MotionEvent ev) {" + errorLine2=" ~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/src/com/android/intentresolver/widget/ResolverDrawerLayout.java" + line="403" + column="20"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView android:id="@android:id/icon"" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_dialog.xml" + line="37" + column="10"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView android:id="@android:id/icon"" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_dialog_item.xml" + line="30" + column="6"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView android:id="@android:id/icon"" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_item.xml" + line="32" + column="6"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_preview_file.xml" + line="47" + column="10"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_grid_preview_text.xml" + line="112" + column="8"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/image_preview_image_item.xml" + line="43" + column="10"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout-h480dp/image_preview_image_item.xml" + line="46" + column="10"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout-h480dp/image_preview_image_item.xml" + line="68" + column="10"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/miniresolver.xml" + line="39" + column="10"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView android:id="@android:id/icon"" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/resolve_grid_item.xml" + line="32" + column="6"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView android:id="@android:id/icon"" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/resolve_list_item.xml" + line="30" + column="6"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/resolver_list_with_default.xml" + line="44" + column="14"/> + </issue> + + <issue + id="ContentDescription" + message="Missing `contentDescription` attribute on image" + errorLine1=" <ImageView" + errorLine2=" ~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/resolver_list_with_default.xml" + line="79" + column="18"/> + </issue> + + <issue + id="HardcodedText" + message="Hardcoded string "App name", should use `@string` resource" + errorLine1=" android:text="App name"" + errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/chooser_dialog.xml" + line="46" + column="19"/> + </issue> + + <issue + id="RelativeOverlap" + message="`@androidprv:id/button_open` can overlap `@androidprv:id/use_same_profile_browser` if @string/activity_resolver_use_once, @string/whichViewApplicationLabel grow due to localized text expansion" + errorLine1=" <Button" + errorLine2=" ~~~~~~"> + <location + file="packages/modules/IntentResolver/java/res/layout/miniresolver.xml" + line="100" + column="14"/> + </issue> + +</issues> diff --git a/tests/unit/src/com/android/intentresolver/ChooserRefinementManagerTest.kt b/tests/unit/src/com/android/intentresolver/ChooserRefinementManagerTest.kt index 61ac0c21..16c917b0 100644 --- a/tests/unit/src/com/android/intentresolver/ChooserRefinementManagerTest.kt +++ b/tests/unit/src/com/android/intentresolver/ChooserRefinementManagerTest.kt @@ -29,8 +29,8 @@ import androidx.lifecycle.Observer import androidx.test.annotation.UiThreadTest import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.intentresolver.ChooserRefinementManager.RefinementCompletion +import com.android.intentresolver.ChooserRefinementManager.RefinementType import com.android.intentresolver.chooser.ImmutableTargetInfo -import com.android.intentresolver.chooser.TargetInfo import com.google.common.truth.Truth.assertThat import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit @@ -55,15 +55,15 @@ class ChooserRefinementManagerTest { object : Observer<RefinementCompletion> { val failureCountDown = CountDownLatch(1) val successCountDown = CountDownLatch(1) - var latestTargetInfo: TargetInfo? = null + var latestRefinedIntent: Intent? = null override fun onChanged(completion: RefinementCompletion) { if (completion.consume()) { - val targetInfo = completion.targetInfo - if (targetInfo == null) { + val refinedIntent = completion.refinedIntent + if (refinedIntent == null) { failureCountDown.countDown() } else { - latestTargetInfo = targetInfo + latestRefinedIntent = refinedIntent successCountDown.countDown() } } @@ -115,8 +115,7 @@ class ChooserRefinementManagerTest { receiver?.send(Activity.RESULT_OK, bundle) assertThat(completionObserver.successCountDown.await(1000, TimeUnit.MILLISECONDS)).isTrue() - assertThat(completionObserver.latestTargetInfo?.resolvedIntent?.action) - .isEqualTo(Intent.ACTION_VIEW) + assertThat(completionObserver.latestRefinedIntent?.action).isEqualTo(Intent.ACTION_VIEW) } @Test @@ -231,10 +230,11 @@ class ChooserRefinementManagerTest { @Test fun testRefinementCompletion() { - val refinementCompletion = RefinementCompletion(exampleTargetInfo) - assertThat(refinementCompletion.targetInfo).isEqualTo(exampleTargetInfo) + val refinementCompletion = + RefinementCompletion(RefinementType.TARGET_INFO, exampleTargetInfo, null) + assertThat(refinementCompletion.originalTargetInfo).isEqualTo(exampleTargetInfo) assertThat(refinementCompletion.consume()).isTrue() - assertThat(refinementCompletion.targetInfo).isEqualTo(exampleTargetInfo) + assertThat(refinementCompletion.originalTargetInfo).isEqualTo(exampleTargetInfo) // can only consume once. assertThat(refinementCompletion.consume()).isFalse() diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/FileContentPreviewUiTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/FileContentPreviewUiTest.kt index 25e8b239..0e4e36ab 100644 --- a/tests/unit/src/com/android/intentresolver/contentpreview/FileContentPreviewUiTest.kt +++ b/tests/unit/src/com/android/intentresolver/contentpreview/FileContentPreviewUiTest.kt @@ -64,46 +64,24 @@ class FileContentPreviewUiTest { val gridLayout = layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) as ViewGroup + val headlineRow = gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) + + assertThat(headlineRow.findViewById<View>(R.id.headline)).isNull() + assertThat(headlineRow.findViewById<View>(R.id.metadata)).isNull() val previewView = testSubject.display( context.resources, layoutInflater, gridLayout, - /*headlineViewParent=*/ null + headlineRow, ) assertThat(previewView).isNotNull() - val headlineView = previewView?.findViewById<TextView>(R.id.headline) - assertThat(headlineView).isNotNull() - assertThat(headlineView?.text).isEqualTo(text) - val metadataView = previewView?.findViewById<TextView>(R.id.metadata) - assertThat(metadataView?.text).isEqualTo(testMetadataText) - } - - @Test - fun test_displayWithExternalHeaderView() { - val layoutInflater = LayoutInflater.from(context) - val gridLayout = - layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) - as ViewGroup - val externalHeaderView = - gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) - - assertThat(externalHeaderView.findViewById<View>(R.id.headline)).isNull() - assertThat(externalHeaderView.findViewById<View>(R.id.metadata)).isNull() - - val previewView = - testSubject.display(context.resources, layoutInflater, gridLayout, externalHeaderView) - - assertThat(previewView).isNotNull() - assertThat(previewView.findViewById<View>(R.id.headline)).isNull() - assertThat(previewView.findViewById<View>(R.id.metadata)).isNull() - - val headlineView = externalHeaderView.findViewById<TextView>(R.id.headline) + val headlineView = headlineRow.findViewById<TextView>(R.id.headline) assertThat(headlineView).isNotNull() assertThat(headlineView?.text).isEqualTo(text) - val metadataView = externalHeaderView.findViewById<TextView>(R.id.metadata) + val metadataView = headlineRow.findViewById<TextView>(R.id.metadata) assertThat(metadataView?.text).isEqualTo(testMetadataText) } } diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt index bd0a8efa..da0ddd12 100644 --- a/tests/unit/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt +++ b/tests/unit/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt @@ -52,9 +52,13 @@ class FilesPlusTextContentPreviewUiTest { private val actionFactory = object : ChooserContentPreviewUi.ActionFactory { override fun getEditButtonRunnable(): Runnable? = null + override fun getCopyButtonRunnable(): Runnable? = null + override fun createCustomActions(): List<ActionRow.Action> = emptyList() + override fun getModifyShareAction(): ActionRow.Action? = null + override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {} } private val imageLoader = mock<ImageLoader>() @@ -70,200 +74,106 @@ class FilesPlusTextContentPreviewUiTest { get() = getInstrumentation().context @Test - fun test_displayImagesPlusTextWithoutUriMetadata_showImagesHeadline() { + fun test_displayImagesPlusTextWithoutUriMetadataHeader_showImagesHeadline() { val sharedFileCount = 2 - val previewView = testLoadingHeadline("image/*", sharedFileCount) - - verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_IMAGES) - verifyPreviewMetadata(previewView, testMetadataText) - verifySharedText(previewView) - } - - @Test - fun test_displayImagesPlusTextWithoutUriMetadataExternalHeader_showImagesHeadline() { - val sharedFileCount = 2 - val (previewView, headerParent) = testLoadingExternalHeadline("image/*", sharedFileCount) + val (previewView, headlineRow) = testLoadingHeadline("image/*", sharedFileCount) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(headerParent, HEADLINE_IMAGES) - verifyPreviewMetadata(headerParent, testMetadataText) + verifyPreviewHeadline(headlineRow, HEADLINE_IMAGES) + verifyPreviewMetadata(headlineRow, testMetadataText) verifySharedText(previewView) } @Test - fun test_displayVideosPlusTextWithoutUriMetadata_showVideosHeadline() { + fun test_displayVideosPlusTextWithoutUriMetadataHeader_showVideosHeadline() { val sharedFileCount = 2 - val previewView = testLoadingHeadline("video/*", sharedFileCount) + val (previewView, headlineRow) = testLoadingHeadline("video/*", sharedFileCount) verify(headlineGenerator, times(1)).getVideosHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_VIDEOS) - verifyPreviewMetadata(previewView, testMetadataText) - verifySharedText(previewView) - } - - @Test - fun test_displayVideosPlusTextWithoutUriMetadataExternalHeader_showVideosHeadline() { - val sharedFileCount = 2 - val (previewView, headerParent) = testLoadingExternalHeadline("video/*", sharedFileCount) - - verify(headlineGenerator, times(1)).getVideosHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(headerParent, HEADLINE_VIDEOS) - verifyPreviewMetadata(headerParent, testMetadataText) - verifySharedText(previewView) - } - - @Test - fun test_displayDocsPlusTextWithoutUriMetadata_showFilesHeadline() { - val sharedFileCount = 2 - val previewView = testLoadingHeadline("application/pdf", sharedFileCount) - - verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_FILES) - verifyPreviewMetadata(previewView, testMetadataText) - verifySharedText(previewView) - } - - @Test - fun test_displayDocsPlusTextWithoutUriMetadataExternalHeader_showFilesHeadline() { - val sharedFileCount = 2 - val (previewView, headerParent) = - testLoadingExternalHeadline("application/pdf", sharedFileCount) - - verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(headerParent, HEADLINE_FILES) - verifyPreviewMetadata(headerParent, testMetadataText) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() + verifyPreviewHeadline(headlineRow, HEADLINE_VIDEOS) + verifyPreviewMetadata(headlineRow, testMetadataText) verifySharedText(previewView) } @Test - fun test_displayMixedContentPlusTextWithoutUriMetadata_showFilesHeadline() { + fun test_displayDocsPlusTextWithoutUriMetadataHeader_showFilesHeadline() { val sharedFileCount = 2 - val previewView = testLoadingHeadline("*/*", sharedFileCount) + val (previewView, headlineRow) = testLoadingHeadline("application/pdf", sharedFileCount) verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_FILES) - verifyPreviewMetadata(previewView, testMetadataText) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() + verifyPreviewHeadline(headlineRow, HEADLINE_FILES) + verifyPreviewMetadata(headlineRow, testMetadataText) verifySharedText(previewView) } @Test - fun test_displayMixedContentPlusTextWithoutUriMetadataExternalHeader_showFilesHeadline() { + fun test_displayMixedContentPlusTextWithoutUriMetadataHeader_showFilesHeadline() { val sharedFileCount = 2 - val (previewView, headerParent) = testLoadingExternalHeadline("*/*", sharedFileCount) + val (previewView, headlineRow) = testLoadingHeadline("*/*", sharedFileCount) verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(headerParent, HEADLINE_FILES) - verifyPreviewMetadata(headerParent, testMetadataText) - verifySharedText(previewView) - } - - @Test - fun test_displayImagesPlusTextWithUriMetadataSet_showImagesHeadline() { - val loadedFileMetadata = createFileInfosWithMimeTypes("image/png", "image/jpeg") - val sharedFileCount = loadedFileMetadata.size - val previewView = testLoadingHeadline("image/*", sharedFileCount, loadedFileMetadata) - - verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_IMAGES) - verifyPreviewMetadata(previewView, testMetadataText) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() + verifyPreviewHeadline(headlineRow, HEADLINE_FILES) + verifyPreviewMetadata(headlineRow, testMetadataText) verifySharedText(previewView) } @Test - fun test_displayImagesPlusTextWithUriMetadataSetExternalHeader_showImagesHeadline() { + fun test_displayImagesPlusTextWithUriMetadataSetHeader_showImagesHeadline() { val loadedFileMetadata = createFileInfosWithMimeTypes("image/png", "image/jpeg") val sharedFileCount = loadedFileMetadata.size - val (previewView, headerParent) = - testLoadingExternalHeadline("image/*", sharedFileCount, loadedFileMetadata) + val (previewView, headlineRow) = + testLoadingHeadline("image/*", sharedFileCount, loadedFileMetadata) verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(headerParent, HEADLINE_IMAGES) - verifyPreviewMetadata(headerParent, testMetadataText) - verifySharedText(previewView) - } - - @Test - fun test_displayVideosPlusTextWithUriMetadataSet_showVideosHeadline() { - val loadedFileMetadata = createFileInfosWithMimeTypes("video/mp4", "video/mp4") - val sharedFileCount = loadedFileMetadata.size - val previewView = testLoadingHeadline("video/*", sharedFileCount, loadedFileMetadata) - - verify(headlineGenerator, times(1)).getVideosHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_VIDEOS) - verifyPreviewMetadata(previewView, testMetadataText) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() + verifyPreviewHeadline(headlineRow, HEADLINE_IMAGES) + verifyPreviewMetadata(headlineRow, testMetadataText) verifySharedText(previewView) } @Test - fun test_displayVideosPlusTextWithUriMetadataSetExternalHeader_showVideosHeadline() { + fun test_displayVideosPlusTextWithUriMetadataSetHeader_showVideosHeadline() { val loadedFileMetadata = createFileInfosWithMimeTypes("video/mp4", "video/mp4") val sharedFileCount = loadedFileMetadata.size - val (previewView, headerParent) = - testLoadingExternalHeadline("video/*", sharedFileCount, loadedFileMetadata) + val (previewView, headlineRow) = + testLoadingHeadline("video/*", sharedFileCount, loadedFileMetadata) verify(headlineGenerator, times(1)).getVideosHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(headerParent, HEADLINE_VIDEOS) - verifyPreviewMetadata(headerParent, testMetadataText) - verifySharedText(previewView) - } - - @Test - fun test_displayImagesAndVideosPlusTextWithUriMetadataSet_showFilesHeadline() { - val loadedFileMetadata = createFileInfosWithMimeTypes("image/png", "video/mp4") - val sharedFileCount = loadedFileMetadata.size - val previewView = testLoadingHeadline("*/*", sharedFileCount, loadedFileMetadata) - - verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_FILES) - verifyPreviewMetadata(previewView, testMetadataText) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() + verifyPreviewHeadline(headlineRow, HEADLINE_VIDEOS) + verifyPreviewMetadata(headlineRow, testMetadataText) verifySharedText(previewView) } @Test - fun test_displayImagesAndVideosPlusTextWithUriMetadataSetExternalHeader_showFilesHeadline() { + fun test_displayImagesAndVideosPlusTextWithUriMetadataSetHeader_showFilesHeadline() { val loadedFileMetadata = createFileInfosWithMimeTypes("image/png", "video/mp4") val sharedFileCount = loadedFileMetadata.size - val (previewView, headerParent) = - testLoadingExternalHeadline("*/*", sharedFileCount, loadedFileMetadata) + val (previewView, headlineRow) = + testLoadingHeadline("*/*", sharedFileCount, loadedFileMetadata) verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(headerParent, HEADLINE_FILES) - verifyPreviewMetadata(headerParent, testMetadataText) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() + verifyPreviewHeadline(headlineRow, HEADLINE_FILES) + verifyPreviewMetadata(headlineRow, testMetadataText) verifySharedText(previewView) } @Test - fun test_displayDocsPlusTextWithUriMetadataSet_showFilesHeadline() { + fun test_displayDocsPlusTextWithUriMetadataSetHeader_showFilesHeadline() { val loadedFileMetadata = createFileInfosWithMimeTypes("application/pdf", "application/pdf") val sharedFileCount = loadedFileMetadata.size - val previewView = + val (previewView, headlineRow) = testLoadingHeadline("application/pdf", sharedFileCount, loadedFileMetadata) verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_FILES) - verifyPreviewMetadata(previewView, testMetadataText) - verifySharedText(previewView) - } - - @Test - fun test_displayDocsPlusTextWithUriMetadataSetExternalHeader_showFilesHeadline() { - val loadedFileMetadata = createFileInfosWithMimeTypes("application/pdf", "application/pdf") - val sharedFileCount = loadedFileMetadata.size - val (previewView, headerParent) = - testLoadingExternalHeadline("application/pdf", sharedFileCount, loadedFileMetadata) - - verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(headerParent, HEADLINE_FILES) - verifyPreviewMetadata(headerParent, testMetadataText) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() + verifyPreviewHeadline(headlineRow, HEADLINE_FILES) + verifyPreviewMetadata(headlineRow, testMetadataText) verifySharedText(previewView) } @@ -287,25 +197,30 @@ class FilesPlusTextContentPreviewUiTest { val gridLayout = layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) as ViewGroup + val headlineRow = gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) - val previewView = - testSubject.display(context.resources, LayoutInflater.from(context), gridLayout, null) + testSubject.display( + context.resources, + LayoutInflater.from(context), + gridLayout, + headlineRow + ) verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) verify(headlineGenerator, never()).getImagesHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_FILES) - verifyPreviewMetadata(previewView, testMetadataText) + verifyPreviewHeadline(headlineRow, HEADLINE_FILES) + verifyPreviewMetadata(headlineRow, testMetadataText) testSubject.updatePreviewMetadata(createFileInfosWithMimeTypes("image/png", "image/jpg")) verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount) - verifyPreviewHeadline(previewView, HEADLINE_IMAGES) - verifyPreviewMetadata(previewView, testMetadataText) + verifyPreviewHeadline(headlineRow, HEADLINE_IMAGES) + verifyPreviewMetadata(headlineRow, testMetadataText) } @Test - fun test_uriMetadataIsMoreSpecificThanIntentMimeTypeExternalHeader_headlineGetsUpdated() { + fun test_uriMetadataIsMoreSpecificThanIntentMimeTypeHeader_headlineGetsUpdated() { val sharedFileCount = 2 val testSubject = FilesPlusTextContentPreviewUi( @@ -324,14 +239,13 @@ class FilesPlusTextContentPreviewUiTest { val gridLayout = layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) as ViewGroup - val externalHeaderView = - gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) + val headlineRow = gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) - assertWithMessage("External headline should not be inflated by default") - .that(externalHeaderView.findViewById<View>(R.id.headline)) + assertWithMessage("Headline should not be inflated by default") + .that(headlineRow.findViewById<View>(R.id.headline)) .isNull() - assertWithMessage("External metadata should not be inflated by default") - .that(externalHeaderView.findViewById<View>(R.id.metadata)) + assertWithMessage("Metadata should not be inflated by default") + .that(headlineRow.findViewById<View>(R.id.metadata)) .isNull() val previewView = @@ -339,59 +253,27 @@ class FilesPlusTextContentPreviewUiTest { context.resources, LayoutInflater.from(context), gridLayout, - externalHeaderView + headlineRow ) verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) verify(headlineGenerator, never()).getImagesHeadline(sharedFileCount) - verifyInternalHeadlineAbsence(previewView) - verifyPreviewHeadline(externalHeaderView, HEADLINE_FILES) - verifyPreviewMetadata(externalHeaderView, testMetadataText) + assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() + verifyPreviewHeadline(headlineRow, HEADLINE_FILES) + verifyPreviewMetadata(headlineRow, testMetadataText) testSubject.updatePreviewMetadata(createFileInfosWithMimeTypes("image/png", "image/jpg")) verify(headlineGenerator, times(1)).getFilesHeadline(sharedFileCount) verify(headlineGenerator, times(1)).getImagesHeadline(sharedFileCount) - verifyPreviewHeadline(externalHeaderView, HEADLINE_IMAGES) - verifyPreviewMetadata(externalHeaderView, testMetadataText) + verifyPreviewHeadline(headlineRow, HEADLINE_IMAGES) + verifyPreviewMetadata(headlineRow, testMetadataText) } private fun testLoadingHeadline( intentMimeType: String, sharedFileCount: Int, loadedFileMetadata: List<FileInfo>? = null, - ): ViewGroup? { - val testSubject = - FilesPlusTextContentPreviewUi( - testScope, - /*isSingleImage=*/ false, - sharedFileCount, - SHARED_TEXT, - intentMimeType, - actionFactory, - imageLoader, - DefaultMimeTypeClassifier, - headlineGenerator, - testMetadataText, - ) - val layoutInflater = LayoutInflater.from(context) - val gridLayout = - layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) - as ViewGroup - - loadedFileMetadata?.let(testSubject::updatePreviewMetadata) - return testSubject.display( - context.resources, - LayoutInflater.from(context), - gridLayout, - /*headlineViewParent=*/ null - ) - } - - private fun testLoadingExternalHeadline( - intentMimeType: String, - sharedFileCount: Int, - loadedFileMetadata: List<FileInfo>? = null, ): Pair<ViewGroup?, View> { val testSubject = FilesPlusTextContentPreviewUi( @@ -410,15 +292,14 @@ class FilesPlusTextContentPreviewUiTest { val gridLayout = layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) as ViewGroup - val externalHeaderView = - gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) + val headlineRow = gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) - assertWithMessage("External headline should not be inflated by default") - .that(externalHeaderView.findViewById<View>(R.id.headline)) + assertWithMessage("Headline should not be inflated by default") + .that(headlineRow.findViewById<View>(R.id.headline)) .isNull() - assertWithMessage("External metadata should not be inflated by default") - .that(externalHeaderView.findViewById<View>(R.id.metadata)) + assertWithMessage("Metadata should not be inflated by default") + .that(headlineRow.findViewById<View>(R.id.metadata)) .isNull() loadedFileMetadata?.let(testSubject::updatePreviewMetadata) @@ -426,8 +307,8 @@ class FilesPlusTextContentPreviewUiTest { context.resources, LayoutInflater.from(context), gridLayout, - externalHeaderView - ) to externalHeaderView + headlineRow + ) to headlineRow } private fun createFileInfosWithMimeTypes(vararg mimeTypes: String): List<FileInfo> { @@ -457,13 +338,4 @@ class FilesPlusTextContentPreviewUiTest { private fun verifySharedText(previewView: ViewGroup?) { verifyTextViewText(previewView, R.id.content_preview_text, SHARED_TEXT) } - - private fun verifyInternalHeadlineAbsence(previewView: ViewGroup?) { - assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() - assertWithMessage( - "Preview headline should not be inflated when an external headline is used" - ) - .that(previewView?.findViewById<View>(R.id.headline)) - .isNull() - } } diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt index 0416d71a..9a15f90a 100644 --- a/tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt +++ b/tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt @@ -44,9 +44,13 @@ class TextContentPreviewUiTest { private val actionFactory = object : ChooserContentPreviewUi.ActionFactory { override fun getEditButtonRunnable(): Runnable? = null + override fun getCopyButtonRunnable(): Runnable? = null + override fun createCustomActions(): List<ActionRow.Action> = emptyList() + override fun getModifyShareAction(): ActionRow.Action? = null + override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {} } private val imageLoader = mock<ImageLoader>() @@ -79,47 +83,21 @@ class TextContentPreviewUiTest { val gridLayout = layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) as ViewGroup + val headlineRow = gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) val previewView = testSubject.display( context.resources, layoutInflater, gridLayout, - /*headlineViewParent=*/ null + headlineRow, ) assertThat(previewView).isNotNull() - val headlineView = previewView?.findViewById<TextView>(R.id.headline) - assertThat(headlineView).isNotNull() - assertThat(headlineView?.text).isEqualTo(text) - val metadataView = previewView?.findViewById<TextView>(R.id.metadata) - assertThat(metadataView).isNotNull() - assertThat(metadataView?.text).isEqualTo(testMetadataText) - } - - @Test - fun test_displayWithExternalHeaderView_externalHeaderIsDisplayed() { - val layoutInflater = LayoutInflater.from(context) - val gridLayout = - layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) - as ViewGroup - val externalHeaderView = - gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) - - assertThat(externalHeaderView.findViewById<View>(R.id.headline)).isNull() - assertThat(externalHeaderView.findViewById<View>(R.id.metadata)).isNull() - - val previewView = - testSubject.display(context.resources, layoutInflater, gridLayout, externalHeaderView) - - assertThat(previewView).isNotNull() - assertThat(previewView.findViewById<View>(R.id.headline)).isNull() - assertThat(previewView.findViewById<View>(R.id.metadata)).isNull() - - val headlineView = externalHeaderView.findViewById<TextView>(R.id.headline) + val headlineView = headlineRow.findViewById<TextView>(R.id.headline) assertThat(headlineView).isNotNull() assertThat(headlineView?.text).isEqualTo(text) - val metadataView = externalHeaderView.findViewById<TextView>(R.id.metadata) + val metadataView = headlineRow.findViewById<TextView>(R.id.metadata) assertThat(metadataView).isNotNull() assertThat(metadataView?.text).isEqualTo(testMetadataText) } @@ -130,6 +108,7 @@ class TextContentPreviewUiTest { val gridLayout = layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) as ViewGroup + val headlineRow = gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) val albumSubject = TextContentPreviewUi( @@ -149,14 +128,14 @@ class TextContentPreviewUiTest { context.resources, layoutInflater, gridLayout, - /*headlineViewParent=*/ null + headlineRow, ) assertThat(previewView).isNotNull() - val headlineView = previewView?.findViewById<TextView>(R.id.headline) + val headlineView = headlineRow.findViewById<TextView>(R.id.headline) assertThat(headlineView).isNotNull() assertThat(headlineView?.text).isEqualTo(albumHeadline) - val metadataView = previewView?.findViewById<TextView>(R.id.metadata) + val metadataView = headlineRow.findViewById<TextView>(R.id.metadata) assertThat(metadataView).isNotNull() assertThat(metadataView?.text).isEqualTo(testMetadataText) } diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUiTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUiTest.kt index 07575be0..98e6c381 100644 --- a/tests/unit/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUiTest.kt +++ b/tests/unit/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUiTest.kt @@ -67,235 +67,100 @@ class UnifiedContentPreviewUiTest { get() = getInstrumentation().context @Test - fun test_displayImagesWithoutUriMetadata_showImagesHeadline() { - testLoadingHeadline("image/*", files = null) { previewView -> + fun test_displayImagesWithoutUriMetadataHeader_showImagesHeadline() { + testLoadingHeadline("image/*", files = null) { headlineRow -> verify(headlineGenerator, times(1)).getImagesHeadline(2) - verifyPreviewHeadline(previewView, IMAGE_HEADLINE) - verifyPreviewMetadata(previewView, testMetadataText) + verifyPreviewHeadline(headlineRow, IMAGE_HEADLINE) + verifyPreviewMetadata(headlineRow, testMetadataText) } } @Test - fun test_displayImagesWithoutUriMetadataExternalHeader_showImagesHeadline() { - testLoadingExternalHeadline("image/*", files = null) { externalHeaderView -> - verify(headlineGenerator, times(1)).getImagesHeadline(2) - verifyPreviewHeadline(externalHeaderView, IMAGE_HEADLINE) - verifyPreviewMetadata(externalHeaderView, testMetadataText) - } - } - - @Test - fun test_displayVideosWithoutUriMetadata_showImagesHeadline() { - testLoadingHeadline("video/*", files = null) { previewView -> - verify(headlineGenerator, times(1)).getVideosHeadline(2) - verifyPreviewHeadline(previewView, VIDEO_HEADLINE) - verifyPreviewMetadata(previewView, testMetadataText) - } - } - - @Test - fun test_displayVideosWithoutUriMetadataExternalHeader_showImagesHeadline() { - testLoadingExternalHeadline("video/*", files = null) { externalHeaderView -> + fun test_displayVideosWithoutUriMetadataHeader_showImagesHeadline() { + testLoadingHeadline("video/*", files = null) { headlineRow -> verify(headlineGenerator, times(1)).getVideosHeadline(2) - verifyPreviewHeadline(externalHeaderView, VIDEO_HEADLINE) - verifyPreviewMetadata(externalHeaderView, testMetadataText) + verifyPreviewHeadline(headlineRow, VIDEO_HEADLINE) + verifyPreviewMetadata(headlineRow, testMetadataText) } } @Test - fun test_displayDocumentsWithoutUriMetadata_showImagesHeadline() { - testLoadingHeadline("application/pdf", files = null) { previewView -> + fun test_displayDocumentsWithoutUriMetadataHeader_showImagesHeadline() { + testLoadingHeadline("application/pdf", files = null) { headlineRow -> verify(headlineGenerator, times(1)).getFilesHeadline(2) - verifyPreviewHeadline(previewView, FILES_HEADLINE) - verifyPreviewMetadata(previewView, testMetadataText) + verifyPreviewHeadline(headlineRow, FILES_HEADLINE) + verifyPreviewMetadata(headlineRow, testMetadataText) } } @Test - fun test_displayDocumentsWithoutUriMetadataExternalHeader_showImagesHeadline() { - testLoadingExternalHeadline("application/pdf", files = null) { externalHeaderView -> + fun test_displayMixedContentWithoutUriMetadataHeader_showImagesHeadline() { + testLoadingHeadline("*/*", files = null) { headlineRow -> verify(headlineGenerator, times(1)).getFilesHeadline(2) - verifyPreviewHeadline(externalHeaderView, FILES_HEADLINE) - verifyPreviewMetadata(externalHeaderView, testMetadataText) - } - } - - @Test - fun test_displayMixedContentWithoutUriMetadata_showImagesHeadline() { - testLoadingHeadline("*/*", files = null) { previewView -> - verify(headlineGenerator, times(1)).getFilesHeadline(2) - verifyPreviewHeadline(previewView, FILES_HEADLINE) - verifyPreviewMetadata(previewView, testMetadataText) - } - } - - @Test - fun test_displayMixedContentWithoutUriMetadataExternalHeader_showImagesHeadline() { - testLoadingExternalHeadline("*/*", files = null) { externalHeader -> - verify(headlineGenerator, times(1)).getFilesHeadline(2) - verifyPreviewHeadline(externalHeader, FILES_HEADLINE) - verifyPreviewMetadata(externalHeader, testMetadataText) - } - } - - @Test - fun test_displayImagesWithUriMetadataSet_showImagesHeadline() { - val uri = Uri.parse("content://pkg.app/image.png") - val files = - listOf( - FileInfo.Builder(uri).withMimeType("image/png").build(), - FileInfo.Builder(uri).withMimeType("image/jpeg").build(), - ) - testLoadingHeadline("image/*", files) { preivewView -> - verify(headlineGenerator, times(1)).getImagesHeadline(2) - verifyPreviewHeadline(preivewView, IMAGE_HEADLINE) + verifyPreviewHeadline(headlineRow, FILES_HEADLINE) + verifyPreviewMetadata(headlineRow, testMetadataText) } } @Test - fun test_displayImagesWithUriMetadataSetExternalHeader_showImagesHeadline() { + fun test_displayImagesWithUriMetadataSetHeader_showImagesHeadline() { val uri = Uri.parse("content://pkg.app/image.png") val files = listOf( FileInfo.Builder(uri).withMimeType("image/png").build(), FileInfo.Builder(uri).withMimeType("image/jpeg").build(), ) - testLoadingExternalHeadline("image/*", files) { externalHeader -> + testLoadingHeadline("image/*", files) { headlineRow -> verify(headlineGenerator, times(1)).getImagesHeadline(2) - verifyPreviewHeadline(externalHeader, IMAGE_HEADLINE) + verifyPreviewHeadline(headlineRow, IMAGE_HEADLINE) } } @Test - fun test_displayVideosWithUriMetadataSet_showImagesHeadline() { + fun test_displayVideosWithUriMetadataSetHeader_showImagesHeadline() { val uri = Uri.parse("content://pkg.app/image.png") val files = listOf( FileInfo.Builder(uri).withMimeType("video/mp4").build(), FileInfo.Builder(uri).withMimeType("video/mp4").build(), ) - testLoadingHeadline("video/*", files) { previewView -> + testLoadingHeadline("video/*", files) { headlineRow -> verify(headlineGenerator, times(1)).getVideosHeadline(2) - verifyPreviewHeadline(previewView, VIDEO_HEADLINE) + verifyPreviewHeadline(headlineRow, VIDEO_HEADLINE) } } @Test - fun test_displayVideosWithUriMetadataSetExternalHeader_showImagesHeadline() { - val uri = Uri.parse("content://pkg.app/image.png") - val files = - listOf( - FileInfo.Builder(uri).withMimeType("video/mp4").build(), - FileInfo.Builder(uri).withMimeType("video/mp4").build(), - ) - testLoadingExternalHeadline("video/*", files) { externalHeader -> - verify(headlineGenerator, times(1)).getVideosHeadline(2) - verifyPreviewHeadline(externalHeader, VIDEO_HEADLINE) - } - } - - @Test - fun test_displayImagesAndVideosWithUriMetadataSet_showImagesHeadline() { + fun test_displayImagesAndVideosWithUriMetadataSetHeader_showImagesHeadline() { val uri = Uri.parse("content://pkg.app/image.png") val files = listOf( FileInfo.Builder(uri).withMimeType("image/png").build(), FileInfo.Builder(uri).withMimeType("video/mp4").build(), ) - testLoadingHeadline("*/*", files) { previewView -> + testLoadingHeadline("*/*", files) { headlineRow -> verify(headlineGenerator, times(1)).getFilesHeadline(2) - verifyPreviewHeadline(previewView, FILES_HEADLINE) + verifyPreviewHeadline(headlineRow, FILES_HEADLINE) } } @Test - fun test_displayImagesAndVideosWithUriMetadataSetExternalHeader_showImagesHeadline() { - val uri = Uri.parse("content://pkg.app/image.png") - val files = - listOf( - FileInfo.Builder(uri).withMimeType("image/png").build(), - FileInfo.Builder(uri).withMimeType("video/mp4").build(), - ) - testLoadingExternalHeadline("*/*", files) { externalHeader -> - verify(headlineGenerator, times(1)).getFilesHeadline(2) - verifyPreviewHeadline(externalHeader, FILES_HEADLINE) - } - } - - @Test - fun test_displayDocumentsWithUriMetadataSet_showImagesHeadline() { + fun test_displayDocumentsWithUriMetadataSetHeader_showImagesHeadline() { val uri = Uri.parse("content://pkg.app/image.png") val files = listOf( FileInfo.Builder(uri).withMimeType("application/pdf").build(), FileInfo.Builder(uri).withMimeType("application/pdf").build(), ) - testLoadingHeadline("application/pdf", files) { previewView -> + testLoadingHeadline("application/pdf", files) { headlineRow -> verify(headlineGenerator, times(1)).getFilesHeadline(2) - verifyPreviewHeadline(previewView, FILES_HEADLINE) - } - } - - @Test - fun test_displayDocumentsWithUriMetadataSetExternalHeader_showImagesHeadline() { - val uri = Uri.parse("content://pkg.app/image.png") - val files = - listOf( - FileInfo.Builder(uri).withMimeType("application/pdf").build(), - FileInfo.Builder(uri).withMimeType("application/pdf").build(), - ) - testLoadingExternalHeadline("application/pdf", files) { externalHeader -> - verify(headlineGenerator, times(1)).getFilesHeadline(2) - verifyPreviewHeadline(externalHeader, FILES_HEADLINE) + verifyPreviewHeadline(headlineRow, FILES_HEADLINE) } } private fun testLoadingHeadline( intentMimeType: String, files: List<FileInfo>?, - verificationBlock: (ViewGroup?) -> Unit, - ) { - testScope.runTest { - val endMarker = FileInfo.Builder(Uri.EMPTY).build() - val emptySourceFlow = MutableSharedFlow<FileInfo>(replay = 1) - val testSubject = - UnifiedContentPreviewUi( - testScope, - /*isSingleImage=*/ false, - intentMimeType, - actionFactory, - imageLoader, - DefaultMimeTypeClassifier, - object : TransitionElementStatusCallback { - override fun onTransitionElementReady(name: String) = Unit - override fun onAllTransitionElementsReady() = Unit - }, - files?.let { it.asFlow() } ?: emptySourceFlow.takeWhile { it !== endMarker }, - /*itemCount=*/ 2, - headlineGenerator, - testMetadataText, - ) - val layoutInflater = LayoutInflater.from(context) - val gridLayout = - layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) - as ViewGroup - - val previewView = - testSubject.display( - context.resources, - LayoutInflater.from(context), - gridLayout, - /*headlineViewParent=*/ null - ) - emptySourceFlow.tryEmit(endMarker) - - verificationBlock(previewView) - } - } - - private fun testLoadingExternalHeadline( - intentMimeType: String, - files: List<FileInfo>?, verificationBlock: (View?) -> Unit, ) { testScope.runTest { @@ -322,26 +187,20 @@ class UnifiedContentPreviewUiTest { val gridLayout = layoutInflater.inflate(R.layout.chooser_grid_scrollable_preview, null, false) as ViewGroup - val externalHeaderView = - gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) + val headlineRow = gridLayout.requireViewById<View>(R.id.chooser_headline_row_container) - assertWithMessage("External headline should not be inflated by default") - .that(externalHeaderView.findViewById<View>(R.id.headline)) + assertWithMessage("Headline row should not be inflated by default") + .that(headlineRow.findViewById<View>(R.id.headline)) .isNull() - val previewView = - testSubject.display( - context.resources, - LayoutInflater.from(context), - gridLayout, - externalHeaderView, - ) - + testSubject.display( + context.resources, + LayoutInflater.from(context), + gridLayout, + headlineRow, + ) emptySourceFlow.tryEmit(endMarker) - - verifyInternalHeadlineAbsence(previewView) - verifyInternalMetadataAbsence(previewView) - verificationBlock(externalHeaderView) + verificationBlock(headlineRow) } } @@ -363,21 +222,4 @@ class UnifiedContentPreviewUiTest { private fun verifyPreviewMetadata(headerViewParent: View?, expectedText: CharSequence) { verifyTextViewText(headerViewParent, R.id.metadata, expectedText) } - - private fun verifyInternalHeadlineAbsence(previewView: ViewGroup?) { - assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() - assertWithMessage( - "Preview headline should not be inflated when an external headline is used" - ) - .that(previewView?.findViewById<View>(R.id.headline)) - .isNull() - } - private fun verifyInternalMetadataAbsence(previewView: ViewGroup?) { - assertWithMessage("Preview parent should not be null").that(previewView).isNotNull() - assertWithMessage( - "Preview metadata should not be inflated when an external metadata is used" - ) - .that(previewView?.findViewById<View>(R.id.metadata)) - .isNull() - } } diff --git a/tests/unit/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProviderTest.kt b/tests/unit/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProviderTest.kt new file mode 100644 index 00000000..fe3e844b --- /dev/null +++ b/tests/unit/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProviderTest.kt @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.intentresolver.emptystate + +import android.content.Intent +import com.android.intentresolver.ProfileHelper +import com.android.intentresolver.ResolverListAdapter +import com.android.intentresolver.annotation.JavaInterop +import com.android.intentresolver.data.repository.FakeUserRepository +import com.android.intentresolver.domain.interactor.UserInteractor +import com.android.intentresolver.inject.FakeIntentResolverFlags +import com.android.intentresolver.shared.model.User +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import org.junit.Test +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyList +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.same +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +@OptIn(JavaInterop::class) +class NoCrossProfileEmptyStateProviderTest { + + private val personalUser = User(0, User.Role.PERSONAL) + private val workUser = User(10, User.Role.WORK) + private val flags = FakeIntentResolverFlags() + private val personalBlocker = mock<EmptyState>() + private val workBlocker = mock<EmptyState>() + + private val userRepository = FakeUserRepository(listOf(personalUser, workUser)) + + private val personalIntents = listOf(Intent("PERSONAL")) + private val personalListAdapter = + mock<ResolverListAdapter> { + on { userHandle } doReturn personalUser.handle + on { intents } doReturn personalIntents + } + private val workIntents = listOf(Intent("WORK")) + private val workListAdapter = + mock<ResolverListAdapter> { + on { userHandle } doReturn workUser.handle + on { intents } doReturn workIntents + } + + // Pretend that no intent can ever be forwarded + val crossProfileIntentsChecker = + mock<CrossProfileIntentsChecker> { + on { + hasCrossProfileIntents( + /* intents = */ anyList(), + /* source = */ anyInt(), + /* target = */ anyInt() + ) + } doReturn false + } + private val sourceUserId = argumentCaptor<Int>() + private val targetUserId = argumentCaptor<Int>() + + @Test + fun testPersonalToWork() { + val userInteractor = UserInteractor(userRepository, launchedAs = personalUser.handle) + + val profileHelper = + ProfileHelper( + userInteractor, + CoroutineScope(Dispatchers.Unconfined), + Dispatchers.Unconfined, + flags + ) + + val provider = + NoCrossProfileEmptyStateProvider( + /* profileHelper = */ profileHelper, + /* noWorkToPersonalEmptyState = */ personalBlocker, + /* noPersonalToWorkEmptyState = */ workBlocker, + /* crossProfileIntentsChecker = */ crossProfileIntentsChecker + ) + + // Personal to personal, not blocked + assertThat(provider.getEmptyState(personalListAdapter)).isNull() + // Not called because sourceUser == targetUser + verify(crossProfileIntentsChecker, never()) + .hasCrossProfileIntents(anyList(), anyInt(), anyInt()) + + // Personal to work, blocked + assertThat(provider.getEmptyState(workListAdapter)).isSameInstanceAs(workBlocker) + + verify(crossProfileIntentsChecker, times(1)) + .hasCrossProfileIntents( + same(workIntents), + sourceUserId.capture(), + targetUserId.capture() + ) + assertThat(sourceUserId.firstValue).isEqualTo(personalUser.id) + assertThat(targetUserId.firstValue).isEqualTo(workUser.id) + } + + @Test + fun testWorkToPersonal() { + val userInteractor = UserInteractor(userRepository, launchedAs = workUser.handle) + + val profileHelper = + ProfileHelper( + userInteractor, + CoroutineScope(Dispatchers.Unconfined), + Dispatchers.Unconfined, + flags + ) + + val provider = + NoCrossProfileEmptyStateProvider( + /* profileHelper = */ profileHelper, + /* noWorkToPersonalEmptyState = */ personalBlocker, + /* noPersonalToWorkEmptyState = */ workBlocker, + /* crossProfileIntentsChecker = */ crossProfileIntentsChecker + ) + + // Work to work, not blocked + assertThat(provider.getEmptyState(workListAdapter)).isNull() + // Not called because sourceUser == targetUser + verify(crossProfileIntentsChecker, never()) + .hasCrossProfileIntents(anyList(), anyInt(), anyInt()) + + // Work to personal, blocked + assertThat(provider.getEmptyState(personalListAdapter)).isSameInstanceAs(personalBlocker) + + verify(crossProfileIntentsChecker, times(1)) + .hasCrossProfileIntents( + same(personalIntents), + sourceUserId.capture(), + targetUserId.capture() + ) + assertThat(sourceUserId.firstValue).isEqualTo(workUser.id) + assertThat(targetUserId.firstValue).isEqualTo(personalUser.id) + } +} |