Merge "[13/n] Letterbox Education: change dialog width and handle oveflow cases."

This commit is contained in:
Tom Natan
2022-02-14 17:54:59 +00:00
committed by Android (Google) Code Review
7 changed files with 174 additions and 118 deletions

View File

@@ -22,81 +22,101 @@
<!-- The background of the top-level layout acts as the background dim. -->
<!-- Setting the alpha of the dialog container to 0, since it shouldn't be visible until the
<!-- Vertical margin will be set dynamically since it depends on task bounds.
Setting the alpha of the dialog container to 0, since it shouldn't be visible until the
enter animation starts. -->
<LinearLayout
<FrameLayout
android:id="@+id/letterbox_education_dialog_container"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal"
android:orientation="vertical"
android:layout_marginHorizontal="@dimen/letterbox_education_dialog_margin"
android:background="@drawable/letterbox_education_dialog_background"
android:padding="24dp"
android:alpha="0">
android:alpha="0"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintWidth_max="@dimen/letterbox_education_dialog_width"
app:layout_constrainedHeight="true">
<ImageView
android:id="@+id/letterbox_education_icon"
android:layout_width="@dimen/letterbox_education_dialog_icon_size"
android:layout_height="@dimen/letterbox_education_dialog_icon_size"
android:layout_marginBottom="12dp"
android:src="@drawable/letterbox_education_ic_letterboxed_app"/>
<TextView
android:id="@+id/letterbox_education_dialog_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="@dimen/letterbox_education_dialog_title_max_width"
android:lineSpacingExtra="4sp"
android:text="@string/letterbox_education_dialog_title"
android:textAlignment="center"
android:textColor="@color/compat_controls_text"
android:textSize="24sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:maxWidth="@dimen/letterbox_education_dialog_title_max_width"
android:lineSpacingExtra="4sp"
android:text="@string/letterbox_education_dialog_subtext"
android:textAlignment="center"
android:textColor="@color/letterbox_education_text_secondary"
android:textSize="14sp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top"
android:orientation="horizontal"
android:paddingTop="48dp">
<com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/letterbox_education_ic_screen_rotation"
app:text="@string/letterbox_education_screen_rotation_text"/>
<com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/letterbox_education_dialog_space_between_actions"
app:icon="@drawable/letterbox_education_ic_reposition"
app:text="@string/letterbox_education_reposition_text"/>
</LinearLayout>
<Button
android:id="@+id/letterbox_education_dialog_dismiss_button"
<!-- The ScrollView should only wrap the content of the dialog, otherwise the background
corner radius will be cut off when scrolling to the top/bottom. -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="48dp"
android:background="@drawable/letterbox_education_dismiss_button_background_ripple"
android:text="@string/letterbox_education_got_it"
android:textColor="@android:color/system_neutral1_900"
android:textAlignment="center"
android:contentDescription="@string/letterbox_education_got_it"/>
android:layout_height="wrap_content">
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:orientation="vertical"
android:padding="24dp">
<ImageView
android:layout_width="@dimen/letterbox_education_dialog_icon_size"
android:layout_height="@dimen/letterbox_education_dialog_icon_size"
android:layout_marginBottom="12dp"
android:src="@drawable/letterbox_education_ic_letterboxed_app"/>
<TextView
android:id="@+id/letterbox_education_dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:lineSpacingExtra="4sp"
android:text="@string/letterbox_education_dialog_title"
android:textAlignment="center"
android:textColor="@color/compat_controls_text"
android:textSize="24sp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:lineSpacingExtra="4sp"
android:text="@string/letterbox_education_dialog_subtext"
android:textAlignment="center"
android:textColor="@color/letterbox_education_text_secondary"
android:textSize="14sp"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="top"
android:orientation="horizontal"
android:paddingTop="48dp">
<com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:icon="@drawable/letterbox_education_ic_screen_rotation"
app:text="@string/letterbox_education_screen_rotation_text"/>
<com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogActionLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart=
"@dimen/letterbox_education_dialog_space_between_actions"
app:icon="@drawable/letterbox_education_ic_reposition"
app:text="@string/letterbox_education_reposition_text"/>
</LinearLayout>
<Button
android:id="@+id/letterbox_education_dialog_dismiss_button"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="48dp"
android:background=
"@drawable/letterbox_education_dismiss_button_background_ripple"
android:text="@string/letterbox_education_got_it"
android:textColor="@android:color/system_neutral1_900"
android:textAlignment="center"
android:contentDescription="@string/letterbox_education_got_it"/>
</LinearLayout>
</ScrollView>
</FrameLayout>
</com.android.wm.shell.compatui.letterboxedu.LetterboxEduDialogLayout>

View File

@@ -225,15 +225,18 @@
<!-- The size of an icon in the letterbox education dialog. -->
<dimen name="letterbox_education_dialog_icon_size">48dp</dimen>
<!-- The fixed width of the dialog if there is enough space in the parent. -->
<dimen name="letterbox_education_dialog_width">472dp</dimen>
<!-- The margin between the dialog container and its parent. -->
<dimen name="letterbox_education_dialog_margin">16dp</dimen>
<!-- The width of each action container in the letterbox education dialog -->
<dimen name="letterbox_education_dialog_action_width">140dp</dimen>
<!-- The space between two actions in the letterbox education dialog -->
<dimen name="letterbox_education_dialog_space_between_actions">24dp</dimen>
<!-- The maximum width of the title and subtitle in the letterbox education dialog. -->
<dimen name="letterbox_education_dialog_title_max_width">444dp</dimen>
<!-- The width of the brand image on staring surface. -->
<dimen name="starting_surface_brand_image_width">200dp</dimen>

View File

@@ -189,15 +189,18 @@ class CompatUIWindowManager extends CompatUIWindowManagerAbstract {
}
@Override
protected void updateSurfacePosition(Rect taskBounds, Rect stableBounds) {
@VisibleForTesting
public void updateSurfacePosition() {
if (mLayout == null) {
return;
}
// Position of the button in the container coordinate.
final Rect taskBounds = getTaskBounds();
final Rect taskStableBounds = getTaskStableBounds();
final int positionX = getLayoutDirection() == View.LAYOUT_DIRECTION_RTL
? stableBounds.left - taskBounds.left
: stableBounds.right - taskBounds.left - mLayout.getMeasuredWidth();
final int positionY = stableBounds.bottom - taskBounds.top
? taskStableBounds.left - taskBounds.left
: taskStableBounds.right - taskBounds.left - mLayout.getMeasuredWidth();
final int positionY = taskStableBounds.bottom - taskBounds.top
- mLayout.getMeasuredHeight();
updateSurfacePosition(positionX, positionY);

View File

@@ -51,15 +51,15 @@ import com.android.wm.shell.common.SyncTransactionQueue;
*/
public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowManager {
protected final SyncTransactionQueue mSyncQueue;
protected final int mDisplayId;
protected final int mTaskId;
protected Context mContext;
protected Configuration mTaskConfig;
protected ShellTaskOrganizer.TaskListener mTaskListener;
protected DisplayLayout mDisplayLayout;
protected final Rect mStableBounds;
private final SyncTransactionQueue mSyncQueue;
private final int mDisplayId;
private Configuration mTaskConfig;
private ShellTaskOrganizer.TaskListener mTaskListener;
private DisplayLayout mDisplayLayout;
private final Rect mStableBounds;
/**
* Utility class for adding and releasing a View hierarchy for this {@link
@@ -211,7 +211,7 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana
boolean layoutDirectionUpdated =
mTaskConfig.getLayoutDirection() != prevTaskConfig.getLayoutDirection();
if (boundsUpdated || layoutDirectionUpdated) {
updateSurface();
onParentBoundsChanged();
}
if (layout != null && layoutDirectionUpdated) {
@@ -248,8 +248,9 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana
displayLayout.getStableBounds(curStableBounds);
mDisplayLayout = displayLayout;
if (!prevStableBounds.equals(curStableBounds)) {
updateSurface();
// mStableBounds should be updated before we call onParentBoundsChanged.
mStableBounds.set(curStableBounds);
onParentBoundsChanged();
}
}
@@ -289,51 +290,39 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana
}
/** Re-layouts the view host and updates the surface position. */
public void relayout() {
void relayout() {
relayout(getWindowLayoutParams());
}
protected void relayout(WindowManager.LayoutParams windowLayoutParams) {
if (mViewHost == null) {
return;
}
mViewHost.relayout(getWindowLayoutParams());
mViewHost.relayout(windowLayoutParams);
updateSurfacePosition();
}
/**
* Updates the surface following a change in the task bounds, display layout stable bounds,
* or the layout direction.
* Called following a change in the task bounds, display layout stable bounds, or the layout
* direction.
*/
protected void updateSurface() {
protected void onParentBoundsChanged() {
updateSurfacePosition();
}
/**
* Updates the position of the surface with respect to the task bounds and display layout
* stable bounds.
* Updates the position of the surface with respect to the parent bounds.
*/
@VisibleForTesting
void updateSurfacePosition() {
if (mLeash == null) {
return;
}
// Use stable bounds to prevent controls from overlapping with system bars.
final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
final Rect stableBounds = new Rect();
mDisplayLayout.getStableBounds(stableBounds);
stableBounds.intersect(taskBounds);
updateSurfacePosition(taskBounds, stableBounds);
}
/**
* Updates the position of the surface with respect to the given {@code taskBounds} and {@code
* stableBounds}.
*/
protected abstract void updateSurfacePosition(Rect taskBounds, Rect stableBounds);
protected abstract void updateSurfacePosition();
/**
* Updates the position of the surface with respect to the given {@code positionX} and {@code
* positionY}.
*/
protected void updateSurfacePosition(int positionX, int positionY) {
if (mLeash == null) {
return;
}
mSyncQueue.runInSync(t -> {
if (mLeash == null || !mLeash.isValid()) {
Log.w(getTag(), "The leash has been released.");
@@ -347,6 +336,17 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana
return mContext.getResources().getConfiguration().getLayoutDirection();
}
protected Rect getTaskBounds() {
return mTaskConfig.windowConfiguration.getBounds();
}
/** Returns the intersection between the task bounds and the display layout stable bounds. */
protected Rect getTaskStableBounds() {
final Rect result = new Rect(mStableBounds);
result.intersect(getTaskBounds());
return result;
}
@VisibleForTesting
SurfaceControlViewHost createSurfaceViewHost() {
return new SurfaceControlViewHost(mContext, mContext.getDisplay(), this);

View File

@@ -43,6 +43,8 @@ import com.android.internal.policy.TransitionAnimation;
class LetterboxEduAnimationController {
private static final String TAG = "LetterboxEduAnimation";
private static final int ENTER_ANIM_START_DELAY_MILLIS = 500;
private final TransitionAnimation mTransitionAnimation;
private final String mPackageName;
@AnyRes
@@ -87,6 +89,9 @@ class LetterboxEduAnimationController {
mDialogAnimation.getDuration());
mBackgroundDimAnimator.addListener(getDimAnimatorListener());
mDialogAnimation.setStartOffset(ENTER_ANIM_START_DELAY_MILLIS);
mBackgroundDimAnimator.setStartDelay(ENTER_ANIM_START_DELAY_MILLIS);
dialogContainer.startAnimation(mDialogAnimation);
mBackgroundDimAnimator.start();
}

View File

@@ -20,7 +20,8 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.wm.shell.R;
@@ -31,7 +32,7 @@ import com.android.wm.shell.R;
* background dim which dismisses the dialog when clicked.
*/
// TODO(b/215316431): Add tests
class LetterboxEduDialogLayout extends FrameLayout {
class LetterboxEduDialogLayout extends ConstraintLayout {
// The alpha of a background is a number between 0 (fully transparent) to 255 (fully opaque).
// 204 is simply 255 * 0.8.

View File

@@ -26,6 +26,7 @@ import android.graphics.Rect;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.WindowManager;
import com.android.wm.shell.R;
@@ -109,6 +110,7 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
protected View createLayout() {
setSeenLetterboxEducation();
mLayout = inflateLayout();
updateDialogMargins();
mAnimationController.startEnterAnimation(mLayout, /* endCallback= */
this::setDismissOnClickListener);
@@ -116,6 +118,22 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
return mLayout;
}
private void updateDialogMargins() {
if (mLayout == null) {
return;
}
final View dialogContainer = mLayout.getDialogContainer();
MarginLayoutParams marginParams = (MarginLayoutParams) dialogContainer.getLayoutParams();
int verticalMargin = (int) mContext.getResources().getDimension(
R.dimen.letterbox_education_dialog_margin);
final Rect taskBounds = getTaskBounds();
final Rect taskStableBounds = getTaskStableBounds();
marginParams.topMargin = taskStableBounds.top - taskBounds.top + verticalMargin;
marginParams.bottomMargin = taskBounds.bottom - taskStableBounds.bottom + verticalMargin;
dialogContainer.setLayoutParams(marginParams);
}
private LetterboxEduDialogLayout inflateLayout() {
return (LetterboxEduDialogLayout) LayoutInflater.from(mContext).inflate(
R.layout.letterbox_education_dialog_layout, null);
@@ -150,20 +168,26 @@ public class LetterboxEduWindowManager extends CompatUIWindowManagerAbstract {
}
@Override
protected void updateSurface() {
// We need to relayout because the layout dimensions depend on the task bounds.
relayout();
protected void onParentBoundsChanged() {
if (mLayout == null) {
return;
}
// Both the layout dimensions and dialog margins depend on the parent bounds.
WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
mLayout.setLayoutParams(windowLayoutParams);
updateDialogMargins();
relayout(windowLayoutParams);
}
@Override
protected void updateSurfacePosition(Rect taskBounds, Rect stableBounds) {
protected void updateSurfacePosition() {
// Nothing to do, since the position of the surface is fixed to the top left corner (0,0)
// of the task (parent surface), which is the default position of a surface.
}
@Override
protected WindowManager.LayoutParams getWindowLayoutParams() {
final Rect taskBounds = mTaskConfig.windowConfiguration.getBounds();
final Rect taskBounds = getTaskBounds();
return getWindowLayoutParams(/* width= */ taskBounds.width(), /* height= */
taskBounds.height());
}