diff options
| author | 2024-10-01 23:41:34 +0000 | |
|---|---|---|
| committer | 2024-10-01 23:41:34 +0000 | |
| commit | 2533fe989871c5ed0fe49bacd9b53b547ecb4cf0 (patch) | |
| tree | a9443673f8d7584d4ba63bcf9bd85d652ec6354f | |
| parent | a9bb4ebff225118288bef3b967816321701433f0 (diff) | |
| parent | 1ead06105a3c263abb03cfb521a26b226e21d60c (diff) | |
Merge "Do not show openInBrowser button if user does not have browser available" into main
6 files changed, 85 insertions, 54 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt index 05ce36120c4f..71bcb590ae23 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebUtils.kt @@ -20,10 +20,11 @@ package com.android.wm.shell.apptoweb import android.content.Context import android.content.Intent +import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.pm.PackageManager import android.net.Uri -private val browserIntent = Intent() +private val GenericBrowserIntent = Intent() .setAction(Intent.ACTION_VIEW) .addCategory(Intent.CATEGORY_BROWSABLE) .setData(Uri.parse("http:")) @@ -32,9 +33,9 @@ private val browserIntent = Intent() * Returns a boolean indicating whether a given package is a browser app. */ fun isBrowserApp(context: Context, packageName: String, userId: Int): Boolean { - browserIntent.setPackage(packageName) + GenericBrowserIntent.setPackage(packageName) val list = context.packageManager.queryIntentActivitiesAsUser( - browserIntent, PackageManager.MATCH_ALL, userId + GenericBrowserIntent, PackageManager.MATCH_ALL, userId ) list.forEach { @@ -44,3 +45,17 @@ fun isBrowserApp(context: Context, packageName: String, userId: Int): Boolean { } return false } + +/** + * Returns intent if there is a browser application available to handle the uri. Otherwise, returns + * null. + */ +fun getBrowserIntent(uri: Uri, packageManager: PackageManager): Intent? { + val intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_BROWSER) + .setData(uri) + .addFlags(FLAG_ACTIVITY_NEW_TASK) + // If there is no browser application available to handle intent, return null + val component = intent.resolveActivity(packageManager) ?: return null + intent.setComponent(component) + return intent +}
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java index c34a0bc829c4..5e909ca005e6 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java @@ -22,9 +22,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; -import static android.content.Intent.ACTION_MAIN; -import static android.content.Intent.CATEGORY_APP_BROWSER; -import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.view.InputDevice.SOURCE_TOUCHSCREEN; import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_HOVER_ENTER; @@ -58,7 +55,6 @@ import android.graphics.PointF; import android.graphics.Rect; import android.graphics.Region; import android.hardware.input.InputManager; -import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -560,20 +556,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { decoration.closeMaximizeMenu(); } - private void onOpenInBrowser(int taskId, @NonNull Uri uri) { + private void onOpenInBrowser(int taskId, @NonNull Intent intent) { final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId); if (decoration == null) { return; } - openInBrowser(uri, decoration.getUser()); + openInBrowser(intent, decoration.getUser()); decoration.closeHandleMenu(); decoration.closeMaximizeMenu(); } - private void openInBrowser(Uri uri, @NonNull UserHandle userHandle) { - final Intent intent = Intent.makeMainSelectorActivity(ACTION_MAIN, CATEGORY_APP_BROWSER) - .setData(uri) - .addFlags(FLAG_ACTIVITY_NEW_TASK); + private void openInBrowser(@NonNull Intent intent, @NonNull UserHandle userHandle) { mContext.startActivityAsUser(intent, userHandle); } @@ -1472,8 +1465,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { onToSplitScreen(taskInfo.taskId); return Unit.INSTANCE; }); - windowDecoration.setOpenInBrowserClickListener((uri) -> { - onOpenInBrowser(taskInfo.taskId, uri); + windowDecoration.setOpenInBrowserClickListener((intent) -> { + onOpenInBrowser(taskInfo.taskId, intent); }); windowDecoration.setOnNewWindowClickListener(() -> { onNewWindow(taskInfo.taskId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java index 99457d8436ff..496906658b3d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java @@ -44,6 +44,7 @@ import android.app.WindowConfiguration.WindowingMode; import android.app.assist.AssistContent; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -166,7 +167,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private CapturedLink mCapturedLink; private Uri mGenericLink; private Uri mWebUri; - private Consumer<Uri> mOpenInBrowserClickListener; + private Consumer<Intent> mOpenInBrowserClickListener; private ExclusionRegionListener mExclusionRegionListener; @@ -335,7 +336,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mDragPositioningCallback = dragPositioningCallback; } - void setOpenInBrowserClickListener(Consumer<Uri> listener) { + void setOpenInBrowserClickListener(Consumer<Intent> listener) { mOpenInBrowserClickListener = listener; } @@ -518,21 +519,28 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } @Nullable - private Uri getBrowserLink() { + private Intent getBrowserLink() { // Do not show browser link in browser applications final ComponentName baseActivity = mTaskInfo.baseActivity; if (baseActivity != null && AppToWebUtils.isBrowserApp(mContext, baseActivity.getPackageName(), mUserContext.getUserId())) { return null; } + + final Uri browserLink; // If the captured link is available and has not expired, return the captured link. // Otherwise, return the generic link which is set to null if a generic link is unavailable. if (mCapturedLink != null && !mCapturedLink.mExpired) { - return mCapturedLink.mUri; + browserLink = mCapturedLink.mUri; } else if (mWebUri != null) { - return mWebUri; + browserLink = mWebUri; + } else { + browserLink = mGenericLink; } - return mGenericLink; + + if (browserLink == null) return null; + return AppToWebUtils.getBrowserIntent(browserLink, mContext.getPackageManager()); + } UserHandle getUser() { @@ -1049,7 +1057,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin } /** - * Determine the highest y coordinate of a freeform task. Used for restricting drag inputs. + * Determine the highest y coordinate of a freeform task. Used for restricting drag inputs.fmdra */ private int determineMaxY(int requiredEmptySpace, Rect stableBounds) { return stableBounds.bottom - requiredEmptySpace; @@ -1172,8 +1180,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin /* onToSplitScreenClickListener= */ mOnToSplitscreenClickListener, /* onNewWindowClickListener= */ mOnNewWindowClickListener, /* onManageWindowsClickListener= */ mOnManageWindowsClickListener, - /* openInBrowserClickListener= */ (uri) -> { - mOpenInBrowserClickListener.accept(uri); + /* openInBrowserClickListener= */ (intent) -> { + mOpenInBrowserClickListener.accept(intent); onCapturedLinkExpired(); return Unit.INSTANCE; }, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt index 9a5b4f54dd36..98fef4722d1c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt @@ -20,13 +20,13 @@ import android.annotation.DimenRes import android.annotation.SuppressLint import android.app.ActivityManager.RunningTaskInfo import android.content.Context +import android.content.Intent import android.content.res.ColorStateList import android.content.res.Resources import android.graphics.Bitmap import android.graphics.Point import android.graphics.PointF import android.graphics.Rect -import android.net.Uri import android.view.LayoutInflater import android.view.MotionEvent import android.view.MotionEvent.ACTION_OUTSIDE @@ -70,7 +70,7 @@ class HandleMenu( private val shouldShowWindowingPill: Boolean, private val shouldShowNewWindowButton: Boolean, private val shouldShowManageWindowsButton: Boolean, - private val openInBrowserLink: Uri?, + private val openInBrowserIntent: Intent?, private val captionWidth: Int, private val captionHeight: Int, captionX: Int @@ -107,7 +107,7 @@ class HandleMenu( private val globalMenuPosition: Point = Point() private val shouldShowBrowserPill: Boolean - get() = openInBrowserLink != null + get() = openInBrowserIntent != null init { updateHandleMenuPillPositions(captionX) @@ -119,7 +119,7 @@ class HandleMenu( onToSplitScreenClickListener: () -> Unit, onNewWindowClickListener: () -> Unit, onManageWindowsClickListener: () -> Unit, - openInBrowserClickListener: (Uri) -> Unit, + openInBrowserClickListener: (Intent) -> Unit, onCloseMenuClickListener: () -> Unit, onOutsideTouchListener: () -> Unit, ) { @@ -152,7 +152,7 @@ class HandleMenu( onToSplitScreenClickListener: () -> Unit, onNewWindowClickListener: () -> Unit, onManageWindowsClickListener: () -> Unit, - openInBrowserClickListener: (Uri) -> Unit, + openInBrowserClickListener: (Intent) -> Unit, onCloseMenuClickListener: () -> Unit, onOutsideTouchListener: () -> Unit ) { @@ -172,7 +172,7 @@ class HandleMenu( this.onNewWindowClickListener = onNewWindowClickListener this.onManageWindowsClickListener = onManageWindowsClickListener this.onOpenInBrowserClickListener = { - openInBrowserClickListener.invoke(openInBrowserLink!!) + openInBrowserClickListener.invoke(openInBrowserIntent!!) } this.onCloseMenuClickListener = onCloseMenuClickListener this.onOutsideTouchListener = onOutsideTouchListener @@ -661,7 +661,7 @@ interface HandleMenuFactory { shouldShowWindowingPill: Boolean, shouldShowNewWindowButton: Boolean, shouldShowManageWindowsButton: Boolean, - openInBrowserLink: Uri?, + openInBrowserIntent: Intent?, captionWidth: Int, captionHeight: Int, captionX: Int @@ -680,7 +680,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory { shouldShowWindowingPill: Boolean, shouldShowNewWindowButton: Boolean, shouldShowManageWindowsButton: Boolean, - openInBrowserLink: Uri?, + openInBrowserIntent: Intent?, captionWidth: Int, captionHeight: Int, captionX: Int @@ -695,7 +695,7 @@ object DefaultHandleMenuFactory : HandleMenuFactory { shouldShowWindowingPill, shouldShowNewWindowButton, shouldShowManageWindowsButton, - openInBrowserLink, + openInBrowserIntent, captionWidth, captionHeight, captionX diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt index 9aa6a52fd851..0331821b5701 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt @@ -27,6 +27,7 @@ import android.app.WindowConfiguration.WindowingMode import android.content.ComponentName import android.content.Context import android.content.Intent +import android.content.Intent.ACTION_MAIN import android.content.pm.ActivityInfo import android.graphics.Rect import android.hardware.display.DisplayManager @@ -930,13 +931,13 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { @Test fun testDecor_onClickToOpenBrowser_closeMenus() { val openInBrowserListenerCaptor = forClass(Consumer::class.java) - as ArgumentCaptor<Consumer<Uri>> + as ArgumentCaptor<Consumer<Intent>> val decor = createOpenTaskDecoration( windowingMode = WINDOWING_MODE_FULLSCREEN, onOpenInBrowserClickListener = openInBrowserListenerCaptor ) - openInBrowserListenerCaptor.value.accept(Uri.EMPTY) + openInBrowserListenerCaptor.value.accept(Intent()) verify(decor).closeHandleMenu() verify(decor).closeMaximizeMenu() @@ -946,20 +947,19 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { fun testDecor_onClickToOpenBrowser_opensBrowser() { doNothing().whenever(spyContext).startActivity(any()) val uri = Uri.parse("https://www.google.com") + val intent = Intent(ACTION_MAIN, uri) val openInBrowserListenerCaptor = forClass(Consumer::class.java) - as ArgumentCaptor<Consumer<Uri>> + as ArgumentCaptor<Consumer<Intent>> createOpenTaskDecoration( windowingMode = WINDOWING_MODE_FULLSCREEN, onOpenInBrowserClickListener = openInBrowserListenerCaptor ) - openInBrowserListenerCaptor.value.accept(uri) + openInBrowserListenerCaptor.value.accept(intent) verify(spyContext).startActivityAsUser(argThat { intent -> - intent.data == uri - && ((intent.flags and Intent.FLAG_ACTIVITY_NEW_TASK) != 0) - && intent.categories.contains(Intent.CATEGORY_LAUNCHER) - && intent.action == Intent.ACTION_MAIN + uri.equals(intent.data) + && intent.action == ACTION_MAIN }, eq(mockUserHandle)) } @@ -1233,8 +1233,8 @@ class DesktopModeWindowDecorViewModelTests : ShellTestCase() { forClass(Function0::class.java) as ArgumentCaptor<Function0<Unit>>, onToSplitScreenClickListenerCaptor: ArgumentCaptor<Function0<Unit>> = forClass(Function0::class.java) as ArgumentCaptor<Function0<Unit>>, - onOpenInBrowserClickListener: ArgumentCaptor<Consumer<Uri>> = - forClass(Consumer::class.java) as ArgumentCaptor<Consumer<Uri>>, + onOpenInBrowserClickListener: ArgumentCaptor<Consumer<Intent>> = + forClass(Consumer::class.java) as ArgumentCaptor<Consumer<Intent>>, onCaptionButtonClickListener: ArgumentCaptor<View.OnClickListener> = forClass(View.OnClickListener::class.java) as ArgumentCaptor<View.OnClickListener>, onCaptionButtonTouchListener: ArgumentCaptor<View.OnTouchListener> = diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java index f007115c6dab..dae172126884 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorationTests.java @@ -37,6 +37,7 @@ import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; @@ -53,9 +54,11 @@ import android.app.ActivityManager; import android.app.assist.AssistContent; import android.content.ComponentName; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.PointF; @@ -187,7 +190,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { @Mock private Handler mMockHandler; @Mock - private Consumer<Uri> mMockOpenInBrowserClickListener; + private Consumer<Intent> mMockOpenInBrowserClickListener; @Mock private AppToWebGenericLinksParser mMockGenericLinksParser; @Mock @@ -242,9 +245,11 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { when(mMockMultiInstanceHelper.supportsMultiInstanceSplit(any())) .thenReturn(false); when(mMockPackageManager.getApplicationLabel(any())).thenReturn("applicationLabel"); - final ActivityInfo activityInfo = new ActivityInfo(); - activityInfo.applicationInfo = new ApplicationInfo(); + final ActivityInfo activityInfo = createActivityInfo(); when(mMockPackageManager.getActivityInfo(any(), anyInt())).thenReturn(activityInfo); + final ResolveInfo resolveInfo = new ResolveInfo(); + resolveInfo.activityInfo = activityInfo; + when(mMockPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo); final Display defaultDisplay = mock(Display.class); doReturn(defaultDisplay).when(mMockDisplayController).getDisplay(Display.DEFAULT_DISPLAY); doReturn(mInsetsState).when(mMockDisplayController).getInsetsState(anyInt()); @@ -771,7 +776,6 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { // Verify handle menu's browser link is set to captured link since menu was opened before // captured link expired - createHandleMenu(decor); verifyHandleMenuCreated(TEST_URI1); } @@ -782,7 +786,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { final DesktopModeWindowDecoration decor = createWindowDecoration( taskInfo, TEST_URI1 /* captured link */, null /* web uri */, null /* generic link */); - final ArgumentCaptor<Function1<Uri, Unit>> openInBrowserCaptor = + final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor = ArgumentCaptor.forClass(Function1.class); // Simulate menu opening and clicking open in browser button @@ -797,7 +801,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { any(), any() ); - openInBrowserCaptor.getValue().invoke(TEST_URI1); + openInBrowserCaptor.getValue().invoke(new Intent(Intent.ACTION_MAIN, TEST_URI1)); // Verify handle menu's browser link not set to captured link since link not valid after // open in browser clicked @@ -812,7 +816,7 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { final DesktopModeWindowDecoration decor = createWindowDecoration( taskInfo, TEST_URI1 /* captured link */, null /* web uri */, null /* generic link */); - final ArgumentCaptor<Function1<Uri, Unit>> openInBrowserCaptor = + final ArgumentCaptor<Function1<Intent, Unit>> openInBrowserCaptor = ArgumentCaptor.forClass(Function1.class); createHandleMenu(decor); verify(mMockHandleMenu).show( @@ -826,9 +830,10 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { any() ); - openInBrowserCaptor.getValue().invoke(TEST_URI1); + openInBrowserCaptor.getValue().invoke(new Intent(Intent.ACTION_MAIN, TEST_URI1)); - verify(mMockOpenInBrowserClickListener).accept(TEST_URI1); + verify(mMockOpenInBrowserClickListener).accept( + argThat(intent -> intent.getData() == TEST_URI1)); } @Test @@ -1021,8 +1026,9 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { private void verifyHandleMenuCreated(@Nullable Uri uri) { verify(mMockHandleMenuFactory).create(any(), any(), anyInt(), any(), any(), - any(), anyBoolean(), anyBoolean(), anyBoolean(), eq(uri), anyInt(), - anyInt(), anyInt()); + any(), anyBoolean(), anyBoolean(), anyBoolean(), + argThat(intent -> (uri == null && intent == null) || intent.getData().equals(uri)), + anyInt(), anyInt(), anyInt()); } private void createMaximizeMenu(DesktopModeWindowDecoration decoration, MaximizeMenu menu) { @@ -1128,6 +1134,15 @@ public class DesktopModeWindowDecorationTests extends ShellTestCase { decor.onAssistContentReceived(mAssistContent); } + private static ActivityInfo createActivityInfo() { + final ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = "DesktopModeWindowDecorationTestPackage"; + final ActivityInfo activityInfo = new ActivityInfo(); + activityInfo.applicationInfo = applicationInfo; + activityInfo.name = "DesktopModeWindowDecorationTest"; + return activityInfo; + } + private static boolean hasNoInputChannelFeature(RelayoutParams params) { return (params.mInputFeatures & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) != 0; |