blob: 59070287cc5cb322f391a8048065f7ff7414eed2 [file] [log] [blame]
/*
* Copyright (C) 2019 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.systemui.globalactions;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
/**
* Grid-based implementation of the button layout created by the global actions dialog.
*/
public class GlobalActionsColumnLayout extends GlobalActionsLayout {
private boolean mLastSnap;
public GlobalActionsColumnLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
post(() -> updateSnap());
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@VisibleForTesting
protected boolean shouldReverseListItems() {
int rotation = getCurrentRotation();
if (rotation == ROTATION_NONE) {
return false;
}
if (getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
return rotation == ROTATION_LANDSCAPE;
}
return rotation == ROTATION_SEASCAPE;
}
@Override
public void onUpdateList() {
super.onUpdateList();
updateChildOrdering();
}
private void updateChildOrdering() {
if (shouldReverseListItems()) {
getListView().bringToFront();
} else {
getSeparatedView().bringToFront();
}
}
/**
* Snap this layout to align with the power button.
*/
@VisibleForTesting
protected void snapToPowerButton() {
int offset = getPowerButtonOffsetDistance();
switch (getCurrentRotation()) {
case (ROTATION_LANDSCAPE):
setPadding(offset, 0, 0, 0);
setGravity(Gravity.LEFT | Gravity.TOP);
break;
case (ROTATION_SEASCAPE):
setPadding(0, 0, offset, 0);
setGravity(Gravity.RIGHT | Gravity.BOTTOM);
break;
default:
setPadding(0, offset, 0, 0);
setGravity(Gravity.TOP | Gravity.RIGHT);
break;
}
}
/**
* Detach this layout from snapping to the power button and instead center along that edge.
*/
@VisibleForTesting
protected void centerAlongEdge() {
switch (getCurrentRotation()) {
case (ROTATION_LANDSCAPE):
setPadding(0, 0, 0, 0);
setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP);
break;
case (ROTATION_SEASCAPE):
setPadding(0, 0, 0, 0);
setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM);
break;
default:
setPadding(0, 0, 0, 0);
setGravity(Gravity.CENTER_VERTICAL | Gravity.RIGHT);
break;
}
}
/**
* Determines the distance from the top of the screen to the power button.
*/
@VisibleForTesting
protected int getPowerButtonOffsetDistance() {
return Math.round(getContext().getResources().getDimension(
R.dimen.global_actions_top_padding));
}
/**
* Check whether there is enough extra space below the dialog such that we can offset the top
* of the dialog from the top of the phone to line it up with the power button, then either
* snap the dialog to the power button or center it along the edge with snapToPowerButton.
*/
@VisibleForTesting
protected boolean shouldSnapToPowerButton() {
int offsetSize = getPowerButtonOffsetDistance();
int dialogSize;
int screenSize;
View wrapper = getWrapper();
int rotation = getCurrentRotation();
if (rotation == ROTATION_NONE) {
dialogSize = wrapper.getMeasuredHeight();
screenSize = getMeasuredHeight();
} else {
dialogSize = wrapper.getMeasuredWidth();
screenSize = getMeasuredWidth();
}
return dialogSize + offsetSize < screenSize;
}
@VisibleForTesting
protected void updateSnap() {
boolean snap = shouldSnapToPowerButton();
if (snap != mLastSnap) {
if (snap) {
snapToPowerButton();
} else {
centerAlongEdge();
}
}
mLastSnap = snap;
}
@VisibleForTesting
protected float getGridItemSize() {
return getContext().getResources().getDimension(R.dimen.global_actions_grid_item_height);
}
@VisibleForTesting
protected float getAnimationDistance() {
return getGridItemSize() / 2;
}
@Override
public float getAnimationOffsetX() {
if (getCurrentRotation() == ROTATION_NONE) {
return getAnimationDistance();
}
return 0;
}
@Override
public float getAnimationOffsetY() {
switch (getCurrentRotation()) {
case ROTATION_LANDSCAPE:
return -getAnimationDistance();
case ROTATION_SEASCAPE:
return getAnimationDistance();
default: // Portrait
return 0;
}
}
}