diff options
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;  |