Merge "Allow non-resizable apps in split-screen (12/n)" into sc-dev
This commit is contained in:
@@ -14,35 +14,52 @@
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<com.android.wm.shell.sizecompatui.SizeCompatHintPopup
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content">
|
||||||
android:background="@android:color/background_light"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
<FrameLayout
|
||||||
android:layout_width="180dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingLeft="10dp"
|
|
||||||
android:paddingRight="10dp"
|
|
||||||
android:paddingTop="10dp"
|
|
||||||
android:text="@string/restart_button_description"
|
|
||||||
android:textAlignment="viewStart"
|
|
||||||
android:textColor="@android:color/primary_text_light"
|
|
||||||
android:textSize="16sp" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/got_it"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:includeFontPadding="false"
|
android:gravity="center"
|
||||||
android:layout_gravity="end"
|
android:clipToPadding="false"
|
||||||
android:minHeight="36dp"
|
android:padding="@dimen/bubble_elevation">
|
||||||
android:background="?android:attr/selectableItemBackground"
|
|
||||||
android:text="@string/got_it"
|
|
||||||
android:textAllCaps="true"
|
|
||||||
android:textColor="#3c78d8"
|
|
||||||
android:textSize="16sp"
|
|
||||||
android:textStyle="bold" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@android:color/background_light"
|
||||||
|
android:elevation="@dimen/bubble_elevation"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="180dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingLeft="10dp"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:text="@string/restart_button_description"
|
||||||
|
android:textAlignment="viewStart"
|
||||||
|
android:textColor="@android:color/primary_text_light"
|
||||||
|
android:textSize="16sp"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/got_it"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:minHeight="36dp"
|
||||||
|
android:background="?android:attr/selectableItemBackground"
|
||||||
|
android:text="@string/got_it"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:textColor="#3c78d8"
|
||||||
|
android:textSize="16sp"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
</com.android.wm.shell.sizecompatui.SizeCompatHintPopup>
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.wm.shell.sizecompatui;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.res.ColorStateList;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.drawable.RippleDrawable;
|
||||||
|
import android.util.AttributeSet;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.android.wm.shell.R;
|
||||||
|
|
||||||
|
/** Popup to show the hint about the {@link SizeCompatRestartButton}. */
|
||||||
|
public class SizeCompatHintPopup extends FrameLayout implements View.OnClickListener {
|
||||||
|
|
||||||
|
private SizeCompatUILayout mLayout;
|
||||||
|
|
||||||
|
public SizeCompatHintPopup(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SizeCompatHintPopup(Context context, @Nullable AttributeSet attrs) {
|
||||||
|
super(context, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SizeCompatHintPopup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||||
|
super(context, attrs, defStyleAttr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SizeCompatHintPopup(Context context, AttributeSet attrs, int defStyleAttr,
|
||||||
|
int defStyleRes) {
|
||||||
|
super(context, attrs, defStyleAttr, defStyleRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void inject(SizeCompatUILayout layout) {
|
||||||
|
mLayout = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
|
final Button gotItButton = findViewById(R.id.got_it);
|
||||||
|
gotItButton.setBackground(new RippleDrawable(ColorStateList.valueOf(Color.LTGRAY),
|
||||||
|
null /* content */, null /* mask */));
|
||||||
|
gotItButton.setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
mLayout.dismissHint();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,19 +22,13 @@ import android.graphics.Color;
|
|||||||
import android.graphics.drawable.GradientDrawable;
|
import android.graphics.drawable.GradientDrawable;
|
||||||
import android.graphics.drawable.RippleDrawable;
|
import android.graphics.drawable.RippleDrawable;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
|
||||||
import android.widget.Button;
|
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
import android.widget.LinearLayout;
|
|
||||||
import android.widget.PopupWindow;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import com.android.internal.annotations.VisibleForTesting;
|
|
||||||
import com.android.wm.shell.R;
|
import com.android.wm.shell.R;
|
||||||
|
|
||||||
/** Button to restart the size compat activity. */
|
/** Button to restart the size compat activity. */
|
||||||
@@ -42,10 +36,6 @@ public class SizeCompatRestartButton extends FrameLayout implements View.OnClick
|
|||||||
View.OnLongClickListener {
|
View.OnLongClickListener {
|
||||||
|
|
||||||
private SizeCompatUILayout mLayout;
|
private SizeCompatUILayout mLayout;
|
||||||
private ImageButton mRestartButton;
|
|
||||||
@VisibleForTesting
|
|
||||||
PopupWindow mShowingHint;
|
|
||||||
private WindowManager.LayoutParams mWinParams;
|
|
||||||
|
|
||||||
public SizeCompatRestartButton(@NonNull Context context) {
|
public SizeCompatRestartButton(@NonNull Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
@@ -67,24 +57,19 @@ public class SizeCompatRestartButton extends FrameLayout implements View.OnClick
|
|||||||
|
|
||||||
void inject(SizeCompatUILayout layout) {
|
void inject(SizeCompatUILayout layout) {
|
||||||
mLayout = layout;
|
mLayout = layout;
|
||||||
mWinParams = layout.getWindowLayoutParams();
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove() {
|
|
||||||
dismissHint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
super.onFinishInflate();
|
super.onFinishInflate();
|
||||||
mRestartButton = findViewById(R.id.size_compat_restart_button);
|
final ImageButton restartButton = findViewById(R.id.size_compat_restart_button);
|
||||||
final ColorStateList color = ColorStateList.valueOf(Color.LTGRAY);
|
final ColorStateList color = ColorStateList.valueOf(Color.LTGRAY);
|
||||||
final GradientDrawable mask = new GradientDrawable();
|
final GradientDrawable mask = new GradientDrawable();
|
||||||
mask.setShape(GradientDrawable.OVAL);
|
mask.setShape(GradientDrawable.OVAL);
|
||||||
mask.setColor(color);
|
mask.setColor(color);
|
||||||
mRestartButton.setBackground(new RippleDrawable(color, null /* content */, mask));
|
restartButton.setBackground(new RippleDrawable(color, null /* content */, mask));
|
||||||
mRestartButton.setOnClickListener(this);
|
restartButton.setOnClickListener(this);
|
||||||
mRestartButton.setOnLongClickListener(this);
|
restartButton.setOnLongClickListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,69 +79,7 @@ public class SizeCompatRestartButton extends FrameLayout implements View.OnClick
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onLongClick(View v) {
|
public boolean onLongClick(View v) {
|
||||||
showHint();
|
mLayout.onRestartButtonLongClicked();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onAttachedToWindow() {
|
|
||||||
super.onAttachedToWindow();
|
|
||||||
if (mLayout.mShouldShowHint) {
|
|
||||||
mLayout.mShouldShowHint = false;
|
|
||||||
showHint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setVisibility(@Visibility int visibility) {
|
|
||||||
if (visibility == View.GONE && mShowingHint != null) {
|
|
||||||
// Also dismiss the popup.
|
|
||||||
dismissHint();
|
|
||||||
}
|
|
||||||
super.setVisibility(visibility);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setLayoutDirection(int layoutDirection) {
|
|
||||||
final int gravity = SizeCompatUILayout.getGravity(layoutDirection);
|
|
||||||
if (mWinParams.gravity != gravity) {
|
|
||||||
mWinParams.gravity = gravity;
|
|
||||||
getContext().getSystemService(WindowManager.class).updateViewLayout(this,
|
|
||||||
mWinParams);
|
|
||||||
}
|
|
||||||
super.setLayoutDirection(layoutDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void showHint() {
|
|
||||||
if (mShowingHint != null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: popup is not attached to the button surface. Need to handle this differently for
|
|
||||||
// non-fullscreen task.
|
|
||||||
final View popupView = LayoutInflater.from(getContext()).inflate(
|
|
||||||
R.layout.size_compat_mode_hint, null);
|
|
||||||
final PopupWindow popupWindow = new PopupWindow(popupView,
|
|
||||||
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
|
|
||||||
popupWindow.setWindowLayoutType(mWinParams.type);
|
|
||||||
popupWindow.setElevation(getResources().getDimension(R.dimen.bubble_elevation));
|
|
||||||
popupWindow.setAnimationStyle(android.R.style.Animation_InputMethod);
|
|
||||||
popupWindow.setClippingEnabled(false);
|
|
||||||
popupWindow.setOnDismissListener(() -> mShowingHint = null);
|
|
||||||
mShowingHint = popupWindow;
|
|
||||||
|
|
||||||
final Button gotItButton = popupView.findViewById(R.id.got_it);
|
|
||||||
gotItButton.setBackground(new RippleDrawable(ColorStateList.valueOf(Color.LTGRAY),
|
|
||||||
null /* content */, null /* mask */));
|
|
||||||
gotItButton.setOnClickListener(view -> dismissHint());
|
|
||||||
popupWindow.showAtLocation(mRestartButton, mWinParams.gravity, mLayout.mPopupOffsetX,
|
|
||||||
mLayout.mPopupOffsetY);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dismissHint() {
|
|
||||||
if (mShowingHint != null) {
|
|
||||||
mShowingHint.dismiss();
|
|
||||||
mShowingHint = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
|
|||||||
/** Whether the IME is shown on display id. */
|
/** Whether the IME is shown on display id. */
|
||||||
private final Set<Integer> mDisplaysWithIme = new ArraySet<>(1);
|
private final Set<Integer> mDisplaysWithIme = new ArraySet<>(1);
|
||||||
|
|
||||||
/** The showing buttons by task id. */
|
/** The showing UIs by task id. */
|
||||||
private final SparseArray<SizeCompatUILayout> mActiveLayouts = new SparseArray<>(0);
|
private final SparseArray<SizeCompatUILayout> mActiveLayouts = new SparseArray<>(0);
|
||||||
|
|
||||||
/** Avoid creating display context frequently for non-default display. */
|
/** Avoid creating display context frequently for non-default display. */
|
||||||
@@ -77,12 +77,12 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the Task info changed. Creates and updates the restart button if there is an
|
* Called when the Task info changed. Creates and updates the size compat UI if there is an
|
||||||
* activity in size compat, or removes the restart button if there is no size compat activity.
|
* activity in size compat, or removes the UI if there is no size compat activity.
|
||||||
*
|
*
|
||||||
* @param displayId display the task and activity are in.
|
* @param displayId display the task and activity are in.
|
||||||
* @param taskId task the activity is in.
|
* @param taskId task the activity is in.
|
||||||
* @param taskConfig task config to place the restart button with.
|
* @param taskConfig task config to place the size compat UI with.
|
||||||
* @param sizeCompatActivity the size compat activity in the task. Can be {@code null} if the
|
* @param sizeCompatActivity the size compat activity in the task. Can be {@code null} if the
|
||||||
* top activity in this Task is not in size compat.
|
* top activity in this Task is not in size compat.
|
||||||
* @param taskListener listener to handle the Task Surface placement.
|
* @param taskListener listener to handle the Task Surface placement.
|
||||||
@@ -94,10 +94,10 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
|
|||||||
// Null token means the current foreground activity is not in size compatibility mode.
|
// Null token means the current foreground activity is not in size compatibility mode.
|
||||||
removeLayout(taskId);
|
removeLayout(taskId);
|
||||||
} else if (mActiveLayouts.contains(taskId)) {
|
} else if (mActiveLayouts.contains(taskId)) {
|
||||||
// Button already exists, update the button layout.
|
// UI already exists, update the UI layout.
|
||||||
updateLayout(taskId, taskConfig, sizeCompatActivity, taskListener);
|
updateLayout(taskId, taskConfig, sizeCompatActivity, taskListener);
|
||||||
} else {
|
} else {
|
||||||
// Create a new restart button.
|
// Create a new size compat UI.
|
||||||
createLayout(displayId, taskId, taskConfig, sizeCompatActivity, taskListener);
|
createLayout(displayId, taskId, taskConfig, sizeCompatActivity, taskListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
|
|||||||
public void onDisplayRemoved(int displayId) {
|
public void onDisplayRemoved(int displayId) {
|
||||||
mDisplayContextCache.remove(displayId);
|
mDisplayContextCache.remove(displayId);
|
||||||
|
|
||||||
// Remove all buttons on the removed display.
|
// Remove all size compat UIs on the removed display.
|
||||||
final List<Integer> toRemoveTaskIds = new ArrayList<>();
|
final List<Integer> toRemoveTaskIds = new ArrayList<>();
|
||||||
forAllLayoutsOnDisplay(displayId, layout -> toRemoveTaskIds.add(layout.getTaskId()));
|
forAllLayoutsOnDisplay(displayId, layout -> toRemoveTaskIds.add(layout.getTaskId()));
|
||||||
for (int i = toRemoveTaskIds.size() - 1; i >= 0; i--) {
|
for (int i = toRemoveTaskIds.size() - 1; i >= 0; i--) {
|
||||||
@@ -128,7 +128,7 @@ public class SizeCompatUIController implements DisplayController.OnDisplaysChang
|
|||||||
mDisplaysWithIme.remove(displayId);
|
mDisplaysWithIme.remove(displayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide the button when input method is showing.
|
// Hide the size compat UIs when input method is showing.
|
||||||
forAllLayoutsOnDisplay(displayId, layout -> layout.updateImeVisibility(isShowing));
|
forAllLayoutsOnDisplay(displayId, layout -> layout.updateImeVisibility(isShowing));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import android.graphics.PixelFormat;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.view.Gravity;
|
|
||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
@@ -43,7 +42,7 @@ import com.android.wm.shell.common.SyncTransactionQueue;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Records and handles layout of size compat UI on a task with size compat activity. Helps to
|
* Records and handles layout of size compat UI on a task with size compat activity. Helps to
|
||||||
* calculate proper bounds when configuration or button position changes.
|
* calculate proper bounds when configuration or UI position changes.
|
||||||
*/
|
*/
|
||||||
class SizeCompatUILayout {
|
class SizeCompatUILayout {
|
||||||
private static final String TAG = "SizeCompatUILayout";
|
private static final String TAG = "SizeCompatUILayout";
|
||||||
@@ -56,12 +55,18 @@ class SizeCompatUILayout {
|
|||||||
private IBinder mActivityToken;
|
private IBinder mActivityToken;
|
||||||
private ShellTaskOrganizer.TaskListener mTaskListener;
|
private ShellTaskOrganizer.TaskListener mTaskListener;
|
||||||
private DisplayLayout mDisplayLayout;
|
private DisplayLayout mDisplayLayout;
|
||||||
@VisibleForTesting
|
|
||||||
final SizeCompatUIWindowManager mWindowManager;
|
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
final SizeCompatUIWindowManager mButtonWindowManager;
|
||||||
|
@VisibleForTesting
|
||||||
|
@Nullable
|
||||||
|
SizeCompatUIWindowManager mHintWindowManager;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@Nullable
|
@Nullable
|
||||||
SizeCompatRestartButton mButton;
|
SizeCompatRestartButton mButton;
|
||||||
|
@VisibleForTesting
|
||||||
|
@Nullable
|
||||||
|
SizeCompatHintPopup mHint;
|
||||||
final int mButtonSize;
|
final int mButtonSize;
|
||||||
final int mPopupOffsetX;
|
final int mPopupOffsetX;
|
||||||
final int mPopupOffsetY;
|
final int mPopupOffsetY;
|
||||||
@@ -79,7 +84,7 @@ class SizeCompatUILayout {
|
|||||||
mTaskListener = taskListener;
|
mTaskListener = taskListener;
|
||||||
mDisplayLayout = displayLayout;
|
mDisplayLayout = displayLayout;
|
||||||
mShouldShowHint = !hasShownHint;
|
mShouldShowHint = !hasShownHint;
|
||||||
mWindowManager = new SizeCompatUIWindowManager(mContext, taskConfig, this);
|
mButtonWindowManager = new SizeCompatUIWindowManager(mContext, taskConfig, this);
|
||||||
|
|
||||||
mButtonSize =
|
mButtonSize =
|
||||||
mContext.getResources().getDimensionPixelSize(R.dimen.size_compat_button_size);
|
mContext.getResources().getDimensionPixelSize(R.dimen.size_compat_button_size);
|
||||||
@@ -87,21 +92,52 @@ class SizeCompatUILayout {
|
|||||||
mPopupOffsetY = mButtonSize;
|
mPopupOffsetY = mButtonSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates the button window. */
|
/** Creates the activity restart button window. */
|
||||||
void createSizeCompatButton(boolean isImeShowing) {
|
void createSizeCompatButton(boolean isImeShowing) {
|
||||||
if (isImeShowing || mButton != null) {
|
if (isImeShowing || mButton != null) {
|
||||||
// When ime is showing, wait until ime is dismiss to create UI.
|
// When ime is showing, wait until ime is dismiss to create UI.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mButton = mWindowManager.createSizeCompatUI();
|
mButton = mButtonWindowManager.createSizeCompatButton();
|
||||||
updateSurfacePosition();
|
updateButtonSurfacePosition();
|
||||||
|
|
||||||
|
if (mShouldShowHint) {
|
||||||
|
// Only show by default for the first time.
|
||||||
|
mShouldShowHint = false;
|
||||||
|
createSizeCompatHint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Releases the button window. */
|
/** Creates the restart button hint window. */
|
||||||
|
private void createSizeCompatHint() {
|
||||||
|
if (mHint != null) {
|
||||||
|
// Hint already shown.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mHintWindowManager = createHintWindowManager();
|
||||||
|
mHint = mHintWindowManager.createSizeCompatHint();
|
||||||
|
updateHintSurfacePosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
SizeCompatUIWindowManager createHintWindowManager() {
|
||||||
|
return new SizeCompatUIWindowManager(mContext, mTaskConfig, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dismisses the hint window. */
|
||||||
|
void dismissHint() {
|
||||||
|
mHint = null;
|
||||||
|
if (mHintWindowManager != null) {
|
||||||
|
mHintWindowManager.release();
|
||||||
|
mHintWindowManager = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Releases the UI windows. */
|
||||||
void release() {
|
void release() {
|
||||||
mButton.remove();
|
dismissHint();
|
||||||
mButton = null;
|
mButton = null;
|
||||||
mWindowManager.release();
|
mButtonWindowManager.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when size compat info changed. */
|
/** Called when size compat info changed. */
|
||||||
@@ -115,7 +151,10 @@ class SizeCompatUILayout {
|
|||||||
|
|
||||||
// Update configuration.
|
// Update configuration.
|
||||||
mContext = mContext.createConfigurationContext(taskConfig);
|
mContext = mContext.createConfigurationContext(taskConfig);
|
||||||
mWindowManager.setConfiguration(taskConfig);
|
mButtonWindowManager.setConfiguration(taskConfig);
|
||||||
|
if (mHintWindowManager != null) {
|
||||||
|
mHintWindowManager.setConfiguration(taskConfig);
|
||||||
|
}
|
||||||
|
|
||||||
if (mButton == null || prevTaskListener != taskListener) {
|
if (mButton == null || prevTaskListener != taskListener) {
|
||||||
// TaskListener changed, recreate the button for new surface parent.
|
// TaskListener changed, recreate the button for new surface parent.
|
||||||
@@ -126,14 +165,19 @@ class SizeCompatUILayout {
|
|||||||
|
|
||||||
if (!taskConfig.windowConfiguration.getBounds()
|
if (!taskConfig.windowConfiguration.getBounds()
|
||||||
.equals(prevTaskConfig.windowConfiguration.getBounds())) {
|
.equals(prevTaskConfig.windowConfiguration.getBounds())) {
|
||||||
// Reposition the button surface.
|
// Reposition the UI surfaces.
|
||||||
updateSurfacePosition();
|
updateButtonSurfacePosition();
|
||||||
|
updateHintSurfacePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) {
|
if (taskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection()) {
|
||||||
// Update layout for RTL.
|
// Update layout for RTL.
|
||||||
mButton.setLayoutDirection(taskConfig.getLayoutDirection());
|
mButton.setLayoutDirection(taskConfig.getLayoutDirection());
|
||||||
updateSurfacePosition();
|
updateButtonSurfacePosition();
|
||||||
|
if (mHint != null) {
|
||||||
|
mHint.setLayoutDirection(taskConfig.getLayoutDirection());
|
||||||
|
updateHintSurfacePosition();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,8 +193,9 @@ class SizeCompatUILayout {
|
|||||||
displayLayout.getStableBounds(curStableBounds);
|
displayLayout.getStableBounds(curStableBounds);
|
||||||
mDisplayLayout = displayLayout;
|
mDisplayLayout = displayLayout;
|
||||||
if (!prevStableBounds.equals(curStableBounds)) {
|
if (!prevStableBounds.equals(curStableBounds)) {
|
||||||
// Stable bounds changed, update button surface position.
|
// Stable bounds changed, update UI surface positions.
|
||||||
updateSurfacePosition();
|
updateButtonSurfacePosition();
|
||||||
|
updateHintSurfacePosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,27 +207,46 @@ class SizeCompatUILayout {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Hide size compat UIs when IME is showing.
|
||||||
final int newVisibility = isImeShowing ? View.GONE : View.VISIBLE;
|
final int newVisibility = isImeShowing ? View.GONE : View.VISIBLE;
|
||||||
if (mButton.getVisibility() != newVisibility) {
|
if (mButton.getVisibility() != newVisibility) {
|
||||||
mButton.setVisibility(newVisibility);
|
mButton.setVisibility(newVisibility);
|
||||||
}
|
}
|
||||||
|
if (mHint != null && mHint.getVisibility() != newVisibility) {
|
||||||
|
mHint.setVisibility(newVisibility);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the layout params for restart button. */
|
/** Gets the layout params for restart button. */
|
||||||
WindowManager.LayoutParams getWindowLayoutParams() {
|
WindowManager.LayoutParams getButtonWindowLayoutParams() {
|
||||||
final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
|
final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
|
||||||
|
// Cannot be wrap_content as this determines the actual window size
|
||||||
mButtonSize, mButtonSize,
|
mButtonSize, mButtonSize,
|
||||||
TYPE_APPLICATION_OVERLAY,
|
TYPE_APPLICATION_OVERLAY,
|
||||||
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
|
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
|
||||||
PixelFormat.TRANSLUCENT);
|
PixelFormat.TRANSLUCENT);
|
||||||
winParams.gravity = getGravity(getLayoutDirection());
|
|
||||||
winParams.token = new Binder();
|
winParams.token = new Binder();
|
||||||
winParams.setTitle(SizeCompatRestartButton.class.getSimpleName() + mContext.getDisplayId());
|
winParams.setTitle(SizeCompatRestartButton.class.getSimpleName() + getTaskId());
|
||||||
winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
|
winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||||
return winParams;
|
return winParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when it is ready to be placed button surface button. */
|
/** Gets the layout params for hint popup. */
|
||||||
|
WindowManager.LayoutParams getHintWindowLayoutParams(SizeCompatHintPopup hint) {
|
||||||
|
final WindowManager.LayoutParams winParams = new WindowManager.LayoutParams(
|
||||||
|
// Cannot be wrap_content as this determines the actual window size
|
||||||
|
hint.getMeasuredWidth(), hint.getMeasuredHeight(),
|
||||||
|
TYPE_APPLICATION_OVERLAY,
|
||||||
|
FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL,
|
||||||
|
PixelFormat.TRANSLUCENT);
|
||||||
|
winParams.token = new Binder();
|
||||||
|
winParams.setTitle(SizeCompatHintPopup.class.getSimpleName() + getTaskId());
|
||||||
|
winParams.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
|
||||||
|
winParams.windowAnimations = android.R.style.Animation_InputMethod;
|
||||||
|
return winParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Called when it is ready to be placed size compat UI surface. */
|
||||||
void attachToParentSurface(SurfaceControl.Builder b) {
|
void attachToParentSurface(SurfaceControl.Builder b) {
|
||||||
mTaskListener.attachChildSurfaceToTask(mTaskId, b);
|
mTaskListener.attachChildSurfaceToTask(mTaskId, b);
|
||||||
}
|
}
|
||||||
@@ -192,13 +256,17 @@ class SizeCompatUILayout {
|
|||||||
ActivityClient.getInstance().restartActivityProcessIfVisible(mActivityToken);
|
ActivityClient.getInstance().restartActivityProcessIfVisible(mActivityToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Called when the restart button is long clicked. */
|
||||||
|
void onRestartButtonLongClicked() {
|
||||||
|
createSizeCompatHint();
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void updateSurfacePosition() {
|
void updateButtonSurfacePosition() {
|
||||||
if (mButton == null || mWindowManager.getSurfaceControl() == null) {
|
if (mButton == null || mButtonWindowManager.getSurfaceControl() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The hint popup won't be at the correct position.
|
final SurfaceControl leash = mButtonWindowManager.getSurfaceControl();
|
||||||
mButton.dismissHint();
|
|
||||||
|
|
||||||
// Use stable bounds to prevent the button from overlapping with system bars.
|
// Use stable bounds to prevent the button from overlapping with system bars.
|
||||||
final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
|
final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
|
||||||
@@ -212,8 +280,30 @@ class SizeCompatUILayout {
|
|||||||
: stableBounds.right - taskBounds.left - mButtonSize;
|
: stableBounds.right - taskBounds.left - mButtonSize;
|
||||||
final int positionY = stableBounds.bottom - taskBounds.top - mButtonSize;
|
final int positionY = stableBounds.bottom - taskBounds.top - mButtonSize;
|
||||||
|
|
||||||
mSyncQueue.runInSync(t ->
|
mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY));
|
||||||
t.setPosition(mWindowManager.getSurfaceControl(), positionX, positionY));
|
}
|
||||||
|
|
||||||
|
void updateHintSurfacePosition() {
|
||||||
|
if (mHint == null || mHintWindowManager == null
|
||||||
|
|| mHintWindowManager.getSurfaceControl() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final SurfaceControl leash = mHintWindowManager.getSurfaceControl();
|
||||||
|
|
||||||
|
// Use stable bounds to prevent the hint from overlapping with system bars.
|
||||||
|
final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
|
||||||
|
final Rect stableBounds = new Rect();
|
||||||
|
mDisplayLayout.getStableBounds(stableBounds);
|
||||||
|
stableBounds.intersect(taskBounds);
|
||||||
|
|
||||||
|
// Position of the hint in the container coordinate.
|
||||||
|
final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
|
||||||
|
? stableBounds.left - taskBounds.left + mPopupOffsetX
|
||||||
|
: stableBounds.right - taskBounds.left - mPopupOffsetX - mHint.getMeasuredWidth();
|
||||||
|
final int positionY =
|
||||||
|
stableBounds.bottom - taskBounds.top - mPopupOffsetY - mHint.getMeasuredHeight();
|
||||||
|
|
||||||
|
mSyncQueue.runInSync(t -> t.setPosition(leash, positionX, positionY));
|
||||||
}
|
}
|
||||||
|
|
||||||
int getDisplayId() {
|
int getDisplayId() {
|
||||||
@@ -227,9 +317,4 @@ class SizeCompatUILayout {
|
|||||||
private int getLayoutDirection() {
|
private int getLayoutDirection() {
|
||||||
return mContext.getResources().getConfiguration().getLayoutDirection();
|
return mContext.getResources().getConfiguration().getLayoutDirection();
|
||||||
}
|
}
|
||||||
|
|
||||||
static int getGravity(int layoutDirection) {
|
|
||||||
return Gravity.BOTTOM
|
|
||||||
| (layoutDirection == View.LAYOUT_DIRECTION_RTL ? Gravity.START : Gravity.END);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,14 @@ import android.view.LayoutInflater;
|
|||||||
import android.view.SurfaceControl;
|
import android.view.SurfaceControl;
|
||||||
import android.view.SurfaceControlViewHost;
|
import android.view.SurfaceControlViewHost;
|
||||||
import android.view.SurfaceSession;
|
import android.view.SurfaceSession;
|
||||||
|
import android.view.View;
|
||||||
import android.view.WindowlessWindowManager;
|
import android.view.WindowlessWindowManager;
|
||||||
|
|
||||||
import com.android.wm.shell.R;
|
import com.android.wm.shell.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds view hierarchy of a root surface and helps to inflate {@link SizeCompatRestartButton}.
|
* Holds view hierarchy of a root surface and helps to inflate {@link SizeCompatRestartButton} or
|
||||||
|
* {@link SizeCompatHintPopup}.
|
||||||
*/
|
*/
|
||||||
class SizeCompatUIWindowManager extends WindowlessWindowManager {
|
class SizeCompatUIWindowManager extends WindowlessWindowManager {
|
||||||
|
|
||||||
@@ -67,18 +69,39 @@ class SizeCompatUIWindowManager extends WindowlessWindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Inflates {@link SizeCompatRestartButton} on to the root surface. */
|
/** Inflates {@link SizeCompatRestartButton} on to the root surface. */
|
||||||
SizeCompatRestartButton createSizeCompatUI() {
|
SizeCompatRestartButton createSizeCompatButton() {
|
||||||
if (mViewHost == null) {
|
if (mViewHost != null) {
|
||||||
mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
|
throw new IllegalStateException(
|
||||||
|
"A UI has already been created with this window manager.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
|
||||||
|
|
||||||
final SizeCompatRestartButton button = (SizeCompatRestartButton)
|
final SizeCompatRestartButton button = (SizeCompatRestartButton)
|
||||||
LayoutInflater.from(mContext).inflate(R.layout.size_compat_ui, null);
|
LayoutInflater.from(mContext).inflate(R.layout.size_compat_ui, null);
|
||||||
button.inject(mLayout);
|
button.inject(mLayout);
|
||||||
mViewHost.setView(button, mLayout.getWindowLayoutParams());
|
mViewHost.setView(button, mLayout.getButtonWindowLayoutParams());
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Inflates {@link SizeCompatHintPopup} on to the root surface. */
|
||||||
|
SizeCompatHintPopup createSizeCompatHint() {
|
||||||
|
if (mViewHost != null) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"A UI has already been created with this window manager.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mViewHost = new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);
|
||||||
|
|
||||||
|
final SizeCompatHintPopup hint = (SizeCompatHintPopup)
|
||||||
|
LayoutInflater.from(mContext).inflate(R.layout.size_compat_mode_hint, null);
|
||||||
|
// Measure how big the hint is.
|
||||||
|
hint.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
|
||||||
|
hint.inject(mLayout);
|
||||||
|
mViewHost.setView(hint, mLayout.getHintWindowLayoutParams(hint));
|
||||||
|
return hint;
|
||||||
|
}
|
||||||
|
|
||||||
/** Releases the surface control and tears down the view hierarchy. */
|
/** Releases the surface control and tears down the view hierarchy. */
|
||||||
void release() {
|
void release() {
|
||||||
if (mViewHost != null) {
|
if (mViewHost != null) {
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2021 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.wm.shell.sizecompatui;
|
||||||
|
|
||||||
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.testing.AndroidTestingRunner;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.widget.Button;
|
||||||
|
|
||||||
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
|
import com.android.wm.shell.R;
|
||||||
|
import com.android.wm.shell.ShellTaskOrganizer;
|
||||||
|
import com.android.wm.shell.ShellTestCase;
|
||||||
|
import com.android.wm.shell.common.DisplayLayout;
|
||||||
|
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link SizeCompatHintPopup}.
|
||||||
|
*
|
||||||
|
* Build/Install/Run:
|
||||||
|
* atest WMShellUnitTests:SizeCompatHintPopupTest
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidTestingRunner.class)
|
||||||
|
@SmallTest
|
||||||
|
public class SizeCompatHintPopupTest extends ShellTestCase {
|
||||||
|
|
||||||
|
@Mock private SyncTransactionQueue mSyncTransactionQueue;
|
||||||
|
@Mock private IBinder mActivityToken;
|
||||||
|
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
|
||||||
|
@Mock private DisplayLayout mDisplayLayout;
|
||||||
|
|
||||||
|
private SizeCompatUILayout mLayout;
|
||||||
|
private SizeCompatHintPopup mHint;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
|
final int taskId = 1;
|
||||||
|
mLayout = new SizeCompatUILayout(mSyncTransactionQueue, mContext, new Configuration(),
|
||||||
|
taskId, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/);
|
||||||
|
mHint = (SizeCompatHintPopup)
|
||||||
|
LayoutInflater.from(mContext).inflate(R.layout.size_compat_mode_hint, null);
|
||||||
|
mHint.inject(mLayout);
|
||||||
|
|
||||||
|
spyOn(mLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnClick() {
|
||||||
|
doNothing().when(mLayout).dismissHint();
|
||||||
|
|
||||||
|
final Button button = mHint.findViewById(R.id.got_it);
|
||||||
|
button.performClick();
|
||||||
|
|
||||||
|
verify(mLayout).dismissHint();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,13 +19,13 @@ package com.android.wm.shell.sizecompatui;
|
|||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||||
|
|
||||||
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.doNothing;
|
||||||
import static org.mockito.Mockito.never;
|
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.testing.AndroidTestingRunner;
|
import android.testing.AndroidTestingRunner;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
|
|
||||||
@@ -71,45 +71,25 @@ public class SizeCompatRestartButtonTest extends ShellTestCase {
|
|||||||
mButton.inject(mLayout);
|
mButton.inject(mLayout);
|
||||||
|
|
||||||
spyOn(mLayout);
|
spyOn(mLayout);
|
||||||
spyOn(mButton);
|
|
||||||
doNothing().when(mButton).showHint();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnClick() {
|
public void testOnClick() {
|
||||||
doNothing().when(mLayout).onRestartButtonClicked();
|
doNothing().when(mLayout).onRestartButtonClicked();
|
||||||
|
|
||||||
mButton.onClick(mButton);
|
final ImageButton button = mButton.findViewById(R.id.size_compat_restart_button);
|
||||||
|
button.performClick();
|
||||||
|
|
||||||
verify(mLayout).onRestartButtonClicked();
|
verify(mLayout).onRestartButtonClicked();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnLongClick() {
|
public void testOnLongClick() {
|
||||||
verify(mButton, never()).showHint();
|
doNothing().when(mLayout).onRestartButtonLongClicked();
|
||||||
|
|
||||||
mButton.onLongClick(mButton);
|
final ImageButton button = mButton.findViewById(R.id.size_compat_restart_button);
|
||||||
|
button.performLongClick();
|
||||||
|
|
||||||
verify(mButton).showHint();
|
verify(mLayout).onRestartButtonLongClicked();
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testOnAttachedToWindow_showHint() {
|
|
||||||
mLayout.mShouldShowHint = false;
|
|
||||||
mButton.onAttachedToWindow();
|
|
||||||
|
|
||||||
verify(mButton, never()).showHint();
|
|
||||||
|
|
||||||
mLayout.mShouldShowHint = true;
|
|
||||||
mButton.onAttachedToWindow();
|
|
||||||
|
|
||||||
verify(mButton).showHint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRemove() {
|
|
||||||
mButton.remove();
|
|
||||||
|
|
||||||
verify(mButton).dismissHint();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.wm.shell.sizecompatui;
|
|||||||
|
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -27,6 +28,7 @@ import static org.mockito.Mockito.doNothing;
|
|||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
import android.app.ActivityClient;
|
import android.app.ActivityClient;
|
||||||
@@ -68,6 +70,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
|
|||||||
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
|
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
|
||||||
@Mock private DisplayLayout mDisplayLayout;
|
@Mock private DisplayLayout mDisplayLayout;
|
||||||
@Mock private SizeCompatRestartButton mButton;
|
@Mock private SizeCompatRestartButton mButton;
|
||||||
|
@Mock private SizeCompatHintPopup mHint;
|
||||||
private Configuration mTaskConfig;
|
private Configuration mTaskConfig;
|
||||||
|
|
||||||
private SizeCompatUILayout mLayout;
|
private SizeCompatUILayout mLayout;
|
||||||
@@ -81,8 +84,13 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
|
|||||||
TASK_ID, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/);
|
TASK_ID, mActivityToken, mTaskListener, mDisplayLayout, false /* hasShownHint*/);
|
||||||
|
|
||||||
spyOn(mLayout);
|
spyOn(mLayout);
|
||||||
spyOn(mLayout.mWindowManager);
|
spyOn(mLayout.mButtonWindowManager);
|
||||||
doReturn(mButton).when(mLayout.mWindowManager).createSizeCompatUI();
|
doReturn(mButton).when(mLayout.mButtonWindowManager).createSizeCompatButton();
|
||||||
|
|
||||||
|
final SizeCompatUIWindowManager hintWindowManager = mLayout.createHintWindowManager();
|
||||||
|
spyOn(hintWindowManager);
|
||||||
|
doReturn(mHint).when(hintWindowManager).createSizeCompatHint();
|
||||||
|
doReturn(hintWindowManager).when(mLayout).createHintWindowManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -90,24 +98,45 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
|
|||||||
// Not create button if IME is showing.
|
// Not create button if IME is showing.
|
||||||
mLayout.createSizeCompatButton(true /* isImeShowing */);
|
mLayout.createSizeCompatButton(true /* isImeShowing */);
|
||||||
|
|
||||||
verify(mLayout.mWindowManager, never()).createSizeCompatUI();
|
verify(mLayout.mButtonWindowManager, never()).createSizeCompatButton();
|
||||||
assertNull(mLayout.mButton);
|
assertNull(mLayout.mButton);
|
||||||
|
assertNull(mLayout.mHintWindowManager);
|
||||||
|
assertNull(mLayout.mHint);
|
||||||
|
|
||||||
|
// Not create hint popup.
|
||||||
|
mLayout.mShouldShowHint = false;
|
||||||
mLayout.createSizeCompatButton(false /* isImeShowing */);
|
mLayout.createSizeCompatButton(false /* isImeShowing */);
|
||||||
|
|
||||||
verify(mLayout.mWindowManager).createSizeCompatUI();
|
verify(mLayout.mButtonWindowManager).createSizeCompatButton();
|
||||||
assertNotNull(mLayout.mButton);
|
assertNotNull(mLayout.mButton);
|
||||||
|
assertNull(mLayout.mHintWindowManager);
|
||||||
|
assertNull(mLayout.mHint);
|
||||||
|
|
||||||
|
// Create hint popup.
|
||||||
|
mLayout.release();
|
||||||
|
mLayout.mShouldShowHint = true;
|
||||||
|
mLayout.createSizeCompatButton(false /* isImeShowing */);
|
||||||
|
|
||||||
|
verify(mLayout.mButtonWindowManager, times(2)).createSizeCompatButton();
|
||||||
|
assertNotNull(mLayout.mButton);
|
||||||
|
assertNotNull(mLayout.mHintWindowManager);
|
||||||
|
verify(mLayout.mHintWindowManager).createSizeCompatHint();
|
||||||
|
assertNotNull(mLayout.mHint);
|
||||||
|
assertFalse(mLayout.mShouldShowHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRelease() {
|
public void testRelease() {
|
||||||
mLayout.createSizeCompatButton(false /* isImeShowing */);
|
mLayout.createSizeCompatButton(false /* isImeShowing */);
|
||||||
|
final SizeCompatUIWindowManager hintWindowManager = mLayout.mHintWindowManager;
|
||||||
|
|
||||||
mLayout.release();
|
mLayout.release();
|
||||||
|
|
||||||
assertNull(mLayout.mButton);
|
assertNull(mLayout.mButton);
|
||||||
verify(mButton).remove();
|
assertNull(mLayout.mHint);
|
||||||
verify(mLayout.mWindowManager).release();
|
verify(hintWindowManager).release();
|
||||||
|
assertNull(mLayout.mHintWindowManager);
|
||||||
|
verify(mLayout.mButtonWindowManager).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -119,7 +148,7 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
|
|||||||
mLayout.updateSizeCompatInfo(mTaskConfig, mActivityToken, mTaskListener,
|
mLayout.updateSizeCompatInfo(mTaskConfig, mActivityToken, mTaskListener,
|
||||||
false /* isImeShowing */);
|
false /* isImeShowing */);
|
||||||
|
|
||||||
verify(mLayout, never()).updateSurfacePosition();
|
verify(mLayout, never()).updateButtonSurfacePosition();
|
||||||
verify(mLayout, never()).release();
|
verify(mLayout, never()).release();
|
||||||
verify(mLayout, never()).createSizeCompatButton(anyBoolean());
|
verify(mLayout, never()).createSizeCompatButton(anyBoolean());
|
||||||
|
|
||||||
@@ -140,7 +169,8 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
|
|||||||
mLayout.updateSizeCompatInfo(newTaskConfiguration, mActivityToken, newTaskListener,
|
mLayout.updateSizeCompatInfo(newTaskConfiguration, mActivityToken, newTaskListener,
|
||||||
false /* isImeShowing */);
|
false /* isImeShowing */);
|
||||||
|
|
||||||
verify(mLayout).updateSurfacePosition();
|
verify(mLayout).updateButtonSurfacePosition();
|
||||||
|
verify(mLayout).updateHintSurfacePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -152,14 +182,16 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
|
|||||||
mContext.getResources(), false, false);
|
mContext.getResources(), false, false);
|
||||||
|
|
||||||
mLayout.updateDisplayLayout(displayLayout1);
|
mLayout.updateDisplayLayout(displayLayout1);
|
||||||
verify(mLayout).updateSurfacePosition();
|
verify(mLayout).updateButtonSurfacePosition();
|
||||||
|
verify(mLayout).updateHintSurfacePosition();
|
||||||
|
|
||||||
// No update if the display bounds is the same.
|
// No update if the display bounds is the same.
|
||||||
clearInvocations(mLayout);
|
clearInvocations(mLayout);
|
||||||
final DisplayLayout displayLayout2 = new DisplayLayout(displayInfo,
|
final DisplayLayout displayLayout2 = new DisplayLayout(displayInfo,
|
||||||
mContext.getResources(), false, false);
|
mContext.getResources(), false, false);
|
||||||
mLayout.updateDisplayLayout(displayLayout2);
|
mLayout.updateDisplayLayout(displayLayout2);
|
||||||
verify(mLayout, never()).updateSurfacePosition();
|
verify(mLayout, never()).updateButtonSurfacePosition();
|
||||||
|
verify(mLayout, never()).updateHintSurfacePosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -203,4 +235,29 @@ public class SizeCompatUILayoutTest extends ShellTestCase {
|
|||||||
|
|
||||||
verify(ActivityClient.getInstance()).restartActivityProcessIfVisible(mActivityToken);
|
verify(ActivityClient.getInstance()).restartActivityProcessIfVisible(mActivityToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOnRestartButtonLongClicked_showHint() {
|
||||||
|
mLayout.dismissHint();
|
||||||
|
|
||||||
|
assertNull(mLayout.mHint);
|
||||||
|
|
||||||
|
mLayout.onRestartButtonLongClicked();
|
||||||
|
|
||||||
|
assertNotNull(mLayout.mHint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDismissHint() {
|
||||||
|
mLayout.onRestartButtonLongClicked();
|
||||||
|
final SizeCompatUIWindowManager hintWindowManager = mLayout.mHintWindowManager;
|
||||||
|
assertNotNull(mLayout.mHint);
|
||||||
|
assertNotNull(hintWindowManager);
|
||||||
|
|
||||||
|
mLayout.dismissHint();
|
||||||
|
|
||||||
|
assertNull(mLayout.mHint);
|
||||||
|
assertNull(mLayout.mHintWindowManager);
|
||||||
|
verify(hintWindowManager).release();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user