summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest-lib.xml2
-rw-r--r--java/src/com/android/intentresolver/ChooserActivity.java3
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java10
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java4
-rw-r--r--java/src/com/android/intentresolver/contentpreview/CursorUriReader.kt1
-rw-r--r--java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt1
-rw-r--r--java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt4
-rw-r--r--java/src/com/android/intentresolver/v2/ChooserActionFactory.java14
-rw-r--r--java/src/com/android/intentresolver/v2/ChooserActivity.java37
-rw-r--r--java/src/com/android/intentresolver/v2/ResolverActivity.java13
-rw-r--r--java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt4
-rw-r--r--java/src/com/android/intentresolver/v2/ext/IntentExt.kt6
-rw-r--r--java/src/com/android/intentresolver/v2/profiles/AdapterBinder.java31
-rw-r--r--java/src/com/android/intentresolver/v2/profiles/ChooserMultiProfilePagerAdapter.java (renamed from java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java)4
-rw-r--r--java/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapter.java (renamed from java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java)157
-rw-r--r--java/src/com/android/intentresolver/v2/profiles/OnProfileSelectedListener.java46
-rw-r--r--java/src/com/android/intentresolver/v2/profiles/OnSwitchOnWorkSelectedListener.java27
-rw-r--r--java/src/com/android/intentresolver/v2/profiles/ProfileDescriptor.java82
-rw-r--r--java/src/com/android/intentresolver/v2/profiles/ResolverMultiProfilePagerAdapter.java (renamed from java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java)4
-rw-r--r--java/src/com/android/intentresolver/v2/profiles/TabConfig.java38
-rw-r--r--java/src/com/android/intentresolver/v2/shared/model/Profile.kt (renamed from java/src/com/android/intentresolver/v2/domain/model/Profile.kt)7
-rw-r--r--java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt2
-rw-r--r--java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt2
-rw-r--r--java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt8
-rw-r--r--java/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestReader.kt2
-rw-r--r--tests/shared/src/com/android/intentresolver/v2/data/repository/FakeUserRepository.kt8
-rw-r--r--tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt98
-rw-r--r--tests/unit/src/com/android/intentresolver/v2/ChooserActionFactoryTest.kt26
-rw-r--r--tests/unit/src/com/android/intentresolver/v2/ChooserMutableActionFactoryTest.kt3
-rw-r--r--tests/unit/src/com/android/intentresolver/v2/data/repository/FakeUserRepositoryTest.kt12
-rw-r--r--tests/unit/src/com/android/intentresolver/v2/domain/interactor/UserInteractorTest.kt30
-rw-r--r--tests/unit/src/com/android/intentresolver/v2/ext/IntentExtTest.kt15
-rw-r--r--tests/unit/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapterTest.kt (renamed from tests/unit/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt)5
-rw-r--r--tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestTest.kt2
34 files changed, 402 insertions, 306 deletions
diff --git a/AndroidManifest-lib.xml b/AndroidManifest-lib.xml
index b3a43eb3..bdb94232 100644
--- a/AndroidManifest-lib.xml
+++ b/AndroidManifest-lib.xml
@@ -32,4 +32,6 @@
<uses-permission android:name="android.permission.QUERY_CLONED_APPS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.REPORT_USAGE_STATS" />
+ <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE" />
+ <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG" />
</manifest>
diff --git a/java/src/com/android/intentresolver/ChooserActivity.java b/java/src/com/android/intentresolver/ChooserActivity.java
index 9b4582df..039fad56 100644
--- a/java/src/com/android/intentresolver/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/ChooserActivity.java
@@ -318,7 +318,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
mEnterTransitionAnimationDelegate,
new HeadlineGeneratorImpl(this),
ContentTypeHint.NONE,
- mChooserRequest.getMetadataText()
+ mChooserRequest.getMetadataText(),
+ /*isPayloadTogglingEnabled =*/ false
);
updateStickyContentPreview();
diff --git a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
index acdf6ec6..6f201ad5 100644
--- a/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUi.java
@@ -25,7 +25,6 @@ import android.content.ClipData;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
-import android.service.chooser.Flags;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -51,6 +50,7 @@ import kotlinx.coroutines.CoroutineScope;
public final class ChooserContentPreviewUi {
private final CoroutineScope mScope;
+ private final boolean mIsPayloadTogglingEnabled;
/**
* Delegate to build the default system action buttons to display in the preview layout, if/when
@@ -103,8 +103,11 @@ public final class ChooserContentPreviewUi {
TransitionElementStatusCallback transitionElementStatusCallback,
HeadlineGenerator headlineGenerator,
ContentTypeHint contentTypeHint,
- @Nullable CharSequence metadata) {
+ @Nullable CharSequence metadata,
+ // TODO: replace with the FeatureFlag ref when v1 is gone
+ boolean isPayloadTogglingEnabled) {
mScope = scope;
+ mIsPayloadTogglingEnabled = isPayloadTogglingEnabled;
mContentPreviewUi = createContentPreview(
previewData,
targetIntent,
@@ -157,8 +160,7 @@ public final class ChooserContentPreviewUi {
return fileContentPreviewUi;
}
- //TODO: use flags injection
- if (previewType == CONTENT_PREVIEW_PAYLOAD_SELECTION && Flags.chooserPayloadToggling()) {
+ if (previewType == CONTENT_PREVIEW_PAYLOAD_SELECTION && mIsPayloadTogglingEnabled) {
transitionElementStatusCallback.onAllTransitionElementsReady(); // TODO
return new ShareouselContentPreviewUi(actionFactory);
}
diff --git a/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java b/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
index c35f93b4..b0fb278e 100644
--- a/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
+++ b/java/src/com/android/intentresolver/contentpreview/ContentPreviewUi.java
@@ -30,12 +30,14 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.intentresolver.R;
import com.android.intentresolver.widget.ActionRow;
import com.android.intentresolver.widget.ScrollableImagePreviewView;
-abstract class ContentPreviewUi {
+@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+public abstract class ContentPreviewUi {
private static final int IMAGE_FADE_IN_MILLIS = 150;
static final String TAG = "ChooserPreview";
diff --git a/java/src/com/android/intentresolver/contentpreview/CursorUriReader.kt b/java/src/com/android/intentresolver/contentpreview/CursorUriReader.kt
index e9e60040..6a12f56c 100644
--- a/java/src/com/android/intentresolver/contentpreview/CursorUriReader.kt
+++ b/java/src/com/android/intentresolver/contentpreview/CursorUriReader.kt
@@ -140,7 +140,6 @@ class CursorUriReader(
cursor.extras?.getInt(CursorExtraKeys.POSITION, 0) ?: 0,
128,
) {
- // TODO: check that authority is case-sensitive for resolution reasons
it.authority != uri.authority
}
}
diff --git a/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt b/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt
index 8073cfec..3f306a80 100644
--- a/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt
+++ b/java/src/com/android/intentresolver/contentpreview/PreviewDataProvider.kt
@@ -155,7 +155,6 @@ constructor(
val extraContentUri = additionalContentUri ?: return false
return runCatching {
val authority = extraContentUri.authority
- // TODO: verify that authority is case-sensitive
records.firstOrNull { authority == it.uri.authority } == null
}
.onFailure {
diff --git a/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt b/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt
index cc89f5bf..82c09986 100644
--- a/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt
+++ b/java/src/com/android/intentresolver/contentpreview/ShareouselContentPreviewUi.kt
@@ -20,6 +20,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
+import androidx.annotation.VisibleForTesting
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
@@ -43,7 +44,8 @@ import com.android.intentresolver.contentpreview.shareousel.ui.composable.Shareo
import com.android.intentresolver.contentpreview.shareousel.ui.viewmodel.ShareouselViewModel
import com.android.intentresolver.contentpreview.shareousel.ui.viewmodel.toShareouselViewModel
-internal class ShareouselContentPreviewUi(
+@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+class ShareouselContentPreviewUi(
private val actionFactory: ActionFactory,
) : ContentPreviewUi() {
diff --git a/java/src/com/android/intentresolver/v2/ChooserActionFactory.java b/java/src/com/android/intentresolver/v2/ChooserActionFactory.java
index f9de9f4b..9077a18d 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActionFactory.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActionFactory.java
@@ -131,11 +131,12 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
Callable</* @Nullable */ View> firstVisibleImageQuery,
ActionActivityStarter activityStarter,
@Nullable ShareResultSender shareResultSender,
- Consumer</* @Nullable */ Integer> finishCallback) {
+ Consumer</* @Nullable */ Integer> finishCallback,
+ ClipboardManager clipboardManager) {
this(
context,
makeCopyButtonRunnable(
- context,
+ clipboardManager,
targetIntent,
referrerPackageName,
finishCallback,
@@ -181,13 +182,12 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
if (mShareResultSender != null) {
mEditButtonRunnable = () -> {
mShareResultSender.onActionSelected(ShareAction.SYSTEM_EDIT);
- mEditButtonRunnable.run();
+ editButtonRunnable.run();
};
if (mCopyButtonRunnable != null) {
mCopyButtonRunnable = () -> {
mShareResultSender.onActionSelected(ShareAction.SYSTEM_COPY);
- //noinspection DataFlowIssue
- mCopyButtonRunnable.run();
+ copyButtonRunnable.run();
};
}
}
@@ -245,7 +245,7 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
@Nullable
private static Runnable makeCopyButtonRunnable(
- Context context,
+ ClipboardManager clipboardManager,
Intent targetIntent,
String referrerPackageName,
Consumer<Integer> finishCallback,
@@ -261,8 +261,6 @@ public final class ChooserActionFactory implements ChooserContentPreviewUi.Actio
return null;
}
return () -> {
- ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(
- Context.CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClipAsPackage(clipData, referrerPackageName);
log.logActionSelected(EventLog.SELECTION_TYPE_COPY);
diff --git a/java/src/com/android/intentresolver/v2/ChooserActivity.java b/java/src/com/android/intentresolver/v2/ChooserActivity.java
index cdc05b95..68815067 100644
--- a/java/src/com/android/intentresolver/v2/ChooserActivity.java
+++ b/java/src/com/android/intentresolver/v2/ChooserActivity.java
@@ -47,6 +47,7 @@ import android.app.prediction.AppPredictor;
import android.app.prediction.AppTarget;
import android.app.prediction.AppTargetEvent;
import android.app.prediction.AppTargetId;
+import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
@@ -138,8 +139,6 @@ import com.android.intentresolver.model.AppPredictionServiceResolverComparator;
import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
import com.android.intentresolver.shortcuts.AppPredictorFactory;
import com.android.intentresolver.shortcuts.ShortcutLoader;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.ProfileType;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.TabConfig;
import com.android.intentresolver.v2.data.repository.DevicePolicyResources;
import com.android.intentresolver.v2.emptystate.NoAppsAvailableEmptyStateProvider;
import com.android.intentresolver.v2.emptystate.NoCrossProfileEmptyStateProvider;
@@ -148,6 +147,12 @@ import com.android.intentresolver.v2.emptystate.WorkProfilePausedEmptyStateProvi
import com.android.intentresolver.v2.platform.AppPredictionAvailable;
import com.android.intentresolver.v2.platform.ImageEditor;
import com.android.intentresolver.v2.platform.NearbyShare;
+import com.android.intentresolver.v2.profiles.ChooserMultiProfilePagerAdapter;
+import com.android.intentresolver.v2.profiles.MultiProfilePagerAdapter;
+import com.android.intentresolver.v2.profiles.MultiProfilePagerAdapter.ProfileType;
+import com.android.intentresolver.v2.profiles.OnProfileSelectedListener;
+import com.android.intentresolver.v2.profiles.OnSwitchOnWorkSelectedListener;
+import com.android.intentresolver.v2.profiles.TabConfig;
import com.android.intentresolver.v2.ui.ActionTitle;
import com.android.intentresolver.v2.ui.ShareResultSender;
import com.android.intentresolver.v2.ui.ShareResultSenderFactory;
@@ -245,7 +250,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
private ResolverActivity.PickTargetOptionRequest mPickOptionRequest;
@Nullable
- private MultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
+ private OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
@@ -278,6 +283,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
@Inject public TargetDataLoader mTargetDataLoader;
@Inject public DevicePolicyResources mDevicePolicyResources;
@Inject public PackageManager mPackageManager;
+ @Inject public ClipboardManager mClipboardManager;
@Inject public IntentForwarding mIntentForwarding;
@Inject public ShareResultSenderFactory mShareResultSenderFactory;
@Nullable
@@ -485,7 +491,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
.get(BasePreviewViewModel.class);
previewViewModel.init(
chooserRequest.getTargetIntent(),
- getIntent(),
+ mActivityLaunch.getIntent(),
chooserRequest.getAdditionalContentUri(),
chooserRequest.getFocusedItemPosition(),
mChooserServiceFeatureFlags.chooserPayloadToggling());
@@ -493,7 +499,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
ChooserContentPreviewUi.ActionFactory actionFactory = chooserActionFactory;
if (previewViewModel.getPreviewDataProvider().getPreviewType()
== CONTENT_PREVIEW_PAYLOAD_SELECTION
- && android.service.chooser.Flags.chooserPayloadToggling()) {
+ && mChooserServiceFeatureFlags.chooserPayloadToggling()) {
PayloadToggleInteractor payloadToggleInteractor =
previewViewModel.getPayloadToggleInteractor();
if (payloadToggleInteractor != null) {
@@ -515,8 +521,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
mEnterTransitionAnimationDelegate,
new HeadlineGeneratorImpl(this),
chooserRequest.getContentTypeHint(),
- chooserRequest.getMetadataText()
- );
+ chooserRequest.getMetadataText(),
+ mChooserServiceFeatureFlags.chooserPayloadToggling());
updateStickyContentPreview();
if (shouldShowStickyContentPreview()
|| mChooserMultiProfilePagerAdapter
@@ -807,10 +813,6 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
mChooserMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
}
- public boolean super_shouldAutoLaunchSingleChoice(TargetInfo target) {
- return !target.isSuspended();
- }
-
/** Start the activity specified by the {@link TargetInfo}.*/
public final void safelyStartActivity(TargetInfo cti) {
// In case cloned apps are present, we would want to start those apps in cloned user
@@ -1169,7 +1171,7 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
R.layout.resolver_profile_tab_button,
com.android.internal.R.id.profile_pager,
() -> onProfileTabSelected(viewPager.getCurrentItem()),
- new MultiProfilePagerAdapter.OnProfileSelectedListener() {
+ new OnProfileSelectedListener() {
@Override
public void onProfilePageSelected(@ProfileType int profileId, int pageNumber) {}
@@ -1652,14 +1654,12 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
}
public boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
- // Note that this is only safe because the Intent handled by the ChooserActivity is
- // guaranteed to contain no extras unknown to the local ClassLoader. That is why this
- // method can not be replaced in the ResolverActivity whole hog.
- if (!super_shouldAutoLaunchSingleChoice(target)) {
+ if (target.isSuspended()) {
return false;
}
- return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, true);
+ return mActivityLaunch.getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE,
+ true);
}
private void showTargetDetails(TargetInfo targetInfo) {
@@ -2155,7 +2155,8 @@ public class ChooserActivity extends Hilt_ChooserActivity implements
setResult(status);
}
finish();
- });
+ },
+ mClipboardManager);
}
/*
diff --git a/java/src/com/android/intentresolver/v2/ResolverActivity.java b/java/src/com/android/intentresolver/v2/ResolverActivity.java
index 77d1dbf5..241b6735 100644
--- a/java/src/com/android/intentresolver/v2/ResolverActivity.java
+++ b/java/src/com/android/intentresolver/v2/ResolverActivity.java
@@ -100,15 +100,18 @@ import com.android.intentresolver.emptystate.EmptyStateProvider;
import com.android.intentresolver.icons.DefaultTargetDataLoader;
import com.android.intentresolver.icons.TargetDataLoader;
import com.android.intentresolver.model.ResolverRankerServiceResolverComparator;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.ProfileType;
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.TabConfig;
import com.android.intentresolver.v2.data.repository.DevicePolicyResources;
-import com.android.intentresolver.v2.domain.model.Profile;
+import com.android.intentresolver.v2.shared.model.Profile;
import com.android.intentresolver.v2.emptystate.NoAppsAvailableEmptyStateProvider;
import com.android.intentresolver.v2.emptystate.NoCrossProfileEmptyStateProvider;
import com.android.intentresolver.v2.emptystate.NoCrossProfileEmptyStateProvider.DevicePolicyBlockerEmptyState;
import com.android.intentresolver.v2.emptystate.WorkProfilePausedEmptyStateProvider;
+import com.android.intentresolver.v2.profiles.MultiProfilePagerAdapter;
+import com.android.intentresolver.v2.profiles.OnSwitchOnWorkSelectedListener;
+import com.android.intentresolver.v2.profiles.MultiProfilePagerAdapter.ProfileType;
+import com.android.intentresolver.v2.profiles.OnProfileSelectedListener;
+import com.android.intentresolver.v2.profiles.TabConfig;
+import com.android.intentresolver.v2.profiles.ResolverMultiProfilePagerAdapter;
import com.android.intentresolver.v2.ui.ActionTitle;
import com.android.intentresolver.v2.ui.model.ActivityLaunch;
import com.android.intentresolver.v2.ui.model.ResolverRequest;
@@ -1865,7 +1868,7 @@ public class ResolverActivity extends Hilt_ResolverActivity implements
R.layout.resolver_profile_tab_button,
com.android.internal.R.id.profile_pager,
() -> onProfileTabSelected(viewPager.getCurrentItem()),
- new MultiProfilePagerAdapter.OnProfileSelectedListener() {
+ new OnProfileSelectedListener() {
@Override
public void onProfilePageSelected(@ProfileType int profileId, int pageNumber) {
resetButtonBar();
diff --git a/java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt b/java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt
index f12d8197..c8df9684 100644
--- a/java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt
+++ b/java/src/com/android/intentresolver/v2/domain/interactor/UserInteractor.kt
@@ -19,8 +19,8 @@ package com.android.intentresolver.v2.domain.interactor
import android.os.UserHandle
import com.android.intentresolver.inject.ApplicationUser
import com.android.intentresolver.v2.data.repository.UserRepository
-import com.android.intentresolver.v2.domain.model.Profile
-import com.android.intentresolver.v2.domain.model.Profile.Type
+import com.android.intentresolver.v2.shared.model.Profile
+import com.android.intentresolver.v2.shared.model.Profile.Type
import com.android.intentresolver.v2.shared.model.User
import com.android.intentresolver.v2.shared.model.User.Role
import javax.inject.Inject
diff --git a/java/src/com/android/intentresolver/v2/ext/IntentExt.kt b/java/src/com/android/intentresolver/v2/ext/IntentExt.kt
index 7aa8e036..8c2d7277 100644
--- a/java/src/com/android/intentresolver/v2/ext/IntentExt.kt
+++ b/java/src/com/android/intentresolver/v2/ext/IntentExt.kt
@@ -32,8 +32,14 @@ inline fun Intent.ifMatch(
/** True if the Intent has one of the specified actions. */
fun Intent.hasAction(vararg actions: String): Boolean = action in actions
+/** True if the Intent has a specific component target */
+fun Intent.hasComponent(): Boolean = (component != null)
+
/** True if the Intent has a single matching category. */
fun Intent.hasSingleCategory(category: String) = categories.singleOrNull() == category
+/** True if the Intent is a SEND or SEND_MULTIPLE action. */
+fun Intent.hasSendAction() = hasAction(Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE)
+
/** True if the Intent resolves to the special Home (Launcher) component */
fun Intent.isHomeIntent() = hasAction(Intent.ACTION_MAIN) && hasSingleCategory(Intent.CATEGORY_HOME)
diff --git a/java/src/com/android/intentresolver/v2/profiles/AdapterBinder.java b/java/src/com/android/intentresolver/v2/profiles/AdapterBinder.java
new file mode 100644
index 00000000..c5b35273
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/AdapterBinder.java
@@ -0,0 +1,31 @@
+/*
+ * 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.v2.profiles;
+
+/**
+ * Delegate to set up a given adapter and page view to be used together.
+ *
+ * @param <PageViewT> (as in {@link MultiProfilePagerAdapter}).
+ * @param <SinglePageAdapterT> (as in {@link MultiProfilePagerAdapter}).
+ */
+public interface AdapterBinder<PageViewT, SinglePageAdapterT> {
+ /**
+ * The given {@code view} will be associated with the given {@code adapter}. Do any work
+ * necessary to configure them compatibly, introduce them to each other, etc.
+ */
+ void bind(PageViewT view, SinglePageAdapterT adapter);
+}
diff --git a/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/profiles/ChooserMultiProfilePagerAdapter.java
index 42eb077b..0ee9d141 100644
--- a/java/src/com/android/intentresolver/v2/ChooserMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/v2/profiles/ChooserMultiProfilePagerAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.intentresolver.v2;
+package com.android.intentresolver.v2.profiles;
import android.content.Context;
import android.os.UserHandle;
diff --git a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapter.java
index 79403095..43785db3 100644
--- a/java/src/com/android/intentresolver/v2/MultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.intentresolver.v2;
+package com.android.intentresolver.v2.profiles;
import android.annotation.IntDef;
import android.annotation.Nullable;
@@ -32,7 +32,6 @@ import androidx.viewpager.widget.ViewPager;
import com.android.intentresolver.ResolverListAdapter;
import com.android.intentresolver.emptystate.EmptyState;
import com.android.intentresolver.emptystate.EmptyStateProvider;
-import com.android.intentresolver.v2.emptystate.EmptyStateUiHelper;
import com.android.internal.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
@@ -48,20 +47,6 @@ import java.util.function.Supplier;
/**
* Skeletal {@link PagerAdapter} implementation for a UI with per-profile tabs (as in Sharesheet).
- * <p>
- * TODO: attempt to further restrict visibility/improve encapsulation in the methods we expose.
- * <p>
- * TODO: deprecate and audit/fix usages of any methods that refer to the "active" or "inactive"
- * <p>
- * adapters; these were marked {@link VisibleForTesting} and their usage seems like an accident
- * waiting to happen since clients seem to make assumptions about which adapter will be "active" in
- * a particular context, and more explicit APIs would make sure those were valid.
- * <p>
- * TODO: consider renaming legacy methods (e.g. why do we know it's a "list", not just a "page"?)
- * <p>
- * TODO: this is part of an in-progress refactor to merge with `GenericMultiProfilePagerAdapter`.
- * As originally noted there, we've reduced explicit references to the `ResolverListAdapter` base
- * type and may be able to drop the type constraint.
*
* @param <PageViewT> the type of the widget that represents the contents of a page in this adapter
* @param <SinglePageAdapterT> the type of a "root" adapter class to be instantiated and included in
@@ -71,24 +56,11 @@ import java.util.function.Supplier;
* be possible to get the list adapter from the page adapter via our
* <code>mListAdapterExtractor</code>.
*/
-class MultiProfilePagerAdapter<
+public class MultiProfilePagerAdapter<
PageViewT extends ViewGroup,
SinglePageAdapterT,
ListAdapterT extends ResolverListAdapter> extends PagerAdapter {
- /**
- * Delegate to set up a given adapter and page view to be used together.
- * @param <PageViewT> (as in {@link MultiProfilePagerAdapter}).
- * @param <SinglePageAdapterT> (as in {@link MultiProfilePagerAdapter}).
- */
- public interface AdapterBinder<PageViewT, SinglePageAdapterT> {
- /**
- * The given {@code view} will be associated with the given {@code adapter}. Do any work
- * necessary to configure them compatibly, introduce them to each other, etc.
- */
- void bind(PageViewT view, SinglePageAdapterT adapter);
- }
-
public static final int PROFILE_PERSONAL = 0;
public static final int PROFILE_WORK = 1;
@@ -110,27 +82,6 @@ class MultiProfilePagerAdapter<
private int mCurrentPage;
private OnProfileSelectedListener mOnProfileSelectedListener;
- public static class TabConfig<PageAdapterT> {
- private final @ProfileType int mProfile;
- private final String mTabLabel;
- private final String mTabAccessibilityLabel;
- private final String mTabTag;
- private final PageAdapterT mPageAdapter;
-
- public TabConfig(
- @ProfileType int profile,
- String tabLabel,
- String tabAccessibilityLabel,
- String tabTag,
- PageAdapterT pageAdapter) {
- mProfile = profile;
- mTabLabel = tabLabel;
- mTabAccessibilityLabel = tabAccessibilityLabel;
- mTabTag = tabTag;
- mPageAdapter = pageAdapter;
- }
- }
-
protected MultiProfilePagerAdapter(
Function<SinglePageAdapterT, ListAdapterT> listAdapterExtractor,
AdapterBinder<PageViewT, SinglePageAdapterT> adapterBinder,
@@ -291,7 +242,7 @@ class MultiProfilePagerAdapter<
int tabButtonLayoutResId,
int tabPageContentViewId,
Runnable onTabChangeListener,
- MultiProfilePagerAdapter.OnProfileSelectedListener clientOnProfileSelectedListener) {
+ OnProfileSelectedListener clientOnProfileSelectedListener) {
tabHost.setup();
viewPager.setSaveEnabled(false);
@@ -325,7 +276,7 @@ class MultiProfilePagerAdapter<
viewPager.setVisibility(View.VISIBLE);
tabHost.setCurrentTab(getCurrentPage());
mOnProfileSelectedListener =
- new MultiProfilePagerAdapter.OnProfileSelectedListener() {
+ new OnProfileSelectedListener() {
@Override
public void onProfilePageSelected(@ProfileType int profileId, int pageNumber) {
tabHost.setCurrentTab(pageNumber);
@@ -457,7 +408,7 @@ class MultiProfilePagerAdapter<
}
public final PageViewT getListViewForIndex(int index) {
- return getItem(index).mView;
+ return getItem(index).getView();
}
/**
@@ -471,7 +422,7 @@ class MultiProfilePagerAdapter<
if (!hasPageForIndex(index)) {
return null;
}
- return getItem(index).mAdapter;
+ return getItem(index).getAdapter();
}
/**
@@ -692,18 +643,6 @@ class MultiProfilePagerAdapter<
showEmptyState(listAdapter, emptyState, clickListener);
}
- /**
- * Class to get user id of the current process
- */
- public static class MyUserIdProvider {
- /**
- * @return user id of the current process
- */
- public int getMyUserId() {
- return UserHandle.myUserId();
- }
- }
-
private void showEmptyState(
ListAdapterT activeListAdapter,
EmptyState emptyState,
@@ -750,86 +689,4 @@ class MultiProfilePagerAdapter<
&& mWorkProfileQuietModeChecker.get());
}
- // TODO: `ChooserActivity` also has a per-profile record type. Maybe the "multi-profile pager"
- // should be the owner of all per-profile data (especially now that the API is generic)?
- private static class ProfileDescriptor<PageViewT, SinglePageAdapterT> {
- final @ProfileType int mProfile;
- final String mTabLabel;
- final String mTabAccessibilityLabel;
- final String mTabTag;
-
- final ViewGroup mRootView;
- final EmptyStateUiHelper mEmptyStateUi;
-
- // TODO: post-refactoring, we may not need to retain these ivars directly (since they may
- // be encapsulated within the `EmptyStateUiHelper`?).
- private final ViewGroup mEmptyStateView;
-
- private final SinglePageAdapterT mAdapter;
- private final PageViewT mView;
-
- ProfileDescriptor(
- @ProfileType int forProfile,
- String tabLabel,
- String tabAccessibilityLabel,
- String tabTag,
- ViewGroup rootView,
- SinglePageAdapterT adapter,
- Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) {
- mProfile = forProfile;
- mTabLabel = tabLabel;
- mTabAccessibilityLabel = tabAccessibilityLabel;
- mTabTag = tabTag;
- mRootView = rootView;
- mAdapter = adapter;
- mEmptyStateView = rootView.findViewById(com.android.internal.R.id.resolver_empty_state);
- mView = (PageViewT) rootView.findViewById(com.android.internal.R.id.resolver_list);
- mEmptyStateUi = new EmptyStateUiHelper(
- rootView,
- com.android.internal.R.id.resolver_list,
- containerBottomPaddingOverrideSupplier);
- }
-
- protected ViewGroup getEmptyStateView() {
- return mEmptyStateView;
- }
-
- private void setupContainerPadding() {
- mEmptyStateUi.setupContainerPadding();
- }
- }
-
- /** Listener interface for changes between the per-profile UI tabs. */
- public interface OnProfileSelectedListener {
- /**
- * Callback for when the user changes the active tab.
- * <p>This callback is only called when the intent resolver or share sheet shows
- * more than one profile.
- * @param profileId the ID of the newly-selected profile, e.g. {@link #PROFILE_PERSONAL}
- * if the personal profile tab was selected or {@link #PROFILE_WORK} if the work profile tab
- * was selected.
- */
- void onProfilePageSelected(@ProfileType int profileId, int pageNumber);
-
-
- /**
- * Callback for when the scroll state changes. Useful for discovering when the user begins
- * dragging, when the pager is automatically settling to the current page, or when it is
- * fully stopped/idle.
- * @param state {@link ViewPager#SCROLL_STATE_IDLE}, {@link ViewPager#SCROLL_STATE_DRAGGING}
- * or {@link ViewPager#SCROLL_STATE_SETTLING}
- * @see ViewPager.OnPageChangeListener#onPageScrollStateChanged
- */
- void onProfilePageStateChanged(int state);
- }
-
- /**
- * Listener for when the user switches on the work profile from the work tab.
- */
- public interface OnSwitchOnWorkSelectedListener {
- /**
- * Callback for when the user switches on the work profile from the work tab.
- */
- void onSwitchOnWorkSelected();
- }
}
diff --git a/java/src/com/android/intentresolver/v2/profiles/OnProfileSelectedListener.java b/java/src/com/android/intentresolver/v2/profiles/OnProfileSelectedListener.java
new file mode 100644
index 00000000..7bdbec4c
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/OnProfileSelectedListener.java
@@ -0,0 +1,46 @@
+/*
+ * 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.v2.profiles;
+
+import androidx.viewpager.widget.ViewPager;
+
+/** Listener interface for changes between the per-profile UI tabs. */
+public interface OnProfileSelectedListener {
+ /**
+ * Callback for when the user changes the active tab.
+ * <p>This callback is only called when the intent resolver or share sheet shows
+ * more than one profile.
+ *
+ * @param profileId the ID of the newly-selected profile, e.g. {@link #PROFILE_PERSONAL}
+ * if the personal profile tab was selected or {@link #PROFILE_WORK} if the
+ * work profile tab
+ * was selected.
+ */
+ void onProfilePageSelected(@MultiProfilePagerAdapter.ProfileType int profileId, int pageNumber);
+
+
+ /**
+ * Callback for when the scroll state changes. Useful for discovering when the user begins
+ * dragging, when the pager is automatically settling to the current page, or when it is
+ * fully stopped/idle.
+ *
+ * @param state {@link ViewPager#SCROLL_STATE_IDLE}, {@link ViewPager#SCROLL_STATE_DRAGGING}
+ * or {@link ViewPager#SCROLL_STATE_SETTLING}
+ * @see ViewPager.OnPageChangeListener#onPageScrollStateChanged
+ */
+ void onProfilePageStateChanged(int state);
+}
diff --git a/java/src/com/android/intentresolver/v2/profiles/OnSwitchOnWorkSelectedListener.java b/java/src/com/android/intentresolver/v2/profiles/OnSwitchOnWorkSelectedListener.java
new file mode 100644
index 00000000..3dbbd4d0
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/OnSwitchOnWorkSelectedListener.java
@@ -0,0 +1,27 @@
+/*
+ * 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.v2.profiles;
+
+/**
+ * Listener for when the user switches on the work profile from the work tab.
+ */
+public interface OnSwitchOnWorkSelectedListener {
+ /**
+ * Callback for when the user switches on the work profile from the work tab.
+ */
+ void onSwitchOnWorkSelected();
+}
diff --git a/java/src/com/android/intentresolver/v2/profiles/ProfileDescriptor.java b/java/src/com/android/intentresolver/v2/profiles/ProfileDescriptor.java
new file mode 100644
index 00000000..e2e9c19d
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/ProfileDescriptor.java
@@ -0,0 +1,82 @@
+/*
+ * 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.v2.profiles;
+
+import android.view.ViewGroup;
+
+import com.android.intentresolver.v2.emptystate.EmptyStateUiHelper;
+
+import java.util.Optional;
+import java.util.function.Supplier;
+
+// TODO: `ChooserActivity` also has a per-profile record type. Maybe the "multi-profile pager"
+// should be the owner of all per-profile data (especially now that the API is generic)?
+class ProfileDescriptor<PageViewT, SinglePageAdapterT> {
+ final @MultiProfilePagerAdapter.ProfileType int mProfile;
+ final String mTabLabel;
+ final String mTabAccessibilityLabel;
+ final String mTabTag;
+
+ final ViewGroup mRootView;
+ final EmptyStateUiHelper mEmptyStateUi;
+
+ // TODO: post-refactoring, we may not need to retain these ivars directly (since they may
+ // be encapsulated within the `EmptyStateUiHelper`?).
+ private final ViewGroup mEmptyStateView;
+
+ private final SinglePageAdapterT mAdapter;
+
+ public SinglePageAdapterT getAdapter() {
+ return mAdapter;
+ }
+
+ public PageViewT getView() {
+ return mView;
+ }
+
+ private final PageViewT mView;
+
+ ProfileDescriptor(
+ @MultiProfilePagerAdapter.ProfileType int forProfile,
+ String tabLabel,
+ String tabAccessibilityLabel,
+ String tabTag,
+ ViewGroup rootView,
+ SinglePageAdapterT adapter,
+ Supplier<Optional<Integer>> containerBottomPaddingOverrideSupplier) {
+ mProfile = forProfile;
+ mTabLabel = tabLabel;
+ mTabAccessibilityLabel = tabAccessibilityLabel;
+ mTabTag = tabTag;
+ mRootView = rootView;
+ mAdapter = adapter;
+ mEmptyStateView = rootView.findViewById(com.android.internal.R.id.resolver_empty_state);
+ mView = (PageViewT) rootView.findViewById(com.android.internal.R.id.resolver_list);
+ mEmptyStateUi = new EmptyStateUiHelper(
+ rootView,
+ com.android.internal.R.id.resolver_list,
+ containerBottomPaddingOverrideSupplier);
+ }
+
+ protected ViewGroup getEmptyStateView() {
+ return mEmptyStateView;
+ }
+
+ public void setupContainerPadding() {
+ mEmptyStateUi.setupContainerPadding();
+ }
+}
diff --git a/java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java b/java/src/com/android/intentresolver/v2/profiles/ResolverMultiProfilePagerAdapter.java
index c2e1ae07..e44cf8da 100644
--- a/java/src/com/android/intentresolver/v2/ResolverMultiProfilePagerAdapter.java
+++ b/java/src/com/android/intentresolver/v2/profiles/ResolverMultiProfilePagerAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.intentresolver.v2;
+package com.android.intentresolver.v2.profiles;
import android.content.Context;
import android.os.UserHandle;
diff --git a/java/src/com/android/intentresolver/v2/profiles/TabConfig.java b/java/src/com/android/intentresolver/v2/profiles/TabConfig.java
new file mode 100644
index 00000000..994f8aff
--- /dev/null
+++ b/java/src/com/android/intentresolver/v2/profiles/TabConfig.java
@@ -0,0 +1,38 @@
+/*
+ * 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.v2.profiles;
+
+public class TabConfig<PageAdapterT> {
+ final @MultiProfilePagerAdapter.ProfileType int mProfile;
+ final String mTabLabel;
+ final String mTabAccessibilityLabel;
+ final String mTabTag;
+ final PageAdapterT mPageAdapter;
+
+ public TabConfig(
+ @MultiProfilePagerAdapter.ProfileType int profile,
+ String tabLabel,
+ String tabAccessibilityLabel,
+ String tabTag,
+ PageAdapterT pageAdapter) {
+ mProfile = profile;
+ mTabLabel = tabLabel;
+ mTabAccessibilityLabel = tabAccessibilityLabel;
+ mTabTag = tabTag;
+ mPageAdapter = pageAdapter;
+ }
+}
diff --git a/java/src/com/android/intentresolver/v2/domain/model/Profile.kt b/java/src/com/android/intentresolver/v2/shared/model/Profile.kt
index 46015c7a..6e37174c 100644
--- a/java/src/com/android/intentresolver/v2/domain/model/Profile.kt
+++ b/java/src/com/android/intentresolver/v2/shared/model/Profile.kt
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package com.android.intentresolver.v2.domain.model
+package com.android.intentresolver.v2.shared.model
-import com.android.intentresolver.v2.domain.model.Profile.Type
-import com.android.intentresolver.v2.shared.model.User
+import com.android.intentresolver.v2.shared.model.Profile.Type
/**
- * A domain layer model which associates [users][User] into a [Type] instance.
+ * Associates [users][User] into a [Type] instance.
*
* This is a simple abstraction which combines a primary [user][User] with an optional
* [cloned apps][User.Role.CLONE] user. This encapsulates the cloned app user id, while still being
diff --git a/java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt b/java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt
index 0d31b23e..1cd72ba5 100644
--- a/java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt
+++ b/java/src/com/android/intentresolver/v2/ui/ProfilePagerResources.kt
@@ -19,7 +19,7 @@ package com.android.intentresolver.v2.ui
import android.content.res.Resources
import com.android.intentresolver.inject.ApplicationOwned
import com.android.intentresolver.v2.data.repository.DevicePolicyResources
-import com.android.intentresolver.v2.domain.model.Profile
+import com.android.intentresolver.v2.shared.model.Profile
import javax.inject.Inject
import com.android.intentresolver.R
diff --git a/java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt b/java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt
index 5abfb602..a4f74ca9 100644
--- a/java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt
+++ b/java/src/com/android/intentresolver/v2/ui/model/ResolverRequest.kt
@@ -19,7 +19,7 @@ package com.android.intentresolver.v2.ui.model
import android.content.Intent
import android.content.pm.ResolveInfo
import android.os.UserHandle
-import com.android.intentresolver.v2.domain.model.Profile
+import com.android.intentresolver.v2.shared.model.Profile
import com.android.intentresolver.v2.ext.isHomeIntent
/** All of the things that are consumed from an incoming Intent Resolution request (+Extras). */
diff --git a/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt b/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt
index 565d4de1..e32d69b0 100644
--- a/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt
+++ b/java/src/com/android/intentresolver/v2/ui/viewmodel/ChooserRequestReader.kt
@@ -17,8 +17,6 @@ package com.android.intentresolver.v2.ui.viewmodel
import android.content.ComponentName
import android.content.Intent
-import android.content.Intent.ACTION_SEND
-import android.content.Intent.ACTION_SEND_MULTIPLE
import android.content.Intent.EXTRA_ALTERNATE_INTENTS
import android.content.Intent.EXTRA_CHOOSER_CUSTOM_ACTIONS
import android.content.Intent.EXTRA_CHOOSER_MODIFY_SHARE_ACTION
@@ -47,7 +45,7 @@ import com.android.intentresolver.ContentTypeHint
import com.android.intentresolver.R
import com.android.intentresolver.inject.ChooserServiceFlags
import com.android.intentresolver.util.hasValidIcon
-import com.android.intentresolver.v2.ext.hasAction
+import com.android.intentresolver.v2.ext.hasSendAction
import com.android.intentresolver.v2.ext.ifMatch
import com.android.intentresolver.v2.ui.model.ActivityLaunch
import com.android.intentresolver.v2.ui.model.ChooserRequest
@@ -60,8 +58,6 @@ import com.android.intentresolver.v2.validation.validateFrom
private const val MAX_CHOOSER_ACTIONS = 5
private const val MAX_INITIAL_INTENTS = 2
-private fun Intent.hasSendAction() = hasAction(ACTION_SEND, ACTION_SEND_MULTIPLE)
-
internal fun Intent.maybeAddSendActionFlags() =
ifMatch(Intent::hasSendAction) {
addFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
@@ -77,7 +73,7 @@ fun readChooserRequest(
return validateFrom(extras::get) {
val targetIntent = required(IntentOrUri(EXTRA_INTENT)).maybeAddSendActionFlags()
- val isSendAction = targetIntent.hasAction(ACTION_SEND, ACTION_SEND_MULTIPLE)
+ val isSendAction = targetIntent.hasSendAction()
val additionalTargets =
optional(array<Intent>(EXTRA_ALTERNATE_INTENTS))?.map { it.maybeAddSendActionFlags() }
diff --git a/java/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestReader.kt b/java/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestReader.kt
index fc9f1e01..22d76493 100644
--- a/java/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestReader.kt
+++ b/java/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestReader.kt
@@ -20,7 +20,7 @@ import android.os.Bundle
import android.os.UserHandle
import com.android.intentresolver.v2.ResolverActivity.PROFILE_PERSONAL
import com.android.intentresolver.v2.ResolverActivity.PROFILE_WORK
-import com.android.intentresolver.v2.domain.model.Profile
+import com.android.intentresolver.v2.shared.model.Profile
import com.android.intentresolver.v2.ui.model.ActivityLaunch
import com.android.intentresolver.v2.ui.model.ResolverRequest
import com.android.intentresolver.v2.validation.Validation
diff --git a/tests/shared/src/com/android/intentresolver/v2/data/repository/FakeUserRepository.kt b/tests/shared/src/com/android/intentresolver/v2/data/repository/FakeUserRepository.kt
index 5ed6f506..73d9a084 100644
--- a/tests/shared/src/com/android/intentresolver/v2/data/repository/FakeUserRepository.kt
+++ b/tests/shared/src/com/android/intentresolver/v2/data/repository/FakeUserRepository.kt
@@ -22,7 +22,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.update
/** A simple repository which can be initialized from a list and updated. */
-class FakeUserRepository(vararg userList: User) : UserRepository {
+class FakeUserRepository(userList: List<User>) : UserRepository {
internal data class UserState(val user: User, val available: Boolean)
private val userState = MutableStateFlow(userList.map { UserState(it, available = true) })
@@ -47,7 +47,7 @@ class FakeUserRepository(vararg userList: User) : UserRepository {
override val availability =
userState.map { userStateList -> userStateList.associate { it.user to it.available } }
- override suspend fun requestState(user: User, available: Boolean) {
+ fun updateState(user: User, available: Boolean) {
userState.update { userStateList ->
userStateList.map { userState ->
if (userState.user.id == user.id) {
@@ -58,4 +58,8 @@ class FakeUserRepository(vararg userList: User) : UserRepository {
}
}
}
+
+ override suspend fun requestState(user: User, available: Boolean) {
+ updateState(user, available)
+ }
}
diff --git a/tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt b/tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
index ad53eef4..c7c3c516 100644
--- a/tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
+++ b/tests/unit/src/com/android/intentresolver/contentpreview/ChooserContentPreviewUiTest.kt
@@ -18,7 +18,6 @@ package com.android.intentresolver.contentpreview
import android.content.Intent
import android.net.Uri
-import android.platform.test.annotations.RequiresFlagsDisabled
import android.platform.test.flag.junit.CheckFlagsRule
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import com.android.intentresolver.ContentTypeHint
@@ -49,29 +48,40 @@ class ChooserContentPreviewUiTest {
private val actionFactory =
object : ActionFactory {
override fun getCopyButtonRunnable(): Runnable? = null
+
override fun getEditButtonRunnable(): Runnable? = null
+
override fun createCustomActions(): List<ActionRow.Action> = emptyList()
+
override fun getModifyShareAction(): ActionRow.Action? = null
+
override fun getExcludeSharedTextAction(): Consumer<Boolean> = Consumer<Boolean> {}
}
private val transitionCallback = mock<ImagePreviewView.TransitionElementStatusCallback>()
@get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+ private fun createContentPreviewUi(
+ targetIntent: Intent,
+ isPayloadTogglingEnabled: Boolean = false
+ ) =
+ ChooserContentPreviewUi(
+ testScope,
+ previewData,
+ targetIntent,
+ imageLoader,
+ actionFactory,
+ transitionCallback,
+ headlineGenerator,
+ ContentTypeHint.NONE,
+ testMetadataText,
+ isPayloadTogglingEnabled,
+ )
+
@Test
fun test_textPreviewType_useTextPreviewUi() {
whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_TEXT)
- val testSubject =
- ChooserContentPreviewUi(
- testScope,
- previewData,
- Intent(Intent.ACTION_VIEW),
- imageLoader,
- actionFactory,
- transitionCallback,
- headlineGenerator,
- ContentTypeHint.NONE,
- testMetadataText,
- )
+ val testSubject = createContentPreviewUi(targetIntent = Intent(Intent.ACTION_VIEW))
+
assertThat(testSubject.preferredContentPreview)
.isEqualTo(ContentPreviewType.CONTENT_PREVIEW_TEXT)
assertThat(testSubject.mContentPreviewUi).isInstanceOf(TextContentPreviewUi::class.java)
@@ -81,18 +91,7 @@ class ChooserContentPreviewUiTest {
@Test
fun test_filePreviewType_useFilePreviewUi() {
whenever(previewData.previewType).thenReturn(ContentPreviewType.CONTENT_PREVIEW_FILE)
- val testSubject =
- ChooserContentPreviewUi(
- testScope,
- previewData,
- Intent(Intent.ACTION_SEND),
- imageLoader,
- actionFactory,
- transitionCallback,
- headlineGenerator,
- ContentTypeHint.NONE,
- testMetadataText,
- )
+ val testSubject = createContentPreviewUi(targetIntent = Intent(Intent.ACTION_SEND))
assertThat(testSubject.preferredContentPreview)
.isEqualTo(ContentPreviewType.CONTENT_PREVIEW_FILE)
assertThat(testSubject.mContentPreviewUi).isInstanceOf(FileContentPreviewUi::class.java)
@@ -108,16 +107,9 @@ class ChooserContentPreviewUiTest {
.thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
whenever(previewData.imagePreviewFileInfoFlow).thenReturn(MutableSharedFlow())
val testSubject =
- ChooserContentPreviewUi(
- testScope,
- previewData,
- Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_TEXT, "Shared text") },
- imageLoader,
- actionFactory,
- transitionCallback,
- headlineGenerator,
- ContentTypeHint.NONE,
- testMetadataText,
+ createContentPreviewUi(
+ targetIntent =
+ Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_TEXT, "Shared text") }
)
assertThat(testSubject.mContentPreviewUi)
.isInstanceOf(FilesPlusTextContentPreviewUi::class.java)
@@ -133,18 +125,7 @@ class ChooserContentPreviewUiTest {
whenever(previewData.firstFileInfo)
.thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
whenever(previewData.imagePreviewFileInfoFlow).thenReturn(MutableSharedFlow())
- val testSubject =
- ChooserContentPreviewUi(
- testScope,
- previewData,
- Intent(Intent.ACTION_SEND),
- imageLoader,
- actionFactory,
- transitionCallback,
- headlineGenerator,
- ContentTypeHint.NONE,
- testMetadataText,
- )
+ val testSubject = createContentPreviewUi(targetIntent = Intent(Intent.ACTION_SEND))
assertThat(testSubject.preferredContentPreview)
.isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
assertThat(testSubject.mContentPreviewUi).isInstanceOf(UnifiedContentPreviewUi::class.java)
@@ -153,8 +134,7 @@ class ChooserContentPreviewUiTest {
}
@Test
- @RequiresFlagsDisabled(android.service.chooser.Flags.FLAG_CHOOSER_PAYLOAD_TOGGLING)
- fun test_imagePayloadSelectionType_useImagePreviewUi() {
+ fun test_imagePayloadSelectionTypeWithEnabledFlag_usePayloadSelectionPreviewUi() {
// Event if we returned wrong type due to a bug, we should not use payload selection UI
val uri = Uri.parse("content://org.pkg.app/img.png")
whenever(previewData.previewType)
@@ -164,21 +144,11 @@ class ChooserContentPreviewUiTest {
.thenReturn(FileInfo.Builder(uri).withPreviewUri(uri).withMimeType("image/png").build())
whenever(previewData.imagePreviewFileInfoFlow).thenReturn(MutableSharedFlow())
val testSubject =
- ChooserContentPreviewUi(
- testScope,
- previewData,
- Intent(Intent.ACTION_SEND),
- imageLoader,
- actionFactory,
- transitionCallback,
- headlineGenerator,
- ContentTypeHint.NONE,
- testMetadataText,
+ createContentPreviewUi(
+ targetIntent = Intent(Intent.ACTION_SEND),
+ isPayloadTogglingEnabled = true
)
- assertThat(testSubject.preferredContentPreview)
- .isEqualTo(ContentPreviewType.CONTENT_PREVIEW_IMAGE)
- assertThat(testSubject.mContentPreviewUi).isInstanceOf(UnifiedContentPreviewUi::class.java)
- verify(previewData, times(1)).imagePreviewFileInfoFlow
- verify(transitionCallback, never()).onAllTransitionElementsReady()
+ assertThat(testSubject.mContentPreviewUi)
+ .isInstanceOf(ShareouselContentPreviewUi::class.java)
}
}
diff --git a/tests/unit/src/com/android/intentresolver/v2/ChooserActionFactoryTest.kt b/tests/unit/src/com/android/intentresolver/v2/ChooserActionFactoryTest.kt
index 717d26bd..95e4c377 100644
--- a/tests/unit/src/com/android/intentresolver/v2/ChooserActionFactoryTest.kt
+++ b/tests/unit/src/com/android/intentresolver/v2/ChooserActionFactoryTest.kt
@@ -31,6 +31,8 @@ import androidx.test.platform.app.InstrumentationRegistry
import com.android.intentresolver.ChooserRequestParameters
import com.android.intentresolver.logging.EventLog
import com.android.intentresolver.mock
+import com.android.intentresolver.v2.ui.ShareResultSender
+import com.android.intentresolver.v2.ui.model.ShareAction
import com.android.intentresolver.whenever
import com.google.common.collect.ImmutableList
import com.google.common.truth.Truth.assertThat
@@ -45,7 +47,9 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mockito
+import org.mockito.Mockito.eq
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
@RunWith(AndroidJUnit4::class)
class ChooserActionFactoryTest {
@@ -94,7 +98,7 @@ class ChooserActionFactoryTest {
// click it
customActions[0].onClicked.run()
- Mockito.verify(logger).logCustomActionSelected(eq(0))
+ verify(logger).logCustomActionSelected(eq(0))
assertEquals(Activity.RESULT_OK, resultConsumer.latestReturn)
// Verify the pending intent has been called
assertTrue("Timed out waiting for broadcast", countdown.await(2500, TimeUnit.MILLISECONDS))
@@ -114,7 +118,7 @@ class ChooserActionFactoryTest {
val action = factory.modifyShareAction ?: error("Modify share action should not be null")
action.onClicked.run()
- Mockito.verify(logger).logActionSelected(eq(EventLog.SELECTION_TYPE_MODIFY_SHARE))
+ verify(logger).logActionSelected(eq(EventLog.SELECTION_TYPE_MODIFY_SHARE))
assertEquals(Activity.RESULT_OK, resultConsumer.latestReturn)
// Verify the pending intent has been called
assertTrue("Timed out waiting for broadcast", countdown.await(2500, TimeUnit.MILLISECONDS))
@@ -146,6 +150,7 @@ class ChooserActionFactoryTest {
/* activityStarter = */ mock(),
/* shareResultSender = */ null,
/* finishCallback = */ {},
+ /* clipboardManager = */ mock(),
)
assertThat(testSubject.copyButtonRunnable).isNull()
}
@@ -173,12 +178,13 @@ class ChooserActionFactoryTest {
/* activityStarter = */ mock(),
/* shareResultSender = */ null,
/* finishCallback = */ {},
+ /* clipboardManager = */ mock(),
)
assertThat(testSubject.copyButtonRunnable).isNull()
}
@Test
- fun sendActionWithText_nonNullCopyRunnable() {
+ fun sendActionWithTextCopyRunnable() {
val targetIntent = Intent(Intent.ACTION_SEND).apply { putExtra(Intent.EXTRA_TEXT, "Text") }
val chooserRequest =
@@ -186,6 +192,8 @@ class ChooserActionFactoryTest {
whenever(this.targetIntent).thenReturn(targetIntent)
whenever(chooserActions).thenReturn(ImmutableList.of())
}
+
+ val resultSender = mock<ShareResultSender>()
val testSubject =
ChooserActionFactory(
/* context = */ context,
@@ -198,10 +206,15 @@ class ChooserActionFactoryTest {
/* onUpdateSharedTextIsExcluded = */ {},
/* firstVisibleImageQuery = */ { null },
/* activityStarter = */ mock(),
- /* shareResultSender = */ null,
+ /* shareResultSender = */ resultSender,
/* finishCallback = */ {},
+ /* clipboardManager = */ mock(),
)
assertThat(testSubject.copyButtonRunnable).isNotNull()
+
+ testSubject.copyButtonRunnable?.run()
+
+ verify(resultSender, times(1)).onActionSelected(ShareAction.SYSTEM_COPY)
}
private fun createFactory(includeModifyShare: Boolean = false): ChooserActionFactory {
@@ -242,7 +255,8 @@ class ChooserActionFactoryTest {
/* firstVisibleImageQuery = */ { null },
/* activityStarter = */ mock(),
/* shareResultSender = */ null,
- /* finishCallback = */ resultConsumer
+ /* finishCallback = */ resultConsumer,
+ /* clipboardManager = */ mock(),
)
}
}
diff --git a/tests/unit/src/com/android/intentresolver/v2/ChooserMutableActionFactoryTest.kt b/tests/unit/src/com/android/intentresolver/v2/ChooserMutableActionFactoryTest.kt
index 42702cef..ec2b807d 100644
--- a/tests/unit/src/com/android/intentresolver/v2/ChooserMutableActionFactoryTest.kt
+++ b/tests/unit/src/com/android/intentresolver/v2/ChooserMutableActionFactoryTest.kt
@@ -110,7 +110,8 @@ class ChooserMutableActionFactoryTest {
/* firstVisibleImageQuery = */ { null },
/* activityStarter = */ mock(),
/* shareResultSender = */ null,
- /* finishCallback = */ resultConsumer
+ /* finishCallback = */ resultConsumer,
+ mock()
)
}
diff --git a/tests/unit/src/com/android/intentresolver/v2/data/repository/FakeUserRepositoryTest.kt b/tests/unit/src/com/android/intentresolver/v2/data/repository/FakeUserRepositoryTest.kt
index 334f31ad..d10ea8d0 100644
--- a/tests/unit/src/com/android/intentresolver/v2/data/repository/FakeUserRepositoryTest.kt
+++ b/tests/unit/src/com/android/intentresolver/v2/data/repository/FakeUserRepositoryTest.kt
@@ -33,7 +33,7 @@ class FakeUserRepositoryTest {
@Test
fun init() = runTest {
- val repo = FakeUserRepository(personalUser, workUser, privateUser)
+ val repo = FakeUserRepository(listOf(personalUser, workUser, privateUser))
val users by collectLastValue(repo.users)
assertThat(users).containsExactly(personalUser, workUser, privateUser)
@@ -41,7 +41,7 @@ class FakeUserRepositoryTest {
@Test
fun addUser() = runTest {
- val repo = FakeUserRepository()
+ val repo = FakeUserRepository(emptyList())
val users by collectLastValue(repo.users)
assertThat(users).isEmpty()
@@ -55,7 +55,7 @@ class FakeUserRepositoryTest {
@Test
fun removeUser() = runTest {
- val repo = FakeUserRepository(personalUser, workUser)
+ val repo = FakeUserRepository(listOf(personalUser, workUser))
val users by collectLastValue(repo.users)
repo.removeUser(workUser)
@@ -67,7 +67,7 @@ class FakeUserRepositoryTest {
@Test
fun isAvailable_defaultValue() = runTest {
- val repo = FakeUserRepository(personalUser, workUser)
+ val repo = FakeUserRepository(listOf(personalUser, workUser))
val available by collectLastValue(repo.availability)
@@ -80,7 +80,7 @@ class FakeUserRepositoryTest {
@Test
fun isAvailable() = runTest {
- val repo = FakeUserRepository(personalUser, workUser)
+ val repo = FakeUserRepository(listOf(personalUser, workUser))
val available by collectLastValue(repo.availability)
assertThat(available!![workUser]).isTrue()
@@ -94,7 +94,7 @@ class FakeUserRepositoryTest {
@Test
fun isAvailable_addRemove() = runTest {
- val repo = FakeUserRepository(personalUser, workUser)
+ val repo = FakeUserRepository(listOf(personalUser, workUser))
val available by collectLastValue(repo.availability)
assertThat(available!![workUser]).isTrue()
diff --git a/tests/unit/src/com/android/intentresolver/v2/domain/interactor/UserInteractorTest.kt b/tests/unit/src/com/android/intentresolver/v2/domain/interactor/UserInteractorTest.kt
index 4d246b9a..b66fabfd 100644
--- a/tests/unit/src/com/android/intentresolver/v2/domain/interactor/UserInteractorTest.kt
+++ b/tests/unit/src/com/android/intentresolver/v2/domain/interactor/UserInteractorTest.kt
@@ -18,10 +18,10 @@ package com.android.intentresolver.v2.domain.interactor
import com.android.intentresolver.v2.coroutines.collectLastValue
import com.android.intentresolver.v2.data.repository.FakeUserRepository
-import com.android.intentresolver.v2.domain.model.Profile
-import com.android.intentresolver.v2.domain.model.Profile.Type.PERSONAL
-import com.android.intentresolver.v2.domain.model.Profile.Type.PRIVATE
-import com.android.intentresolver.v2.domain.model.Profile.Type.WORK
+import com.android.intentresolver.v2.shared.model.Profile
+import com.android.intentresolver.v2.shared.model.Profile.Type.PERSONAL
+import com.android.intentresolver.v2.shared.model.Profile.Type.PRIVATE
+import com.android.intentresolver.v2.shared.model.Profile.Type.WORK
import com.android.intentresolver.v2.shared.model.User
import com.android.intentresolver.v2.shared.model.User.Role
import com.google.common.truth.Truth.assertThat
@@ -45,7 +45,7 @@ class UserInteractorTest {
fun launchedByProfile(): Unit = runTest {
val profileInteractor =
UserInteractor(
- userRepository = FakeUserRepository(personalUser, cloneUser),
+ userRepository = FakeUserRepository(listOf(personalUser, cloneUser)),
launchedAs = personalUser.handle
)
@@ -58,7 +58,7 @@ class UserInteractorTest {
fun launchedByProfile_asClone(): Unit = runTest {
val profileInteractor =
UserInteractor(
- userRepository = FakeUserRepository(personalUser, cloneUser),
+ userRepository = FakeUserRepository(listOf(personalUser, cloneUser)),
launchedAs = cloneUser.handle
)
val profiles by collectLastValue(profileInteractor.launchedAsProfile)
@@ -70,7 +70,7 @@ class UserInteractorTest {
fun profiles_withPersonal(): Unit = runTest {
val profileInteractor =
UserInteractor(
- userRepository = FakeUserRepository(personalUser),
+ userRepository = FakeUserRepository(listOf(personalUser)),
launchedAs = personalUser.handle
)
@@ -81,7 +81,7 @@ class UserInteractorTest {
@Test
fun profiles_addClone(): Unit = runTest {
- val fakeUserRepo = FakeUserRepository(personalUser)
+ val fakeUserRepo = FakeUserRepository(listOf(personalUser))
val profileInteractor =
UserInteractor(userRepository = fakeUserRepo, launchedAs = personalUser.handle)
@@ -96,7 +96,7 @@ class UserInteractorTest {
fun profiles_withPersonalAndClone(): Unit = runTest {
val profileInteractor =
UserInteractor(
- userRepository = FakeUserRepository(personalUser, cloneUser),
+ userRepository = FakeUserRepository(listOf(personalUser, cloneUser)),
launchedAs = personalUser.handle
)
val profiles by collectLastValue(profileInteractor.profiles)
@@ -108,7 +108,8 @@ class UserInteractorTest {
fun profiles_withAllSupportedTypes(): Unit = runTest {
val profileInteractor =
UserInteractor(
- userRepository = FakeUserRepository(personalUser, cloneUser, workUser, privateUser),
+ userRepository =
+ FakeUserRepository(listOf(personalUser, cloneUser, workUser, privateUser)),
launchedAs = personalUser.handle
)
val profiles by collectLastValue(profileInteractor.profiles)
@@ -125,7 +126,8 @@ class UserInteractorTest {
fun profiles_preservesIterationOrder(): Unit = runTest {
val profileInteractor =
UserInteractor(
- userRepository = FakeUserRepository(workUser, cloneUser, privateUser, personalUser),
+ userRepository =
+ FakeUserRepository(listOf(workUser, cloneUser, privateUser, personalUser)),
launchedAs = personalUser.handle
)
@@ -141,7 +143,7 @@ class UserInteractorTest {
@Test
fun isAvailable_defaultValue() = runTest {
- val userRepo = FakeUserRepository(personalUser)
+ val userRepo = FakeUserRepository(listOf(personalUser))
userRepo.addUser(workUser, false)
val profileInteractor =
@@ -156,7 +158,7 @@ class UserInteractorTest {
@Test
fun isAvailable() = runTest {
- val userRepo = FakeUserRepository(workUser, personalUser)
+ val userRepo = FakeUserRepository(listOf(workUser, personalUser))
val profileInteractor =
UserInteractor(userRepository = userRepo, launchedAs = personalUser.handle)
val workAvailable by collectLastValue(profileInteractor.isAvailable(WORK))
@@ -183,7 +185,7 @@ class UserInteractorTest {
*/
@Test
fun updateState() = runTest {
- val userRepo = FakeUserRepository(workUser, personalUser)
+ val userRepo = FakeUserRepository(listOf(workUser, personalUser))
val userInteractor =
UserInteractor(userRepository = userRepo, launchedAs = personalUser.handle)
val workProfile = Profile(Profile.Type.WORK, workUser)
diff --git a/tests/unit/src/com/android/intentresolver/v2/ext/IntentExtTest.kt b/tests/unit/src/com/android/intentresolver/v2/ext/IntentExtTest.kt
index 6a16168c..2ccd548a 100644
--- a/tests/unit/src/com/android/intentresolver/v2/ext/IntentExtTest.kt
+++ b/tests/unit/src/com/android/intentresolver/v2/ext/IntentExtTest.kt
@@ -15,6 +15,7 @@
*/
package com.android.intentresolver.v2.ext
+import android.content.ComponentName
import android.content.Intent
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
@@ -36,6 +37,20 @@ class IntentExtTest {
}
@Test
+ fun hasComponent() {
+ assertThat(Intent().hasComponent()).isFalse()
+ assertThat(Intent().setComponent(ComponentName("A", "B")).hasComponent()).isTrue()
+ }
+
+ @Test
+ fun hasSendAction() {
+ assertThat(Intent(Intent.ACTION_SEND).hasSendAction()).isTrue()
+ assertThat(Intent(Intent.ACTION_SEND_MULTIPLE).hasSendAction()).isTrue()
+ assertThat(Intent(Intent.ACTION_SENDTO).hasSendAction()).isFalse()
+ assertThat(Intent(Intent.ACTION_VIEW).hasSendAction()).isFalse()
+ }
+
+ @Test
fun hasSingleCategory() {
val intent = Intent().addCategory(Intent.CATEGORY_HOME)
assertThat(intent.hasSingleCategory(Intent.CATEGORY_HOME)).isTrue()
diff --git a/tests/unit/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt b/tests/unit/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapterTest.kt
index 8e5f00ac..5b6b5d99 100644
--- a/tests/unit/src/com/android/intentresolver/v2/MultiProfilePagerAdapterTest.kt
+++ b/tests/unit/src/com/android/intentresolver/v2/profiles/MultiProfilePagerAdapterTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.intentresolver.v2
+package com.android.intentresolver.v2.profiles
import android.os.UserHandle
import android.view.LayoutInflater
@@ -28,7 +28,6 @@ import com.android.intentresolver.R
import com.android.intentresolver.ResolverListAdapter
import com.android.intentresolver.emptystate.EmptyStateProvider
import com.android.intentresolver.mock
-import com.android.intentresolver.v2.MultiProfilePagerAdapter.TabConfig
import com.android.intentresolver.whenever
import com.google.common.collect.ImmutableList
import com.google.common.truth.Truth.assertThat
diff --git a/tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestTest.kt b/tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestTest.kt
index a5acb0d3..e88c46f5 100644
--- a/tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestTest.kt
+++ b/tests/unit/src/com/android/intentresolver/v2/ui/viewmodel/ResolverRequestTest.kt
@@ -22,7 +22,7 @@ import android.os.UserHandle
import androidx.core.net.toUri
import androidx.core.os.bundleOf
import com.android.intentresolver.v2.ResolverActivity.PROFILE_WORK
-import com.android.intentresolver.v2.domain.model.Profile.Type.WORK
+import com.android.intentresolver.v2.shared.model.Profile.Type.WORK
import com.android.intentresolver.v2.ui.model.ActivityLaunch
import com.android.intentresolver.v2.ui.model.ResolverRequest
import com.android.intentresolver.v2.validation.UncaughtException