Merge "Add bar type window caption." into tm-qpr-dev
This commit is contained in:
@@ -0,0 +1,32 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="32.0dp"
|
||||||
|
android:height="32.0dp"
|
||||||
|
android:viewportWidth="32.0"
|
||||||
|
android:viewportHeight="32.0"
|
||||||
|
>
|
||||||
|
<group android:scaleX="0.5"
|
||||||
|
android:scaleY="0.5"
|
||||||
|
android:translateX="8.0"
|
||||||
|
android:translateY="8.0" >
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black"
|
||||||
|
android:pathData="MM24,40.3 L7.7,24 24,7.7 26.8,10.45 15.3,22H40.3V26H15.3L26.8,37.5Z"/>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
@@ -15,8 +15,6 @@
|
|||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
<shape android:shape="rectangle"
|
<shape android:shape="rectangle"
|
||||||
android:tintMode="multiply"
|
|
||||||
android:tint="@color/decor_caption_title_color"
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<solid android:color="?android:attr/colorPrimary" />
|
<solid android:color="@android:color/white" />
|
||||||
</shape>
|
</shape>
|
||||||
|
|||||||
@@ -18,15 +18,13 @@
|
|||||||
android:width="32.0dp"
|
android:width="32.0dp"
|
||||||
android:height="32.0dp"
|
android:height="32.0dp"
|
||||||
android:viewportWidth="32.0"
|
android:viewportWidth="32.0"
|
||||||
android:viewportHeight="32.0"
|
android:viewportHeight="32.0">
|
||||||
android:tint="@color/decor_button_dark_color"
|
|
||||||
>
|
|
||||||
<group android:scaleX="0.5"
|
<group android:scaleX="0.5"
|
||||||
android:scaleY="0.5"
|
android:scaleY="0.5"
|
||||||
android:translateX="8.0"
|
android:translateX="8.0"
|
||||||
android:translateY="8.0" >
|
android:translateY="8.0" >
|
||||||
<path
|
<path
|
||||||
android:fillColor="@android:color/white"
|
android:fillColor="@android:color/black"
|
||||||
android:pathData="M6.9,4.0l-2.9,2.9 9.1,9.1 -9.1,9.200001 2.9,2.799999 9.1,-9.1 9.1,9.1 2.9,-2.799999 -9.1,-9.200001 9.1,-9.1 -2.9,-2.9 -9.1,9.2z"/>
|
android:pathData="M12.45,38.35 L9.65,35.55 21.2,24 9.65,12.45 12.45,9.65 24,21.2 35.55,9.65 38.35,12.45 26.8,24 38.35,35.55 35.55,38.35 24,26.8Z"/>
|
||||||
</group>
|
</group>
|
||||||
</vector>
|
</vector>
|
||||||
|
|||||||
23
libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
Normal file
23
libs/WindowManager/Shell/res/drawable/decor_handle_dark.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/black" android:pathData="M3,5V3H21V5Z"/>
|
||||||
|
</vector>
|
||||||
@@ -17,39 +17,33 @@
|
|||||||
<com.android.wm.shell.windowdecor.WindowDecorLinearLayout
|
<com.android.wm.shell.windowdecor.WindowDecorLinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:id="@+id/caption"
|
android:id="@+id/caption"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="end"
|
android:gravity="center_horizontal"
|
||||||
android:background="@drawable/decor_caption_title">
|
android:background="@drawable/decor_caption_title">
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/minimize_window"
|
android:id="@+id/back_button"
|
||||||
android:visibility="gone"
|
|
||||||
android:layout_width="32dp"
|
android:layout_width="32dp"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
android:layout_margin="5dp"
|
android:layout_margin="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:layout_gravity="top|end"
|
android:contentDescription="@string/back_button_text"
|
||||||
android:contentDescription="@string/maximize_button_text"
|
android:background="@drawable/decor_back_button_dark"
|
||||||
android:background="@drawable/decor_minimize_button_dark"
|
/>
|
||||||
android:duplicateParentState="true"/>
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/maximize_window"
|
android:id="@+id/caption_handle"
|
||||||
android:layout_width="32dp"
|
android:layout_width="128dp"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
android:layout_margin="5dp"
|
android:layout_margin="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:layout_gravity="center_vertical|end"
|
android:contentDescription="@string/handle_text"
|
||||||
android:contentDescription="@string/maximize_button_text"
|
android:background="@drawable/decor_handle_dark"/>
|
||||||
android:background="@drawable/decor_maximize_button_dark"
|
|
||||||
android:duplicateParentState="true"/>
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/close_window"
|
android:id="@+id/close_window"
|
||||||
android:layout_width="32dp"
|
android:layout_width="32dp"
|
||||||
android:layout_height="32dp"
|
android:layout_height="32dp"
|
||||||
android:layout_margin="5dp"
|
android:layout_margin="5dp"
|
||||||
android:padding="4dp"
|
android:padding="4dp"
|
||||||
android:layout_gravity="center_vertical|end"
|
|
||||||
android:contentDescription="@string/close_button_text"
|
android:contentDescription="@string/close_button_text"
|
||||||
android:background="@drawable/decor_close_button_dark"
|
android:background="@drawable/decor_close_button_dark"/>
|
||||||
android:duplicateParentState="true"/>
|
|
||||||
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
|
</com.android.wm.shell.windowdecor.WindowDecorLinearLayout>
|
||||||
@@ -193,4 +193,8 @@
|
|||||||
<string name="minimize_button_text">Minimize</string>
|
<string name="minimize_button_text">Minimize</string>
|
||||||
<!-- Accessibility text for the close window button [CHAR LIMIT=NONE] -->
|
<!-- Accessibility text for the close window button [CHAR LIMIT=NONE] -->
|
||||||
<string name="close_button_text">Close</string>
|
<string name="close_button_text">Close</string>
|
||||||
|
<!-- Accessibility text for the caption back button [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="back_button_text">Back</string>
|
||||||
|
<!-- Accessibility text for the caption handle [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="handle_text">Handle</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -19,15 +19,20 @@ package com.android.wm.shell.windowdecor;
|
|||||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
|
||||||
|
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.ActivityManager.RunningTaskInfo;
|
import android.app.ActivityManager.RunningTaskInfo;
|
||||||
import android.app.ActivityTaskManager;
|
import android.app.ActivityTaskManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.hardware.input.InputManager;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
import android.util.SparseArray;
|
import android.util.SparseArray;
|
||||||
import android.view.Choreographer;
|
import android.view.Choreographer;
|
||||||
|
import android.view.InputDevice;
|
||||||
|
import android.view.KeyCharacterMap;
|
||||||
|
import android.view.KeyEvent;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -47,7 +52,9 @@ import com.android.wm.shell.transition.Transitions;
|
|||||||
* View model for the window decoration with a caption and shadows. Works with
|
* View model for the window decoration with a caption and shadows. Works with
|
||||||
* {@link CaptionWindowDecoration}.
|
* {@link CaptionWindowDecoration}.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
||||||
|
private static final String TAG = "CaptionViewModel";
|
||||||
private final ActivityTaskManager mActivityTaskManager;
|
private final ActivityTaskManager mActivityTaskManager;
|
||||||
private final ShellTaskOrganizer mTaskOrganizer;
|
private final ShellTaskOrganizer mTaskOrganizer;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
@@ -107,7 +114,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
|
windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
|
||||||
windowDecoration.setDragResizeCallback(taskPositioner);
|
windowDecoration.setDragResizeCallback(taskPositioner);
|
||||||
setupWindowDecorationForTransition(taskInfo, startT, finishT);
|
setupWindowDecorationForTransition(taskInfo, startT, finishT);
|
||||||
setupCaptionColor(taskInfo, windowDecoration);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,12 +123,6 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
if (decoration == null) return;
|
if (decoration == null) return;
|
||||||
|
|
||||||
decoration.relayout(taskInfo);
|
decoration.relayout(taskInfo);
|
||||||
setupCaptionColor(taskInfo, decoration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupCaptionColor(RunningTaskInfo taskInfo, CaptionWindowDecoration decoration) {
|
|
||||||
int statusBarColor = taskInfo.taskDescription.getStatusBarColor();
|
|
||||||
decoration.setCaptionColor(statusBarColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -153,6 +153,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
private final DragResizeCallback mDragResizeCallback;
|
private final DragResizeCallback mDragResizeCallback;
|
||||||
|
|
||||||
private int mDragPointerId = -1;
|
private int mDragPointerId = -1;
|
||||||
|
private boolean mDragActive = false;
|
||||||
|
|
||||||
private CaptionTouchEventListener(
|
private CaptionTouchEventListener(
|
||||||
RunningTaskInfo taskInfo,
|
RunningTaskInfo taskInfo,
|
||||||
@@ -173,42 +174,38 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
} else {
|
} else {
|
||||||
mSyncQueue.queue(wct);
|
mSyncQueue.queue(wct);
|
||||||
}
|
}
|
||||||
} else if (id == R.id.maximize_window) {
|
} else if (id == R.id.back_button) {
|
||||||
WindowContainerTransaction wct = new WindowContainerTransaction();
|
injectBackKey();
|
||||||
RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
|
|
||||||
int targetWindowingMode = taskInfo.getWindowingMode() != WINDOWING_MODE_FULLSCREEN
|
|
||||||
? WINDOWING_MODE_FULLSCREEN : WINDOWING_MODE_FREEFORM;
|
|
||||||
int displayWindowingMode =
|
|
||||||
taskInfo.configuration.windowConfiguration.getDisplayWindowingMode();
|
|
||||||
wct.setWindowingMode(mTaskToken,
|
|
||||||
targetWindowingMode == displayWindowingMode
|
|
||||||
? WINDOWING_MODE_UNDEFINED : targetWindowingMode);
|
|
||||||
if (targetWindowingMode == WINDOWING_MODE_FULLSCREEN) {
|
|
||||||
wct.setBounds(mTaskToken, null);
|
|
||||||
}
|
}
|
||||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
|
||||||
mTransitionStarter.startWindowingModeTransition(targetWindowingMode, wct);
|
|
||||||
} else {
|
|
||||||
mSyncQueue.queue(wct);
|
|
||||||
}
|
}
|
||||||
} else if (id == R.id.minimize_window) {
|
private void injectBackKey() {
|
||||||
WindowContainerTransaction wct = new WindowContainerTransaction();
|
sendBackEvent(KeyEvent.ACTION_DOWN);
|
||||||
wct.reorder(mTaskToken, false);
|
sendBackEvent(KeyEvent.ACTION_UP);
|
||||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
|
||||||
mTransitionStarter.startMinimizedModeTransition(wct);
|
|
||||||
} else {
|
|
||||||
mSyncQueue.queue(wct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendBackEvent(int action) {
|
||||||
|
final long when = SystemClock.uptimeMillis();
|
||||||
|
final KeyEvent ev = new KeyEvent(when, when, action, KeyEvent.KEYCODE_BACK,
|
||||||
|
0 /* repeat */, 0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD,
|
||||||
|
0 /* scancode */, KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
|
||||||
|
InputDevice.SOURCE_KEYBOARD);
|
||||||
|
|
||||||
|
ev.setDisplayId(mContext.getDisplay().getDisplayId());
|
||||||
|
if (!InputManager.getInstance()
|
||||||
|
.injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) {
|
||||||
|
Log.e(TAG, "Inject input event fail");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onTouch(View v, MotionEvent e) {
|
public boolean onTouch(View v, MotionEvent e) {
|
||||||
if (v.getId() != R.id.caption) {
|
int id = v.getId();
|
||||||
|
if (id != R.id.caption_handle && id != R.id.caption) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (id == R.id.caption_handle || mDragActive) {
|
||||||
handleEventForMove(e);
|
handleEventForMove(e);
|
||||||
|
}
|
||||||
if (e.getAction() != MotionEvent.ACTION_DOWN) {
|
if (e.getAction() != MotionEvent.ACTION_DOWN) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -231,6 +228,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
}
|
}
|
||||||
switch (e.getActionMasked()) {
|
switch (e.getActionMasked()) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
mDragActive = true;
|
||||||
mDragPointerId = e.getPointerId(0);
|
mDragPointerId = e.getPointerId(0);
|
||||||
mDragResizeCallback.onDragResizeStart(
|
mDragResizeCallback.onDragResizeStart(
|
||||||
0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
|
0 /* ctrlType */, e.getRawX(0), e.getRawY(0));
|
||||||
@@ -243,6 +241,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
|
|||||||
}
|
}
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
case MotionEvent.ACTION_CANCEL: {
|
case MotionEvent.ACTION_CANCEL: {
|
||||||
|
mDragActive = false;
|
||||||
int dragPointerIdx = e.findPointerIndex(mDragPointerId);
|
int dragPointerIdx = e.findPointerIndex(mDragPointerId);
|
||||||
int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId)
|
int statusBarHeight = mDisplayController.getDisplayLayout(taskInfo.displayId)
|
||||||
.stableInsets().top;
|
.stableInsets().top;
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import android.content.Context;
|
|||||||
import android.content.res.ColorStateList;
|
import android.content.res.ColorStateList;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.graphics.drawable.GradientDrawable;
|
|
||||||
import android.graphics.drawable.VectorDrawable;
|
import android.graphics.drawable.VectorDrawable;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.view.Choreographer;
|
import android.view.Choreographer;
|
||||||
@@ -39,11 +38,7 @@ import com.android.wm.shell.desktopmode.DesktopModeStatus;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
|
* Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
|
||||||
* {@link CaptionWindowDecorViewModel}. The caption bar contains maximize and close buttons.
|
* {@link CaptionWindowDecorViewModel}. The caption bar contains a handle, back button, and close button.
|
||||||
*
|
|
||||||
* {@link CaptionWindowDecorViewModel} can change the color of the caption bar based on the foremost
|
|
||||||
* app's request through {@link #setCaptionColor(int)}, in which it changes the foreground color of
|
|
||||||
* caption buttons according to the luminance of the background.
|
|
||||||
*
|
*
|
||||||
* The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't.
|
* The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't.
|
||||||
*/
|
*/
|
||||||
@@ -55,6 +50,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
|
|
||||||
// Height of button (32dp) + 2 * margin (5dp each)
|
// Height of button (32dp) + 2 * margin (5dp each)
|
||||||
private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42;
|
private static final int DECOR_CAPTION_HEIGHT_IN_DIP = 42;
|
||||||
|
// Width of buttons (64dp) + handle (128dp) + padding (24dp total)
|
||||||
|
private static final int DECOR_CAPTION_WIDTH_IN_DIP = 216;
|
||||||
private static final int RESIZE_HANDLE_IN_DIP = 30;
|
private static final int RESIZE_HANDLE_IN_DIP = 30;
|
||||||
private static final int RESIZE_CORNER_IN_DIP = 44;
|
private static final int RESIZE_CORNER_IN_DIP = 44;
|
||||||
|
|
||||||
@@ -75,6 +72,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
|
private final WindowDecoration.RelayoutResult<WindowDecorLinearLayout> mResult =
|
||||||
new WindowDecoration.RelayoutResult<>();
|
new WindowDecoration.RelayoutResult<>();
|
||||||
|
|
||||||
|
private boolean mDesktopActive;
|
||||||
|
|
||||||
CaptionWindowDecoration(
|
CaptionWindowDecoration(
|
||||||
Context context,
|
Context context,
|
||||||
DisplayController displayController,
|
DisplayController displayController,
|
||||||
@@ -89,6 +88,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
mHandler = handler;
|
mHandler = handler;
|
||||||
mChoreographer = choreographer;
|
mChoreographer = choreographer;
|
||||||
mSyncQueue = syncQueue;
|
mSyncQueue = syncQueue;
|
||||||
|
mDesktopActive = DesktopModeStatus.isActive(mContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCaptionListeners(
|
void setCaptionListeners(
|
||||||
@@ -125,8 +125,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
|
final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
|
||||||
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
final WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||||
relayout(taskInfo, R.layout.caption_window_decoration, oldRootView,
|
relayout(taskInfo, R.layout.caption_window_decoration, oldRootView,
|
||||||
DECOR_CAPTION_HEIGHT_IN_DIP, outset, shadowRadiusDp, startT, finishT, wct, mResult);
|
DECOR_CAPTION_HEIGHT_IN_DIP, DECOR_CAPTION_WIDTH_IN_DIP, outset, shadowRadiusDp,
|
||||||
taskInfo = null; // Clear it just in case we use it accidentally
|
startT, finishT, wct, mResult);
|
||||||
|
|
||||||
mTaskOrganizer.applyTransaction(wct);
|
mTaskOrganizer.applyTransaction(wct);
|
||||||
|
|
||||||
@@ -139,6 +139,17 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
setupRootView();
|
setupRootView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If this task is not focused, do not show caption.
|
||||||
|
setCaptionVisibility(taskInfo.isFocused);
|
||||||
|
|
||||||
|
// Only handle should show if Desktop Mode is inactive.
|
||||||
|
boolean desktopCurrentStatus = DesktopModeStatus.isActive(mContext);
|
||||||
|
if (mDesktopActive != desktopCurrentStatus && taskInfo.isFocused) {
|
||||||
|
mDesktopActive = desktopCurrentStatus;
|
||||||
|
setButtonVisibility();
|
||||||
|
}
|
||||||
|
taskInfo = null; // Clear it just in case we use it accidentally
|
||||||
|
|
||||||
if (!isDragResizeable) {
|
if (!isDragResizeable) {
|
||||||
closeDragResizeListener();
|
closeDragResizeListener();
|
||||||
return;
|
return;
|
||||||
@@ -168,42 +179,46 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
|
|||||||
private void setupRootView() {
|
private void setupRootView() {
|
||||||
View caption = mResult.mRootView.findViewById(R.id.caption);
|
View caption = mResult.mRootView.findViewById(R.id.caption);
|
||||||
caption.setOnTouchListener(mOnCaptionTouchListener);
|
caption.setOnTouchListener(mOnCaptionTouchListener);
|
||||||
View maximize = caption.findViewById(R.id.maximize_window);
|
|
||||||
if (DesktopModeStatus.IS_SUPPORTED) {
|
|
||||||
// Hide maximize button when desktop mode is available
|
|
||||||
maximize.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
maximize.setVisibility(View.VISIBLE);
|
|
||||||
maximize.setOnClickListener(mOnCaptionButtonClickListener);
|
|
||||||
}
|
|
||||||
View close = caption.findViewById(R.id.close_window);
|
View close = caption.findViewById(R.id.close_window);
|
||||||
close.setOnClickListener(mOnCaptionButtonClickListener);
|
close.setOnClickListener(mOnCaptionButtonClickListener);
|
||||||
View minimize = caption.findViewById(R.id.minimize_window);
|
View back = caption.findViewById(R.id.back_button);
|
||||||
minimize.setOnClickListener(mOnCaptionButtonClickListener);
|
back.setOnClickListener(mOnCaptionButtonClickListener);
|
||||||
}
|
View handle = caption.findViewById(R.id.caption_handle);
|
||||||
|
handle.setOnTouchListener(mOnCaptionTouchListener);
|
||||||
void setCaptionColor(int captionColor) {
|
setButtonVisibility();
|
||||||
if (mResult.mRootView == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets caption visibility based on task focus.
|
||||||
|
*
|
||||||
|
* @param visible whether or not the caption should be visible
|
||||||
|
*/
|
||||||
|
private void setCaptionVisibility(boolean visible) {
|
||||||
|
int v = visible ? View.VISIBLE : View.GONE;
|
||||||
View caption = mResult.mRootView.findViewById(R.id.caption);
|
View caption = mResult.mRootView.findViewById(R.id.caption);
|
||||||
GradientDrawable captionDrawable = (GradientDrawable) caption.getBackground();
|
caption.setVisibility(v);
|
||||||
captionDrawable.setColor(captionColor);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the visibility of buttons and color of caption based on desktop mode status
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setButtonVisibility() {
|
||||||
|
int v = mDesktopActive ? View.VISIBLE : View.GONE;
|
||||||
|
View caption = mResult.mRootView.findViewById(R.id.caption);
|
||||||
|
View back = caption.findViewById(R.id.back_button);
|
||||||
|
View close = caption.findViewById(R.id.close_window);
|
||||||
|
back.setVisibility(v);
|
||||||
|
close.setVisibility(v);
|
||||||
int buttonTintColorRes =
|
int buttonTintColorRes =
|
||||||
Color.valueOf(captionColor).luminance() < 0.5
|
mDesktopActive ? R.color.decor_button_dark_color
|
||||||
? R.color.decor_button_light_color
|
: R.color.decor_button_light_color;
|
||||||
: R.color.decor_button_dark_color;
|
|
||||||
ColorStateList buttonTintColor =
|
ColorStateList buttonTintColor =
|
||||||
caption.getResources().getColorStateList(buttonTintColorRes, null /* theme */);
|
caption.getResources().getColorStateList(buttonTintColorRes, null /* theme */);
|
||||||
View maximize = caption.findViewById(R.id.maximize_window);
|
View handle = caption.findViewById(R.id.caption_handle);
|
||||||
VectorDrawable maximizeBackground = (VectorDrawable) maximize.getBackground();
|
VectorDrawable handleBackground = (VectorDrawable) handle.getBackground();
|
||||||
maximizeBackground.setTintList(buttonTintColor);
|
handleBackground.setTintList(buttonTintColor);
|
||||||
|
caption.setBackgroundColor(v == View.VISIBLE ? Color.WHITE : Color.TRANSPARENT);
|
||||||
View close = caption.findViewById(R.id.close_window);
|
|
||||||
VectorDrawable closeBackground = (VectorDrawable) close.getBackground();
|
|
||||||
closeBackground.setTintList(buttonTintColor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void closeDragResizeListener() {
|
private void closeDragResizeListener() {
|
||||||
|
|||||||
@@ -143,9 +143,9 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
|||||||
abstract void relayout(RunningTaskInfo taskInfo);
|
abstract void relayout(RunningTaskInfo taskInfo);
|
||||||
|
|
||||||
void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp,
|
void relayout(RunningTaskInfo taskInfo, int layoutResId, T rootView, float captionHeightDp,
|
||||||
Rect outsetsDp, float shadowRadiusDp, SurfaceControl.Transaction startT,
|
float captionWidthDp, Rect outsetsDp, float shadowRadiusDp,
|
||||||
SurfaceControl.Transaction finishT, WindowContainerTransaction wct,
|
SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
|
||||||
RelayoutResult<T> outResult) {
|
WindowContainerTransaction wct, RelayoutResult<T> outResult) {
|
||||||
outResult.reset();
|
outResult.reset();
|
||||||
|
|
||||||
final Configuration oldTaskConfig = mTaskInfo.getConfiguration();
|
final Configuration oldTaskConfig = mTaskInfo.getConfiguration();
|
||||||
@@ -249,8 +249,15 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int captionHeight = (int) Math.ceil(captionHeightDp * outResult.mDensity);
|
final int captionHeight = (int) Math.ceil(captionHeightDp * outResult.mDensity);
|
||||||
|
final int captionWidth = (int) Math.ceil(captionWidthDp * outResult.mDensity);
|
||||||
|
|
||||||
|
//Prevent caption from going offscreen if task is too high up
|
||||||
|
final int captionYPos = taskBounds.top <= captionHeight / 2 ? 0 : captionHeight / 2;
|
||||||
|
|
||||||
startT.setPosition(
|
startT.setPosition(
|
||||||
mCaptionContainerSurface, -decorContainerOffsetX, -decorContainerOffsetY)
|
mCaptionContainerSurface, -decorContainerOffsetX
|
||||||
|
+ taskBounds.width() / 2 - captionWidth / 2,
|
||||||
|
-decorContainerOffsetY - captionYPos)
|
||||||
.setWindowCrop(mCaptionContainerSurface, taskBounds.width(), captionHeight)
|
.setWindowCrop(mCaptionContainerSurface, taskBounds.width(), captionHeight)
|
||||||
.show(mCaptionContainerSurface);
|
.show(mCaptionContainerSurface);
|
||||||
|
|
||||||
@@ -264,7 +271,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
|||||||
// Caption view
|
// Caption view
|
||||||
mCaptionWindowManager.setConfiguration(taskConfig);
|
mCaptionWindowManager.setConfiguration(taskConfig);
|
||||||
final WindowManager.LayoutParams lp =
|
final WindowManager.LayoutParams lp =
|
||||||
new WindowManager.LayoutParams(taskBounds.width(), captionHeight,
|
new WindowManager.LayoutParams(captionWidth, captionHeight,
|
||||||
WindowManager.LayoutParams.TYPE_APPLICATION,
|
WindowManager.LayoutParams.TYPE_APPLICATION,
|
||||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSPARENT);
|
||||||
lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
|
lp.setTitle("Caption of Task=" + mTaskInfo.taskId);
|
||||||
@@ -282,7 +289,7 @@ public abstract class WindowDecoration<T extends View & TaskFocusStateConsumer>
|
|||||||
|
|
||||||
// Caption insets
|
// Caption insets
|
||||||
mCaptionInsetsRect.set(taskBounds);
|
mCaptionInsetsRect.set(taskBounds);
|
||||||
mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight;
|
mCaptionInsetsRect.bottom = mCaptionInsetsRect.top + captionHeight - captionYPos;
|
||||||
wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES);
|
wct.addRectInsetsProvider(mTaskInfo.token, mCaptionInsetsRect, CAPTION_INSETS_TYPES);
|
||||||
} else {
|
} else {
|
||||||
startT.hide(mCaptionContainerSurface);
|
startT.hide(mCaptionContainerSurface);
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ import java.util.function.Supplier;
|
|||||||
@RunWith(AndroidTestingRunner.class)
|
@RunWith(AndroidTestingRunner.class)
|
||||||
public class WindowDecorationTests extends ShellTestCase {
|
public class WindowDecorationTests extends ShellTestCase {
|
||||||
private static final int CAPTION_HEIGHT_DP = 32;
|
private static final int CAPTION_HEIGHT_DP = 32;
|
||||||
|
private static final int CAPTION_WIDTH_DP = 216;
|
||||||
private static final int SHADOW_RADIUS_DP = 5;
|
private static final int SHADOW_RADIUS_DP = 5;
|
||||||
private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400);
|
private static final Rect TASK_BOUNDS = new Rect(100, 300, 400, 400);
|
||||||
private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60);
|
private static final Point TASK_POSITION_IN_PARENT = new Point(40, 60);
|
||||||
@@ -220,7 +221,7 @@ public class WindowDecorationTests extends ShellTestCase {
|
|||||||
|
|
||||||
verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
|
verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
|
||||||
verify(captionContainerSurfaceBuilder).setContainerLayer();
|
verify(captionContainerSurfaceBuilder).setContainerLayer();
|
||||||
verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
|
verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, -46, 8);
|
||||||
verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
|
verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
|
||||||
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
|
verify(mMockSurfaceControlStartT).show(captionContainerSurface);
|
||||||
|
|
||||||
@@ -410,7 +411,7 @@ public class WindowDecorationTests extends ShellTestCase {
|
|||||||
@Override
|
@Override
|
||||||
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
|
void relayout(ActivityManager.RunningTaskInfo taskInfo) {
|
||||||
relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP,
|
relayout(null /* taskInfo */, 0 /* layoutResId */, mMockView, CAPTION_HEIGHT_DP,
|
||||||
mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT,
|
CAPTION_WIDTH_DP, mOutsetsDp, SHADOW_RADIUS_DP, mMockSurfaceControlStartT,
|
||||||
mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mRelayoutResult);
|
mMockSurfaceControlFinishT, mMockWindowContainerTransaction, mRelayoutResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user