Merge changes I3460e27e,Ib2f1d194,I28b8f266 into udc-dev
* changes: Always close the handle menu if the window loses focus Delegate window decor view binding / updating to *ViewHolders Update desktop mode caption bar to newest spec
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,24 +171,28 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
|
||||
return;
|
||||
}
|
||||
if (oldRootView != mResult.mRootView) {
|
||||
setupRootView();
|
||||
}
|
||||
|
||||
// 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 (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 (!mTaskInfo.isFocused) {
|
||||
closeHandleMenu();
|
||||
}
|
||||
|
||||
if (!isDragResizeable) {
|
||||
closeDragResizeListener();
|
||||
@@ -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(
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user