diff options
Diffstat (limited to 'libs')
12 files changed, 374 insertions, 165 deletions
diff --git a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml index 27e0b184f427..5d7771366bec 100644 --- a/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml +++ b/libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml @@ -14,13 +14,12 @@ ~ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="24dp" - android:height="24dp" - android:viewportWidth="24" - android:viewportHeight="24" - android:tint="@color/decor_button_dark_color"> + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> <group android:translateY="8.0"> <path - android:fillColor="@android:color/white" android:pathData="M3,5V3H21V5Z"/> + android:fillColor="@android:color/black" android:pathData="M3,5V3H21V5Z"/> </group> </vector> diff --git a/libs/WindowManager/Shell/res/drawable/ic_baseline_expand_more_24.xml b/libs/WindowManager/Shell/res/drawable/ic_baseline_expand_more_24.xml new file mode 100644 index 000000000000..3e0297ab612b --- /dev/null +++ b/libs/WindowManager/Shell/res/drawable/ic_baseline_expand_more_24.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2023 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 + --> +<vector android:height="24dp" android:tint="#000000" + android:viewportHeight="24" android:viewportWidth="24" + android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> + <path android:fillColor="@android:color/black" android:pathData="M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z"/> +</vector> diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml new file mode 100644 index 000000000000..35562b650994 --- /dev/null +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_app_controls_window_decor.xml @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2022 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. + --> +<com.android.wm.shell.windowdecor.WindowDecorLinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/desktop_mode_caption" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:gravity="center_horizontal" + android:orientation="horizontal" + android:background="@drawable/desktop_mode_decor_title"> + + <LinearLayout + android:id="@+id/open_menu_button" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:orientation="horizontal" + android:clickable="true" + android:focusable="true" + android:paddingStart="8dp" + android:background="?android:selectableItemBackgroundBorderless"> + + <ImageView + android:id="@+id/application_icon" + android:layout_width="24dp" + android:layout_height="24dp" + android:layout_margin="4dp" + android:layout_gravity="center_vertical" + android:contentDescription="@string/app_icon_text" /> + + <TextView + android:id="@+id/application_name" + android:layout_width="0dp" + android:layout_height="match_parent" + android:minWidth="80dp" + android:textColor="@color/desktop_mode_caption_app_name_dark" + android:textSize="14sp" + android:textFontWeight="500" + android:gravity="center_vertical" + android:layout_weight="1" + android:paddingStart="4dp" + android:paddingEnd="4dp" + tools:text="Gmail"/> + + <ImageButton + android:id="@+id/expand_menu_button" + android:layout_width="32dp" + android:layout_height="32dp" + android:padding="4dp" + android:contentDescription="@string/collapse_menu_text" + android:src="@drawable/ic_baseline_expand_more_24" + android:tint="@color/desktop_mode_caption_expand_button_dark" + android:background="@null" + android:scaleType="fitCenter" + android:clickable="false" + android:focusable="false" + android:layout_gravity="center_vertical"/> + + </LinearLayout> + + <View + android:id="@+id/caption_handle" + android:layout_width="wrap_content" + android:layout_height="40dp" + android:layout_weight="1"/> + + <ImageButton + android:id="@+id/close_window" + android:layout_width="40dp" + android:layout_height="40dp" + android:padding="4dp" + android:layout_marginEnd="8dp" + android:contentDescription="@string/close_button_text" + android:src="@drawable/decor_close_button_dark" + android:scaleType="fitCenter" + android:gravity="end" + android:background="?android:selectableItemBackgroundBorderless" + android:tint="@color/desktop_mode_caption_close_button_dark"/> +</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml index f9aeb6a8448a..ac13eaeda6f5 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_decor_handle_menu.xml @@ -50,7 +50,7 @@ android:layout_marginEnd="10dp" android:contentDescription="@string/collapse_menu_text" android:layout_alignParentEnd="true" - android:background="@drawable/caption_collapse_menu_button" + android:background="@drawable/ic_baseline_expand_more_24" android:layout_centerVertical="true"/> </RelativeLayout> <LinearLayout diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml index 29cf1512e2e5..5ab159cdf264 100644 --- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor.xml +++ b/libs/WindowManager/Shell/res/layout/desktop_mode_focused_window_decor.xml @@ -16,26 +16,21 @@ --> <com.android.wm.shell.windowdecor.WindowDecorLinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" android:id="@+id/desktop_mode_caption" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:background="@drawable/desktop_mode_decor_title"> - <Button - style="@style/CaptionButtonStyle" - android:id="@+id/back_button" - android:contentDescription="@string/back_button_text" - android:background="@drawable/decor_back_button_dark"/> - <Button + + <ImageButton android:id="@+id/caption_handle" android:layout_width="128dp" - android:layout_height="32dp" - android:layout_margin="5dp" + android:layout_height="42dp" android:contentDescription="@string/handle_text" - android:background="@drawable/decor_handle_dark"/> - <Button - style="@style/CaptionButtonStyle" - android:id="@+id/close_window" - android:contentDescription="@string/close_button_text" - android:background="@drawable/decor_close_button_dark"/> + android:src="@drawable/decor_handle_dark" + tools:tint="@color/desktop_mode_caption_handle_bar_dark" + android:scaleType="fitXY" + android:background="?android:selectableItemBackground"/> + </com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
\ No newline at end of file diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml index 6fb70006e67f..2a03b03d86f1 100644 --- a/libs/WindowManager/Shell/res/values/colors.xml +++ b/libs/WindowManager/Shell/res/values/colors.xml @@ -54,4 +54,14 @@ <color name="splash_screen_bg_light">#FFFFFF</color> <color name="splash_screen_bg_dark">#000000</color> <color name="splash_window_background_default">@color/splash_screen_bg_light</color> + + <!-- Desktop Mode --> + <color name="desktop_mode_caption_handle_bar_light">#EFF1F2</color> + <color name="desktop_mode_caption_handle_bar_dark">#1C1C17</color> + <color name="desktop_mode_caption_expand_button_light">#EFF1F2</color> + <color name="desktop_mode_caption_expand_button_dark">#48473A</color> + <color name="desktop_mode_caption_close_button_light">#EFF1F2</color> + <color name="desktop_mode_caption_close_button_dark">#1C1C17</color> + <color name="desktop_mode_caption_app_name_light">#EFF1F2</color> + <color name="desktop_mode_caption_app_name_dark">#1C1C17</color> </resources> 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 6b45149e35a2..d2a80471a46f 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 @@ -166,7 +166,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } decoration.relayout(taskInfo); - setupCaptionColor(taskInfo, decoration); } @Override @@ -252,7 +251,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } else if (id == R.id.back_button) { mTaskOperations.injectBackKey(); - } else if (id == R.id.caption_handle) { + } else if (id == R.id.caption_handle || id == R.id.open_menu_button) { decoration.createHandleMenu(); } else if (id == R.id.desktop_button) { mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(true)); @@ -262,7 +261,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { mDesktopModeController.ifPresent(c -> c.setDesktopModeActive(false)); mDesktopTasksController.ifPresent(c -> c.moveToFullscreen(mTaskId)); decoration.closeHandleMenu(); - decoration.setButtonVisibility(false); } else if (id == R.id.collapse_menu_button) { decoration.closeHandleMenu(); } @@ -556,13 +554,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { } } - private void setupCaptionColor(RunningTaskInfo taskInfo, - DesktopModeWindowDecoration decoration) { - if (taskInfo == null || taskInfo.taskDescription == null) return; - final int statusBarColor = taskInfo.taskDescription.getStatusBarColor(); - decoration.setCaptionColor(statusBarColor); - } - private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) { if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true; return DesktopModeStatus.isProto2Enabled() @@ -602,7 +593,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { windowDecoration.setDragPositioningCallback(taskPositioner); windowDecoration.setDragDetector(touchEventListener.mDragDetector); windowDecoration.relayout(taskInfo, startT, finishT); - setupCaptionColor(taskInfo, windowDecoration); incrementEventReceiverTasks(taskInfo.displayId); } 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 3c0ef965f4f5..43605e30b813 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 @@ -22,15 +22,10 @@ import android.app.ActivityManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; -import android.graphics.Color; import android.graphics.Point; import android.graphics.PointF; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.GradientDrawable; -import android.graphics.drawable.VectorDrawable; import android.os.Handler; import android.util.Log; import android.view.Choreographer; @@ -48,20 +43,24 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.desktopmode.DesktopModeStatus; import com.android.wm.shell.desktopmode.DesktopTasksController; +import com.android.wm.shell.windowdecor.viewholder.DesktopModeAppControlsWindowDecorationViewHolder; +import com.android.wm.shell.windowdecor.viewholder.DesktopModeFocusedWindowDecorationViewHolder; +import com.android.wm.shell.windowdecor.viewholder.DesktopModeWindowDecorationViewHolder; /** * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with - * {@link DesktopModeWindowDecorViewModel}. The caption bar contains a handle, back button, and - * close button. + * {@link DesktopModeWindowDecorViewModel}. * * The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't. */ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLinearLayout> { private static final String TAG = "DesktopModeWindowDecoration"; + private final Handler mHandler; private final Choreographer mChoreographer; private final SyncTransactionQueue mSyncQueue; + private DesktopModeWindowDecorationViewHolder mWindowDecorViewHolder; private View.OnClickListener mOnCaptionButtonClickListener; private View.OnTouchListener mOnCaptionTouchListener; private DragPositioningCallback mDragPositioningCallback; @@ -73,7 +72,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult = new WindowDecoration.RelayoutResult<>(); - private boolean mDesktopActive; private AdditionalWindow mHandleMenu; private final int mHandleMenuWidthId = R.dimen.freeform_decor_caption_menu_width; private final int mHandleMenuShadowRadiusId = R.dimen.caption_menu_shadow_radius; @@ -94,7 +92,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mHandler = handler; mChoreographer = choreographer; mSyncQueue = syncQueue; - mDesktopActive = DesktopModeStatus.isActive(mContext); } @Override @@ -152,9 +149,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final int outsetRightId = R.dimen.freeform_resize_handle; final int outsetBottomId = R.dimen.freeform_resize_handle; + final int windowDecorLayoutId = getDesktopModeWindowDecorLayoutId( + taskInfo.getWindowingMode()); mRelayoutParams.reset(); mRelayoutParams.mRunningTaskInfo = taskInfo; - mRelayoutParams.mLayoutResId = R.layout.desktop_mode_window_decor; + mRelayoutParams.mLayoutResId = windowDecorLayoutId; mRelayoutParams.mCaptionHeightId = R.dimen.freeform_decor_caption_height; mRelayoutParams.mShadowRadiusId = shadowRadiusID; if (isDragResizeable) { @@ -172,23 +171,27 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin return; } if (oldRootView != mResult.mRootView) { - setupRootView(); + if (mRelayoutParams.mLayoutResId == R.layout.desktop_mode_focused_window_decor) { + mWindowDecorViewHolder = new DesktopModeFocusedWindowDecorationViewHolder( + mResult.mRootView, + mOnCaptionTouchListener, + mOnCaptionButtonClickListener + ); + } else if (mRelayoutParams.mLayoutResId + == R.layout.desktop_mode_app_controls_window_decor) { + mWindowDecorViewHolder = new DesktopModeAppControlsWindowDecorationViewHolder( + mResult.mRootView, + mOnCaptionTouchListener, + mOnCaptionButtonClickListener + ); + } else { + throw new IllegalArgumentException("Unexpected layout resource id"); + } } + mWindowDecorViewHolder.bindData(mTaskInfo); - // If this task is not focused, do not show caption. - setCaptionVisibility(mTaskInfo.isFocused); - - if (mTaskInfo.isFocused) { - if (DesktopModeStatus.isProto2Enabled()) { - updateButtonVisibility(); - } else if (DesktopModeStatus.isProto1Enabled()) { - // Only handle should show if Desktop Mode is inactive. - boolean desktopCurrentStatus = DesktopModeStatus.isActive(mContext); - if (mDesktopActive != desktopCurrentStatus) { - mDesktopActive = desktopCurrentStatus; - setButtonVisibility(mDesktopActive); - } - } + if (!mTaskInfo.isFocused) { + closeHandleMenu(); } if (!isDragResizeable) { @@ -219,24 +222,6 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop); } - /** - * Sets up listeners when a new root view is created. - */ - private void setupRootView() { - final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption); - caption.setOnTouchListener(mOnCaptionTouchListener); - final View handle = caption.findViewById(R.id.caption_handle); - handle.setOnTouchListener(mOnCaptionTouchListener); - handle.setOnClickListener(mOnCaptionButtonClickListener); - if (DesktopModeStatus.isProto1Enabled()) { - final View back = caption.findViewById(R.id.back_button); - back.setOnClickListener(mOnCaptionButtonClickListener); - final View close = caption.findViewById(R.id.close_window); - close.setOnClickListener(mOnCaptionButtonClickListener); - } - updateButtonVisibility(); - } - private void setupHandleMenu() { final View menu = mHandleMenu.mWindowViewHost.getView(); final View fullscreen = menu.findViewById(R.id.fullscreen_button); @@ -255,98 +240,26 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin collapse.setOnClickListener(mOnCaptionButtonClickListener); menu.setOnTouchListener(mOnCaptionTouchListener); - String packageName = mTaskInfo.baseActivity.getPackageName(); - PackageManager pm = mContext.getApplicationContext().getPackageManager(); - // TODO(b/268363572): Use IconProvider or BaseIconCache to set drawable/name. - try { - ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, - PackageManager.ApplicationInfoFlags.of(0)); - final ImageView appIcon = menu.findViewById(R.id.application_icon); - appIcon.setImageDrawable(pm.getApplicationIcon(applicationInfo)); - final TextView appName = menu.findViewById(R.id.application_name); - appName.setText(pm.getApplicationLabel(applicationInfo)); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Package not found: " + packageName, e); - } - } - - /** - * Sets caption visibility based on task focus. - * Note: Only applicable to Desktop Proto 1; Proto 2 only closes handle menu on focus loss - * @param visible whether or not the caption should be visible - */ - private void setCaptionVisibility(boolean visible) { - if (!visible) closeHandleMenu(); - if (!DesktopModeStatus.isProto1Enabled()) return; - final int v = visible ? View.VISIBLE : View.GONE; - final View captionView = mResult.mRootView.findViewById(R.id.desktop_mode_caption); - captionView.setVisibility(v); - - } - - /** - * Sets the visibility of buttons and color of caption based on desktop mode status - */ - void updateButtonVisibility() { - if (DesktopModeStatus.isProto2Enabled()) { - setButtonVisibility(mTaskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM); - } else if (DesktopModeStatus.isProto1Enabled()) { - mDesktopActive = DesktopModeStatus.isActive(mContext); - setButtonVisibility(mDesktopActive); - } - } - - /** - * Show or hide buttons - */ - void setButtonVisibility(boolean visible) { - final int visibility = visible && DesktopModeStatus.isProto1Enabled() - ? View.VISIBLE : View.GONE; - final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption); - final View back = caption.findViewById(R.id.back_button); - final View close = caption.findViewById(R.id.close_window); - back.setVisibility(visibility); - close.setVisibility(visibility); - final int buttonTintColorRes = - mDesktopActive ? R.color.decor_button_dark_color - : R.color.decor_button_light_color; - final ColorStateList buttonTintColor = - caption.getResources().getColorStateList(buttonTintColorRes, null /* theme */); - final View handle = caption.findViewById(R.id.caption_handle); - final VectorDrawable handleBackground = (VectorDrawable) handle.getBackground(); - handleBackground.setTintList(buttonTintColor); + final ImageView appIcon = menu.findViewById(R.id.application_icon); + final TextView appName = menu.findViewById(R.id.application_name); + loadAppInfo(appName, appIcon); } boolean isHandleMenuActive() { return mHandleMenu != null; } - void setCaptionColor(int captionColor) { - if (mResult.mRootView == null) { - return; - } - - final View caption = mResult.mRootView.findViewById(R.id.desktop_mode_caption); - final GradientDrawable captionDrawable = (GradientDrawable) caption.getBackground(); - captionDrawable.setColor(captionColor); - - final int buttonTintColorRes = - Color.valueOf(captionColor).luminance() < 0.5 - ? R.color.decor_button_light_color - : R.color.decor_button_dark_color; - final ColorStateList buttonTintColor = - caption.getResources().getColorStateList(buttonTintColorRes, null /* theme */); - - final View handle = caption.findViewById(R.id.caption_handle); - final Drawable handleBackground = handle.getBackground(); - handleBackground.setTintList(buttonTintColor); - if (DesktopModeStatus.isProto1Enabled()) { - final View back = caption.findViewById(R.id.back_button); - final Drawable backBackground = back.getBackground(); - backBackground.setTintList(buttonTintColor); - final View close = caption.findViewById(R.id.close_window); - final Drawable closeBackground = close.getBackground(); - closeBackground.setTintList(buttonTintColor); + private void loadAppInfo(TextView appNameTextView, ImageView appIconImageView) { + String packageName = mTaskInfo.realActivity.getPackageName(); + PackageManager pm = mContext.getApplicationContext().getPackageManager(); + try { + // TODO(b/268363572): Use IconProvider or BaseIconCache to set drawable/name. + ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, + PackageManager.ApplicationInfoFlags.of(0)); + appNameTextView.setText(pm.getApplicationLabel(applicationInfo)); + appIconImageView.setImageDrawable(pm.getApplicationIcon(applicationInfo)); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Package not found: " + packageName, e); } } @@ -371,9 +284,18 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin final int shadowRadius = loadDimensionPixelSize(resources, mHandleMenuShadowRadiusId); final int cornerRadius = loadDimensionPixelSize(resources, mHandleMenuCornerRadiusId); - final int x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2) - - mResult.mDecorContainerOffsetX; - final int y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY; + final int x, y; + if (mRelayoutParams.mLayoutResId + == R.layout.desktop_mode_app_controls_window_decor) { + // Align the handle menu to the left of the caption. + x = mRelayoutParams.mCaptionX - mResult.mDecorContainerOffsetX; + y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY; + } else { + // Position the handle menu at the center of the caption. + x = mRelayoutParams.mCaptionX + (captionWidth / 2) - (menuWidth / 2) + - mResult.mDecorContainerOffsetX; + y = mRelayoutParams.mCaptionY - mResult.mDecorContainerOffsetY; + } mHandleMenuPosition.set(x, y); String namePrefix = "Caption Menu"; mHandleMenu = addWindow(R.layout.desktop_mode_decor_handle_menu, namePrefix, t, x, y, @@ -503,6 +425,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin super.close(); } + private int getDesktopModeWindowDecorLayoutId(int windowingMode) { + if (DesktopModeStatus.isProto1Enabled()) { + return R.layout.desktop_mode_app_controls_window_decor; + } + return windowingMode == WINDOWING_MODE_FREEFORM + ? R.layout.desktop_mode_app_controls_window_decor + : R.layout.desktop_mode_focused_window_decor; + } + static class Factory { DesktopModeWindowDecoration create( diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java index ddd3b440e1a6..31e93ac6068f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java @@ -84,6 +84,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> }; RunningTaskInfo mTaskInfo; + int mLayoutResId; final SurfaceControl mTaskSurface; Display mDisplay; @@ -162,6 +163,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> if (params.mRunningTaskInfo != null) { mTaskInfo = params.mRunningTaskInfo; } + final int oldLayoutResId = mLayoutResId; + mLayoutResId = params.mLayoutResId; if (!mTaskInfo.isVisible) { releaseViews(); @@ -178,7 +181,8 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer> final Configuration taskConfig = getConfigurationWithOverrides(mTaskInfo); if (oldTaskConfig.densityDpi != taskConfig.densityDpi || mDisplay == null - || mDisplay.getDisplayId() != mTaskInfo.displayId) { + || mDisplay.getDisplayId() != mTaskInfo.displayId + || oldLayoutResId != mLayoutResId) { releaseViews(); if (!obtainDisplayOrRegisterListener()) { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt new file mode 100644 index 000000000000..95b5051cb81d --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeAppControlsWindowDecorationViewHolder.kt @@ -0,0 +1,94 @@ +package com.android.wm.shell.windowdecor.viewholder + +import android.app.ActivityManager.RunningTaskInfo +import android.content.pm.PackageManager +import android.content.res.ColorStateList +import android.graphics.drawable.GradientDrawable +import android.util.Log +import android.view.View +import android.widget.ImageButton +import android.widget.ImageView +import android.widget.TextView +import com.android.wm.shell.R + +/** + * A desktop mode window decoration used when the window is floating (i.e. freeform). It hosts + * finer controls such as a close window button and an "app info" section to pull up additional + * controls. + */ +internal class DesktopModeAppControlsWindowDecorationViewHolder( + rootView: View, + onCaptionTouchListener: View.OnTouchListener, + onCaptionButtonClickListener: View.OnClickListener +) : DesktopModeWindowDecorationViewHolder(rootView) { + + private val captionView: View = rootView.findViewById(R.id.desktop_mode_caption) + private val captionHandle: View = rootView.findViewById(R.id.caption_handle) + private val openMenuButton: View = rootView.findViewById(R.id.open_menu_button) + private val closeWindowButton: ImageButton = rootView.findViewById(R.id.close_window) + private val expandMenuButton: ImageButton = rootView.findViewById(R.id.expand_menu_button) + private val appNameTextView: TextView = rootView.findViewById(R.id.application_name) + private val appIconImageView: ImageView = rootView.findViewById(R.id.application_icon) + + init { + captionView.setOnTouchListener(onCaptionTouchListener) + captionHandle.setOnTouchListener(onCaptionTouchListener) + openMenuButton.setOnClickListener(onCaptionButtonClickListener) + closeWindowButton.setOnClickListener(onCaptionButtonClickListener) + } + + override fun bindData(taskInfo: RunningTaskInfo) { + bindAppInfo(taskInfo) + + val captionDrawable = captionView.background as GradientDrawable + captionDrawable.setColor(taskInfo.taskDescription.statusBarColor) + + closeWindowButton.imageTintList = ColorStateList.valueOf( + getCaptionCloseButtonColor(taskInfo)) + expandMenuButton.imageTintList = ColorStateList.valueOf( + getCaptionExpandButtonColor(taskInfo)) + appNameTextView.setTextColor(getCaptionAppNameTextColor(taskInfo)) + } + + private fun bindAppInfo(taskInfo: RunningTaskInfo) { + val packageName: String = taskInfo.realActivity.packageName + val pm: PackageManager = context.applicationContext.packageManager + try { + // TODO(b/268363572): Use IconProvider or BaseIconCache to set drawable/name. + val applicationInfo = pm.getApplicationInfo(packageName, + PackageManager.ApplicationInfoFlags.of(0)) + appNameTextView.text = pm.getApplicationLabel(applicationInfo) + appIconImageView.setImageDrawable(pm.getApplicationIcon(applicationInfo)) + } catch (e: PackageManager.NameNotFoundException) { + Log.w(TAG, "Package not found: $packageName", e) + } + } + + private fun getCaptionAppNameTextColor(taskInfo: RunningTaskInfo): Int { + return if (shouldUseLightCaptionColors(taskInfo)) { + context.getColor(R.color.desktop_mode_caption_app_name_light) + } else { + context.getColor(R.color.desktop_mode_caption_app_name_dark) + } + } + + private fun getCaptionCloseButtonColor(taskInfo: RunningTaskInfo): Int { + return if (shouldUseLightCaptionColors(taskInfo)) { + context.getColor(R.color.desktop_mode_caption_close_button_light) + } else { + context.getColor(R.color.desktop_mode_caption_close_button_dark) + } + } + + private fun getCaptionExpandButtonColor(taskInfo: RunningTaskInfo): Int { + return if (shouldUseLightCaptionColors(taskInfo)) { + context.getColor(R.color.desktop_mode_caption_expand_button_light) + } else { + context.getColor(R.color.desktop_mode_caption_expand_button_dark) + } + } + + companion object { + private const val TAG = "DesktopModeAppControlsWindowDecorationViewHolder" + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt new file mode 100644 index 000000000000..47a12a0cb71c --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeFocusedWindowDecorationViewHolder.kt @@ -0,0 +1,44 @@ +package com.android.wm.shell.windowdecor.viewholder + +import android.app.ActivityManager.RunningTaskInfo +import android.content.res.ColorStateList +import android.graphics.drawable.GradientDrawable +import android.view.View +import android.widget.ImageButton +import com.android.wm.shell.R + +/** + * A desktop mode window decoration used when the window is in full "focus" (i.e. fullscreen). It + * hosts a simple handle bar from which to initiate a drag motion to enter desktop mode. + */ +internal class DesktopModeFocusedWindowDecorationViewHolder( + rootView: View, + onCaptionTouchListener: View.OnTouchListener, + onCaptionButtonClickListener: View.OnClickListener +) : DesktopModeWindowDecorationViewHolder(rootView) { + + private val captionView: View = rootView.findViewById(R.id.desktop_mode_caption) + private val captionHandle: ImageButton = rootView.findViewById(R.id.caption_handle) + + init { + captionView.setOnTouchListener(onCaptionTouchListener) + captionHandle.setOnTouchListener(onCaptionTouchListener) + captionHandle.setOnClickListener(onCaptionButtonClickListener) + } + + override fun bindData(taskInfo: RunningTaskInfo) { + val captionColor = taskInfo.taskDescription.statusBarColor + val captionDrawable = captionView.background as GradientDrawable + captionDrawable.setColor(captionColor) + + captionHandle.imageTintList = ColorStateList.valueOf(getCaptionHandleBarColor(taskInfo)) + } + + private fun getCaptionHandleBarColor(taskInfo: RunningTaskInfo): Int { + return if (shouldUseLightCaptionColors(taskInfo)) { + context.getColor(R.color.desktop_mode_caption_handle_bar_light) + } else { + context.getColor(R.color.desktop_mode_caption_handle_bar_dark) + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt new file mode 100644 index 000000000000..514ea52cb8ae --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/DesktopModeWindowDecorationViewHolder.kt @@ -0,0 +1,28 @@ +package com.android.wm.shell.windowdecor.viewholder + +import android.app.ActivityManager.RunningTaskInfo +import android.content.Context +import android.graphics.Color +import android.view.View + +/** + * Encapsulates the root [View] of a window decoration and its children to facilitate looking up + * children (via findViewById) and updating to the latest data from [RunningTaskInfo]. + */ +internal abstract class DesktopModeWindowDecorationViewHolder(rootView: View) { + val context: Context = rootView.context + + /** + * A signal to the view holder that new data is available and that the views should be updated + * to reflect it. + */ + abstract fun bindData(taskInfo: RunningTaskInfo) + + /** + * Whether the caption items should use the 'light' color variant so that there's good contrast + * with the caption background color. + */ + protected fun shouldUseLightCaptionColors(taskInfo: RunningTaskInfo): Boolean { + return Color.valueOf(taskInfo.taskDescription.statusBarColor).luminance() < 0.5 + } +} |