Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00f53750 authored by Maryam Dehaini's avatar Maryam Dehaini
Browse files

Allow users to switch from web to app

Create web to app button in handle menu if browser provides url that can
be handled by application.

Bug: 377755706
Test: open app from web
Flag: com.android.window.flags.enable_desktop_windowing_app_to_web
Change-Id: I12232b064f5c5706ecef430330db07c93cd9b02e
parent 3885ea04
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -168,7 +168,7 @@
    </LinearLayout>

    <LinearLayout
        android:id="@+id/open_in_browser_pill"
        android:id="@+id/open_in_app_or_browser_pill"
        android:layout_width="match_parent"
        android:layout_height="@dimen/desktop_mode_handle_menu_open_in_browser_pill_height"
        android:layout_marginTop="@dimen/desktop_mode_handle_menu_pill_spacing_margin"
@@ -178,7 +178,7 @@
        android:background="@drawable/desktop_mode_decor_handle_menu_background">

        <Button
            android:id="@+id/open_in_browser_button"
            android:id="@+id/open_in_app_or_browser_button"
            android:layout_weight="1"
            android:contentDescription="@string/open_in_browser_text"
            android:text="@string/open_in_browser_text"
+2 −0
Original line number Diff line number Diff line
@@ -301,6 +301,8 @@
    <string name="screenshot_text">Screenshot</string>
    <!-- Accessibility text for the handle menu open in browser button [CHAR LIMIT=NONE] -->
    <string name="open_in_browser_text">Open in browser</string>
    <!-- Accessibility text for the handle menu open in app button [CHAR LIMIT=NONE] -->
    <string name="open_in_app_text">Open in App</string>
    <!-- Accessibility text for the handle menu new window button [CHAR LIMIT=NONE] -->
    <string name="new_window_text">New Window</string>
    <!-- Accessibility text for the handle menu new window button [CHAR LIMIT=NONE] -->
+17 −1
Original line number Diff line number Diff line
@@ -20,7 +20,9 @@ package com.android.wm.shell.apptoweb

import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_VIEW
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER
import android.content.pm.PackageManager
import android.content.pm.verify.domain.DomainVerificationManager
import android.content.pm.verify.domain.DomainVerificationUserState
@@ -31,7 +33,7 @@ import com.android.wm.shell.protolog.ShellProtoLogGroup
private const val TAG = "AppToWebUtils"

private val GenericBrowserIntent = Intent()
    .setAction(Intent.ACTION_VIEW)
    .setAction(ACTION_VIEW)
    .addCategory(Intent.CATEGORY_BROWSABLE)
    .setData(Uri.parse("http:"))

@@ -66,6 +68,20 @@ fun getBrowserIntent(uri: Uri, packageManager: PackageManager): Intent? {
    return intent
}

/**
 * Returns intent if there is a non-browser application available to handle the uri. Otherwise,
 * returns null.
 */
fun getAppIntent(uri: Uri, packageManager: PackageManager): Intent? {
    val intent = Intent(ACTION_VIEW, uri).apply {
        flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_REQUIRE_NON_BROWSER
    }
    // If there is no application available to handle intent, return null
    val component = intent.resolveActivity(packageManager) ?: return null
    intent.setComponent(component)
    return intent
}

/**
 * Returns the [DomainVerificationUserState] of the user associated with the given
 * [DomainVerificationManager] and the given package.
+15 −8
Original line number Diff line number Diff line
@@ -628,13 +628,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin

    @Nullable
    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.
@@ -651,6 +644,18 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin

    }

    @Nullable
    private Intent getAppLink() {
        return mWebUri == null ? null
                : AppToWebUtils.getAppIntent(mWebUri, mContext.getPackageManager());
    }

    private boolean isBrowserApp() {
        final ComponentName baseActivity = mTaskInfo.baseActivity;
        return baseActivity != null && AppToWebUtils.isBrowserApp(mContext,
                baseActivity.getPackageName(), mUserContext.getUserId());
    }

    UserHandle getUser() {
        return mUserContext.getUser();
    }
@@ -1368,6 +1373,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                .shouldShowChangeAspectRatioButton(mTaskInfo);
        final boolean inDesktopImmersive = mDesktopRepository
                .isTaskInFullImmersiveState(mTaskInfo.taskId);
        final boolean isBrowserApp = isBrowserApp();
        mHandleMenu = mHandleMenuFactory.create(
                this,
                mWindowManagerWrapper,
@@ -1379,7 +1385,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                supportsMultiInstance,
                shouldShowManageWindowsButton,
                shouldShowChangeAspectRatioButton,
                getBrowserLink(),
                isBrowserApp,
                isBrowserApp ? getAppLink() : getBrowserLink(),
                mResult.mCaptionWidth,
                mResult.mCaptionHeight,
                mResult.mCaptionX,
+43 −25
Original line number Diff line number Diff line
@@ -40,11 +40,13 @@ import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import android.window.SurfaceSyncGroup
import androidx.annotation.StringRes
import androidx.annotation.VisibleForTesting
import androidx.compose.ui.graphics.toArgb
import androidx.core.view.isGone
import com.android.window.flags.Flags
import com.android.wm.shell.R
import com.android.wm.shell.apptoweb.isBrowserApp
import com.android.wm.shell.shared.split.SplitScreenConstants
import com.android.wm.shell.splitscreen.SplitScreenController
import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer
@@ -73,7 +75,8 @@ class HandleMenu(
    private val shouldShowNewWindowButton: Boolean,
    private val shouldShowManageWindowsButton: Boolean,
    private val shouldShowChangeAspectRatioButton: Boolean,
    private val openInBrowserIntent: Intent?,
    private val isBrowserApp: Boolean,
    private val openInAppOrBrowserIntent: Intent?,
    private val captionWidth: Int,
    private val captionHeight: Int,
    captionX: Int,
@@ -111,7 +114,7 @@ class HandleMenu(
    private val globalMenuPosition: Point = Point()

    private val shouldShowBrowserPill: Boolean
        get() = openInBrowserIntent != null
        get() = openInAppOrBrowserIntent != null

    private val shouldShowMoreActionsPill: Boolean
        get() = SHOULD_SHOW_SCREENSHOT_BUTTON || shouldShowNewWindowButton ||
@@ -128,7 +131,7 @@ class HandleMenu(
        onNewWindowClickListener: () -> Unit,
        onManageWindowsClickListener: () -> Unit,
        onChangeAspectRatioClickListener: () -> Unit,
        openInBrowserClickListener: (Intent) -> Unit,
        openInAppOrBrowserClickListener: (Intent) -> Unit,
        onOpenByDefaultClickListener: () -> Unit,
        onCloseMenuClickListener: () -> Unit,
        onOutsideTouchListener: () -> Unit,
@@ -146,7 +149,7 @@ class HandleMenu(
            onNewWindowClickListener = onNewWindowClickListener,
            onManageWindowsClickListener = onManageWindowsClickListener,
            onChangeAspectRatioClickListener = onChangeAspectRatioClickListener,
            openInBrowserClickListener = openInBrowserClickListener,
            openInAppOrBrowserClickListener = openInAppOrBrowserClickListener,
            onOpenByDefaultClickListener = onOpenByDefaultClickListener,
            onCloseMenuClickListener = onCloseMenuClickListener,
            onOutsideTouchListener = onOutsideTouchListener,
@@ -167,7 +170,7 @@ class HandleMenu(
        onNewWindowClickListener: () -> Unit,
        onManageWindowsClickListener: () -> Unit,
        onChangeAspectRatioClickListener: () -> Unit,
        openInBrowserClickListener: (Intent) -> Unit,
        openInAppOrBrowserClickListener: (Intent) -> Unit,
        onOpenByDefaultClickListener: () -> Unit,
        onCloseMenuClickListener: () -> Unit,
        onOutsideTouchListener: () -> Unit,
@@ -181,7 +184,8 @@ class HandleMenu(
            shouldShowBrowserPill = shouldShowBrowserPill,
            shouldShowNewWindowButton = shouldShowNewWindowButton,
            shouldShowManageWindowsButton = shouldShowManageWindowsButton,
            shouldShowChangeAspectRatioButton = shouldShowChangeAspectRatioButton
            shouldShowChangeAspectRatioButton = shouldShowChangeAspectRatioButton,
            isBrowserApp = isBrowserApp
        ).apply {
            bind(taskInfo, appIconBitmap, appName, shouldShowMoreActionsPill)
            this.onToDesktopClickListener = onToDesktopClickListener
@@ -190,8 +194,8 @@ class HandleMenu(
            this.onNewWindowClickListener = onNewWindowClickListener
            this.onManageWindowsClickListener = onManageWindowsClickListener
            this.onChangeAspectRatioClickListener = onChangeAspectRatioClickListener
            this.onOpenInBrowserClickListener = {
                openInBrowserClickListener.invoke(openInBrowserIntent!!)
            this.onOpenInAppOrBrowserClickListener = {
                openInAppOrBrowserClickListener.invoke(openInAppOrBrowserIntent!!)
            }
            this.onOpenByDefaultClickListener = onOpenByDefaultClickListener
            this.onCloseMenuClickListener = onCloseMenuClickListener
@@ -435,14 +439,15 @@ class HandleMenu(
    /** The view within the Handle Menu, with options to change the windowing mode and more. */
    @SuppressLint("ClickableViewAccessibility")
    class HandleMenuView(
        context: Context,
        private val context: Context,
        menuWidth: Int,
        captionHeight: Int,
        private val shouldShowWindowingPill: Boolean,
        private val shouldShowBrowserPill: Boolean,
        private val shouldShowNewWindowButton: Boolean,
        private val shouldShowManageWindowsButton: Boolean,
        private val shouldShowChangeAspectRatioButton: Boolean
        private val shouldShowChangeAspectRatioButton: Boolean,
        private val isBrowserApp: Boolean
    ) {
        val rootView = LayoutInflater.from(context)
            .inflate(R.layout.desktop_mode_window_decor_handle_menu, null /* root */) as View
@@ -472,11 +477,12 @@ class HandleMenu(
        private val changeAspectRatioBtn = moreActionsPill
            .requireViewById<Button>(R.id.change_aspect_ratio_button)

        // Open in Browser Pill.
        private val openInBrowserPill = rootView.requireViewById<View>(R.id.open_in_browser_pill)
        private val browserBtn = openInBrowserPill.requireViewById<Button>(
            R.id.open_in_browser_button)
        private val openByDefaultBtn = openInBrowserPill.requireViewById<ImageButton>(
        // Open in Browser/App Pill.
        private val openInAppOrBrowserPill = rootView.requireViewById<View>(
            R.id.open_in_app_or_browser_pill)
        private val openInAppOrBrowserBtn = openInAppOrBrowserPill.requireViewById<Button>(
            R.id.open_in_app_or_browser_button)
        private val openByDefaultBtn = openInAppOrBrowserPill.requireViewById<ImageButton>(
            R.id.open_by_default_button)
        private val decorThemeUtil = DecorThemeUtil(context)
        private val animator = HandleMenuAnimator(rootView, menuWidth, captionHeight.toFloat())
@@ -490,7 +496,7 @@ class HandleMenu(
        var onNewWindowClickListener: (() -> Unit)? = null
        var onManageWindowsClickListener: (() -> Unit)? = null
        var onChangeAspectRatioClickListener: (() -> Unit)? = null
        var onOpenInBrowserClickListener: (() -> Unit)? = null
        var onOpenInAppOrBrowserClickListener: (() -> Unit)? = null
        var onOpenByDefaultClickListener: (() -> Unit)? = null
        var onCloseMenuClickListener: (() -> Unit)? = null
        var onOutsideTouchListener: (() -> Unit)? = null
@@ -499,7 +505,7 @@ class HandleMenu(
            fullscreenBtn.setOnClickListener { onToFullscreenClickListener?.invoke() }
            splitscreenBtn.setOnClickListener { onToSplitScreenClickListener?.invoke() }
            desktopBtn.setOnClickListener { onToDesktopClickListener?.invoke() }
            browserBtn.setOnClickListener { onOpenInBrowserClickListener?.invoke() }
            openInAppOrBrowserBtn.setOnClickListener { onOpenInAppOrBrowserClickListener?.invoke() }
            openByDefaultBtn.setOnClickListener {
                onOpenByDefaultClickListener?.invoke()
            }
@@ -535,10 +541,10 @@ class HandleMenu(
            if (shouldShowMoreActionsPill) {
                bindMoreActionsPill(style)
            }
            bindOpenInBrowserPill(style)
            bindOpenInAppOrBrowserPill(style)
        }

        /** Animates the menu opening. */
        /** Animates the menu openInAppOrBrowserg. */
        fun animateOpenMenu() {
            if (taskInfo.isFullscreen || taskInfo.isMultiWindow) {
                animator.animateCaptionHandleExpandToOpen()
@@ -660,13 +666,20 @@ class HandleMenu(
            }
        }

        private fun bindOpenInBrowserPill(style: MenuStyle) {
            openInBrowserPill.apply {
        private fun bindOpenInAppOrBrowserPill(style: MenuStyle) {
            openInAppOrBrowserPill.apply {
                isGone = !shouldShowBrowserPill
                background.setTint(style.backgroundColor)
            }

            browserBtn.apply {
            val btnText = if (isBrowserApp) {
                getString(R.string.open_in_app_text)
            } else {
                getString(R.string.open_in_browser_text)
            }
            openInAppOrBrowserBtn.apply {
                text = btnText
                contentDescription = btnText
                setTextColor(style.textColor)
                compoundDrawableTintList = ColorStateList.valueOf(style.textColor)
            }
@@ -674,6 +687,8 @@ class HandleMenu(
            openByDefaultBtn.imageTintList = ColorStateList.valueOf(style.textColor)
        }

        private fun getString(@StringRes resId: Int): String = context.resources.getString(resId)

        private data class MenuStyle(
            @ColorInt val backgroundColor: Int,
            @ColorInt val textColor: Int,
@@ -708,7 +723,8 @@ interface HandleMenuFactory {
        shouldShowNewWindowButton: Boolean,
        shouldShowManageWindowsButton: Boolean,
        shouldShowChangeAspectRatioButton: Boolean,
        openInBrowserIntent: Intent?,
        isBrowserApp: Boolean,
        openInAppOrBrowserIntent: Intent?,
        captionWidth: Int,
        captionHeight: Int,
        captionX: Int,
@@ -729,7 +745,8 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
        shouldShowNewWindowButton: Boolean,
        shouldShowManageWindowsButton: Boolean,
        shouldShowChangeAspectRatioButton: Boolean,
        openInBrowserIntent: Intent?,
        isBrowserApp: Boolean,
        openInAppOrBrowserIntent: Intent?,
        captionWidth: Int,
        captionHeight: Int,
        captionX: Int,
@@ -746,7 +763,8 @@ object DefaultHandleMenuFactory : HandleMenuFactory {
            shouldShowNewWindowButton,
            shouldShowManageWindowsButton,
            shouldShowChangeAspectRatioButton,
            openInBrowserIntent,
            isBrowserApp,
            openInAppOrBrowserIntent,
            captionWidth,
            captionHeight,
            captionX,
Loading