Loading libs/WindowManager/Shell/res/values/config.xml +4 −0 Original line number Diff line number Diff line Loading @@ -179,4 +179,8 @@ <!-- Whether pointer pilfer is required to start back animation. --> <bool name="config_backAnimationRequiresPointerPilfer">true</bool> <!-- This is to be overridden to define a list of packages mapped to web links which will be parsed and utilized for desktop windowing's app-to-web feature. --> <string name="generic_links_list" translatable="false"/> </resources> libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java +11 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,10 @@ public class DesktopModeStatus { private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean( "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); private static final boolean USE_APP_TO_WEB_BUILD_TIME_GENERIC_LINKS = SystemProperties.getBoolean( "persist.wm.debug.use_app_to_web_build_time_generic_links", true); /** Whether the desktop density override is enabled. */ public static final boolean DESKTOP_DENSITY_OVERRIDE_ENABLED = SystemProperties.getBoolean("persist.wm.debug.desktop_mode_density_enabled", false); Loading Loading @@ -175,6 +179,13 @@ public class DesktopModeStatus { return isDesktopDensityOverrideEnabled() && isValidDesktopDensityOverrideSet(); } /** * Returns {@code true} if the app-to-web feature is using the build-time generic links list. */ public static boolean useAppToWebBuildTimeGenericLinks() { return USE_APP_TO_WEB_BUILD_TIME_GENERIC_LINKS; } /** * Return {@code true} if the override desktop density is enabled. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebGenericLinksParser.kt 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * 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.wm.shell.apptoweb import android.content.Context import android.provider.DeviceConfig import android.webkit.URLUtil import com.android.internal.annotations.VisibleForTesting import com.android.wm.shell.R import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useAppToWebBuildTimeGenericLinks /** * Retrieves the build-time or server-side generic links list and parses and stores the * package-to-url pairs. */ class AppToWebGenericLinksParser( private val context: Context, @ShellMainThread private val mainExecutor: ShellExecutor ) { private val genericLinksMap: MutableMap<String, String> = mutableMapOf() init { // If using the server-side generic links list, register a listener if (!useAppToWebBuildTimeGenericLinks()) { DeviceConfigListener() } updateGenericLinksMap() } /** Returns the generic link associated with the [packageName] or null if there is none. */ fun getGenericLink(packageName: String): String? = genericLinksMap[packageName] private fun updateGenericLinksMap() { val genericLinksList = if (useAppToWebBuildTimeGenericLinks()) { context.resources.getString(R.string.generic_links_list) } else { DeviceConfig.getString(NAMESPACE, FLAG_GENERIC_LINKS, /* defaultValue= */ "") } ?: return parseGenericLinkList(genericLinksList) } private fun parseGenericLinkList(genericLinksList: String) { val newEntries = genericLinksList .split(" ") .filter { it.contains(':') } .map { val (packageName, url) = it.split(':', limit = 2) return@map packageName to url } .filter { URLUtil.isNetworkUrl(it.second) } genericLinksMap.clear() genericLinksMap.putAll(newEntries) } /** * Listens for changes to the server-side generic links list and updates the package to url map * if [DesktopModeStatus#useBuildTimeGenericLinkList()] is set to false. */ inner class DeviceConfigListener : DeviceConfig.OnPropertiesChangedListener { init { DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, mainExecutor, this) } override fun onPropertiesChanged(properties: DeviceConfig.Properties) { if (properties.keyset.contains(FLAG_GENERIC_LINKS)) { updateGenericLinksMap() } } } companion object { private const val NAMESPACE = DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES @VisibleForTesting const val FLAG_GENERIC_LINKS = "generic_links_flag" } } libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +14 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.activityembedding.ActivityEmbeddingController; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.bubbles.BubbleData; import com.android.wm.shell.bubbles.BubbleDataRepository; Loading Loading @@ -223,7 +224,8 @@ public abstract class WMShellModule { Transitions transitions, Optional<DesktopTasksController> desktopTasksController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor) { InteractionJankMonitor interactionJankMonitor, AppToWebGenericLinksParser genericLinksParser) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return new DesktopModeWindowDecorViewModel( context, Loading @@ -242,7 +244,8 @@ public abstract class WMShellModule { transitions, desktopTasksController, rootTaskDisplayAreaOrganizer, interactionJankMonitor); interactionJankMonitor, genericLinksParser); } return new CaptionWindowDecorViewModel( context, Loading @@ -259,6 +262,15 @@ public abstract class WMShellModule { transitions); } @WMSingleton @Provides static AppToWebGenericLinksParser provideGenericLinksParser( Context context, @ShellMainThread ShellExecutor mainExecutor ) { return new AppToWebGenericLinksParser(context, mainExecutor); } // // Freeform // Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +9 −2 Original line number Diff line number Diff line Loading @@ -87,6 +87,7 @@ import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; Loading Loading @@ -162,6 +163,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DesktopModeKeyguardChangeListener mDesktopModeKeyguardChangeListener = new DesktopModeKeyguardChangeListener(); private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private final AppToWebGenericLinksParser mGenericLinksParser; private final DisplayInsetsController mDisplayInsetsController; private final Region mExclusionRegion = Region.obtain(); private boolean mInImmersiveMode; Loading Loading @@ -198,7 +200,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { Transitions transitions, Optional<DesktopTasksController> desktopTasksController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor InteractionJankMonitor interactionJankMonitor, AppToWebGenericLinksParser genericLinksParser ) { this( context, Loading @@ -216,6 +219,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { syncQueue, transitions, desktopTasksController, genericLinksParser, new DesktopModeWindowDecoration.Factory(), new InputMonitorFactory(), SurfaceControl.Transaction::new, Loading @@ -241,6 +245,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { SyncTransactionQueue syncQueue, Transitions transitions, Optional<DesktopTasksController> desktopTasksController, AppToWebGenericLinksParser genericLinksParser, DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory, InputMonitorFactory inputMonitorFactory, Supplier<SurfaceControl.Transaction> transactionFactory, Loading @@ -266,6 +271,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mInputMonitorFactory = inputMonitorFactory; mTransactionFactory = transactionFactory; mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mGenericLinksParser = genericLinksParser; mInputManager = mContext.getSystemService(InputManager.class); mWindowDecorByTaskId = windowDecorByTaskId; mSysUIPackageName = mContext.getResources().getString( Loading Loading @@ -1151,7 +1157,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mBgExecutor, mMainChoreographer, mSyncQueue, mRootTaskDisplayAreaOrganizer); mRootTaskDisplayAreaOrganizer, mGenericLinksParser); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final DragPositioningCallback dragPositioningCallback; Loading Loading
libs/WindowManager/Shell/res/values/config.xml +4 −0 Original line number Diff line number Diff line Loading @@ -179,4 +179,8 @@ <!-- Whether pointer pilfer is required to start back animation. --> <bool name="config_backAnimationRequiresPointerPilfer">true</bool> <!-- This is to be overridden to define a list of packages mapped to web links which will be parsed and utilized for desktop windowing's app-to-web feature. --> <string name="generic_links_list" translatable="false"/> </resources>
libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java +11 −0 Original line number Diff line number Diff line Loading @@ -70,6 +70,10 @@ public class DesktopModeStatus { private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean( "persist.wm.debug.desktop_mode_enforce_device_restrictions", true); private static final boolean USE_APP_TO_WEB_BUILD_TIME_GENERIC_LINKS = SystemProperties.getBoolean( "persist.wm.debug.use_app_to_web_build_time_generic_links", true); /** Whether the desktop density override is enabled. */ public static final boolean DESKTOP_DENSITY_OVERRIDE_ENABLED = SystemProperties.getBoolean("persist.wm.debug.desktop_mode_density_enabled", false); Loading Loading @@ -175,6 +179,13 @@ public class DesktopModeStatus { return isDesktopDensityOverrideEnabled() && isValidDesktopDensityOverrideSet(); } /** * Returns {@code true} if the app-to-web feature is using the build-time generic links list. */ public static boolean useAppToWebBuildTimeGenericLinks() { return USE_APP_TO_WEB_BUILD_TIME_GENERIC_LINKS; } /** * Return {@code true} if the override desktop density is enabled. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/apptoweb/AppToWebGenericLinksParser.kt 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * 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.wm.shell.apptoweb import android.content.Context import android.provider.DeviceConfig import android.webkit.URLUtil import com.android.internal.annotations.VisibleForTesting import com.android.wm.shell.R import com.android.wm.shell.common.ShellExecutor import com.android.wm.shell.shared.annotations.ShellMainThread import com.android.wm.shell.shared.desktopmode.DesktopModeStatus.useAppToWebBuildTimeGenericLinks /** * Retrieves the build-time or server-side generic links list and parses and stores the * package-to-url pairs. */ class AppToWebGenericLinksParser( private val context: Context, @ShellMainThread private val mainExecutor: ShellExecutor ) { private val genericLinksMap: MutableMap<String, String> = mutableMapOf() init { // If using the server-side generic links list, register a listener if (!useAppToWebBuildTimeGenericLinks()) { DeviceConfigListener() } updateGenericLinksMap() } /** Returns the generic link associated with the [packageName] or null if there is none. */ fun getGenericLink(packageName: String): String? = genericLinksMap[packageName] private fun updateGenericLinksMap() { val genericLinksList = if (useAppToWebBuildTimeGenericLinks()) { context.resources.getString(R.string.generic_links_list) } else { DeviceConfig.getString(NAMESPACE, FLAG_GENERIC_LINKS, /* defaultValue= */ "") } ?: return parseGenericLinkList(genericLinksList) } private fun parseGenericLinkList(genericLinksList: String) { val newEntries = genericLinksList .split(" ") .filter { it.contains(':') } .map { val (packageName, url) = it.split(':', limit = 2) return@map packageName to url } .filter { URLUtil.isNetworkUrl(it.second) } genericLinksMap.clear() genericLinksMap.putAll(newEntries) } /** * Listens for changes to the server-side generic links list and updates the package to url map * if [DesktopModeStatus#useBuildTimeGenericLinkList()] is set to false. */ inner class DeviceConfigListener : DeviceConfig.OnPropertiesChangedListener { init { DeviceConfig.addOnPropertiesChangedListener(NAMESPACE, mainExecutor, this) } override fun onPropertiesChanged(properties: DeviceConfig.Properties) { if (properties.keyset.contains(FLAG_GENERIC_LINKS)) { updateGenericLinksMap() } } } companion object { private const val NAMESPACE = DeviceConfig.NAMESPACE_APP_COMPAT_OVERRIDES @VisibleForTesting const val FLAG_GENERIC_LINKS = "generic_links_flag" } }
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +14 −2 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.WindowManagerShellWrapper; import com.android.wm.shell.activityembedding.ActivityEmbeddingController; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.bubbles.BubbleData; import com.android.wm.shell.bubbles.BubbleDataRepository; Loading Loading @@ -223,7 +224,8 @@ public abstract class WMShellModule { Transitions transitions, Optional<DesktopTasksController> desktopTasksController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor) { InteractionJankMonitor interactionJankMonitor, AppToWebGenericLinksParser genericLinksParser) { if (DesktopModeStatus.canEnterDesktopMode(context)) { return new DesktopModeWindowDecorViewModel( context, Loading @@ -242,7 +244,8 @@ public abstract class WMShellModule { transitions, desktopTasksController, rootTaskDisplayAreaOrganizer, interactionJankMonitor); interactionJankMonitor, genericLinksParser); } return new CaptionWindowDecorViewModel( context, Loading @@ -259,6 +262,15 @@ public abstract class WMShellModule { transitions); } @WMSingleton @Provides static AppToWebGenericLinksParser provideGenericLinksParser( Context context, @ShellMainThread ShellExecutor mainExecutor ) { return new AppToWebGenericLinksParser(context, mainExecutor); } // // Freeform // Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +9 −2 Original line number Diff line number Diff line Loading @@ -87,6 +87,7 @@ import com.android.window.flags.Flags; import com.android.wm.shell.R; import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayInsetsController; import com.android.wm.shell.common.DisplayLayout; Loading Loading @@ -162,6 +163,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { private final DesktopModeKeyguardChangeListener mDesktopModeKeyguardChangeListener = new DesktopModeKeyguardChangeListener(); private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer; private final AppToWebGenericLinksParser mGenericLinksParser; private final DisplayInsetsController mDisplayInsetsController; private final Region mExclusionRegion = Region.obtain(); private boolean mInImmersiveMode; Loading Loading @@ -198,7 +200,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { Transitions transitions, Optional<DesktopTasksController> desktopTasksController, RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer, InteractionJankMonitor interactionJankMonitor InteractionJankMonitor interactionJankMonitor, AppToWebGenericLinksParser genericLinksParser ) { this( context, Loading @@ -216,6 +219,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { syncQueue, transitions, desktopTasksController, genericLinksParser, new DesktopModeWindowDecoration.Factory(), new InputMonitorFactory(), SurfaceControl.Transaction::new, Loading @@ -241,6 +245,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { SyncTransactionQueue syncQueue, Transitions transitions, Optional<DesktopTasksController> desktopTasksController, AppToWebGenericLinksParser genericLinksParser, DesktopModeWindowDecoration.Factory desktopModeWindowDecorFactory, InputMonitorFactory inputMonitorFactory, Supplier<SurfaceControl.Transaction> transactionFactory, Loading @@ -266,6 +271,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mInputMonitorFactory = inputMonitorFactory; mTransactionFactory = transactionFactory; mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer; mGenericLinksParser = genericLinksParser; mInputManager = mContext.getSystemService(InputManager.class); mWindowDecorByTaskId = windowDecorByTaskId; mSysUIPackageName = mContext.getResources().getString( Loading Loading @@ -1151,7 +1157,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mBgExecutor, mMainChoreographer, mSyncQueue, mRootTaskDisplayAreaOrganizer); mRootTaskDisplayAreaOrganizer, mGenericLinksParser); mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration); final DragPositioningCallback dragPositioningCallback; Loading