summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--aconfig/FeatureFlags.aconfig10
-rw-r--r--java/res/drawable/resolver_profile_tab_bg.xml2
-rw-r--r--java/res/layout/chooser_grid_preview_file.xml8
-rw-r--r--java/res/layout/chooser_grid_preview_files_text.xml8
-rw-r--r--java/res/layout/chooser_grid_preview_text.xml9
-rw-r--r--java/res/values-en-rCA/strings.xml3
-rw-r--r--java/res/values-en-rXC/strings.xml3
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java165
-rw-r--r--java/src/com/android/intentresolver/ChooserRefinementManager.java117
-rw-r--r--java/src/com/android/intentresolver/ResolverListAdapter.java2
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java15
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java2
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FileContentPreviewUi.java7
-rw-r--r--java/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUi.java6
-rw-r--r--java/src/com/android/intentresolver/contentpreview/NoContextPreviewUi.kt2
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt12
-rw-r--r--java/src/com/android/intentresolver/contentpreview/TextContentPreviewUi.java7
-rw-r--r--java/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUi.java7
-rw-r--r--java/src/com/android/intentresolver/contentpreview/payloadtoggle/ui/composable/ShareouselComposable.kt10
-rw-r--r--java/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProvider.java7
-rw-r--r--java/src/com/android/intentresolver/grid/ChooserGridAdapter.java41
-rw-r--r--lint-baseline.xml2425
-rw-r--r--tests/unit/src/com/android/intentresolver/ChooserRefinementManagerTest.kt20
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/FileContentPreviewUiTest.kt36
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/FilesPlusTextContentPreviewUiTest.kt282
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/TextContentPreviewUiTest.kt45
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/UnifiedContentPreviewUiTest.kt234
-rw-r--r--tests/unit/src/com/android/intentresolver/emptystate/NoCrossProfileEmptyStateProviderTest.kt156
29 files changed, 2991 insertions, 651 deletions
diff --git a/Android.bp b/Android.bp
index d476321c..d0d20cdb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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&lt;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 &quot;`_Layout`&quot;, 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 &quot;edit&quot; in layout &quot;image_preview_image_item&quot; is missing from the following layout configurations: layout (present in layout-h480dp)"
+ errorLine1=" android:id=&quot;@+id/edit&quot;"
+ 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=" &lt;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=" &lt;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&apos;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&apos;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&apos;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&apos;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&apos;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="`&lt;uses-sdk>` tag appears after `&lt;application>` tag"
+ errorLine1=" &lt;uses-sdk android:minSdkVersion=&quot;VanillaIceCream&quot; android:targetSdkVersion=&quot;16&quot;/>"
+ 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=" &amp;&amp; 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=" &amp;&amp; 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=" &lt;uses-sdk android:minSdkVersion=&quot;VanillaIceCream&quot; android:targetSdkVersion=&quot;16&quot;/>"
+ 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&lt;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&lt;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&lt;Array&lt;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&lt;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=&quot;true&quot;"
+ 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=&quot;true&quot;"
+ 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&lt;Void, Void, List&lt;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 `&lt;TextView/>` and a compound drawable"
+ errorLine1=" &lt;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=&quot;?androidprv:attr/materialColorSurfaceContainer&quot;>"
+ 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=&quot;?androidprv:attr/materialColorSurfaceContainer&quot;>"
+ 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=&quot;?androidprv:attr/materialColorSurfaceContainer&quot;>"
+ 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=&quot;?androidprv:attr/materialColorSurfaceContainer&quot;>"
+ 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=" &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;"
+ 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=&quot;http://schemas.android.com/aapt&quot;"
+ 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=" &lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;"
+ 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=&quot;http://schemas.android.com/apk/res/android&quot;"
+ 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=" &lt;LinearLayout xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;"
+ 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=&quot;http://schemas.android.com/apk/res/android&quot;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/IntentResolver/java/res/layout/resolver_list_per_profile.xml"
+ line="23"
+ column="9"/>
+ </issue>
+
+ <issue
+ id="TypographyEllipsis"
+ message="Replace &quot;...&quot; with ellipsis character (…, &amp;#8230;) ?"
+ errorLine1=" &lt;string name=&quot;whichApplication&quot; msgid=&quot;2309561338625872614&quot;>&quot;... በመጠቀም ድርጊቱን አጠናቅ&quot;&lt;/string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/IntentResolver/java/res/values-am/strings.xml"
+ line="19"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="TypographyEllipsis"
+ message="Replace &quot;...&quot; with ellipsis character (…, &amp;#8230;) ?"
+ errorLine1=" &lt;string name=&quot;whichApplication&quot; msgid=&quot;2309561338625872614&quot;>&quot;Wykonaj czynność przez...&quot;&lt;/string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/IntentResolver/java/res/values-pl/strings.xml"
+ line="19"
+ column="65"/>
+ </issue>
+
+ <issue
+ id="TypographyEllipsis"
+ message="Replace &quot;...&quot; with ellipsis character (…, &amp;#8230;) ?"
+ errorLine1=" &lt;string name=&quot;whichViewApplication&quot; msgid=&quot;7660051361612888119&quot;>&quot;...ဖြင့် ဖွင့်မည်&quot;&lt;/string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/IntentResolver/java/res/values-my/strings.xml"
+ line="22"
+ column="69"/>
+ </issue>
+
+ <issue
+ id="TypographyEllipsis"
+ message="Replace &quot;...&quot; with ellipsis character (…, &amp;#8230;) ?"
+ errorLine1=" &lt;string name=&quot;whichEditApplication&quot; msgid=&quot;5097563012157950614&quot;>&quot;...နှင့် တည်းဖြတ်ရန်&quot;&lt;/string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="packages/modules/IntentResolver/java/res/values-my/strings.xml"
+ line="30"
+ column="69"/>
+ </issue>
+
+ <issue
+ id="TypographyEllipsis"
+ message="Replace &quot;...&quot; with ellipsis character (…, &amp;#8230;) ?"
+ errorLine1=" &lt;string name=&quot;whichSendToApplication&quot; msgid=&quot;2724450540348806267&quot;>&quot;Sūtīšana, izmantojot...&quot;&lt;/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=" &lt;ImageView android:id=&quot;@android:id/icon&quot;"
+ 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=" &lt;ImageView android:id=&quot;@android:id/icon&quot;"
+ 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=" &lt;ImageView android:id=&quot;@android:id/icon&quot;"
+ 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=" &lt;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=" &lt;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=" &lt;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=" &lt;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=" &lt;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=" &lt;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=" &lt;ImageView android:id=&quot;@android:id/icon&quot;"
+ 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=" &lt;ImageView android:id=&quot;@android:id/icon&quot;"
+ 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=" &lt;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=" &lt;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 &quot;App name&quot;, should use `@string` resource"
+ errorLine1=" android:text=&quot;App name&quot;"
+ 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=" &lt;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)
+ }
+}