mirror of
https://github.com/LawnchairLauncher/lawnchair.git
synced 2026-02-20 11:18:21 +00:00
This could be caused by landscape layout not receiving inset changes Adding logs for hotseat layout info as well Bug: 335141365 Flag: EXEMPT bugfix Test: N/A Change-Id: I987f8622907a10fac5375ddddac3db2c5eba41c1
302 lines
11 KiB
Java
302 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2011 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.launcher3;
|
|
|
|
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
|
|
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_BUBBLE_ADJUSTMENT_ANIM;
|
|
|
|
import android.animation.AnimatorSet;
|
|
import android.animation.ObjectAnimator;
|
|
import android.animation.ValueAnimator;
|
|
import android.content.Context;
|
|
import android.graphics.Rect;
|
|
import android.util.AttributeSet;
|
|
import android.view.Gravity;
|
|
import android.view.LayoutInflater;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.view.ViewDebug;
|
|
import android.view.ViewGroup;
|
|
import android.widget.FrameLayout;
|
|
|
|
import com.android.launcher3.util.HorizontalInsettableView;
|
|
import com.android.launcher3.util.MultiTranslateDelegate;
|
|
import com.android.launcher3.views.ActivityContext;
|
|
|
|
/**
|
|
* View class that represents the bottom row of the home screen.
|
|
*/
|
|
public class Hotseat extends CellLayout implements Insettable {
|
|
|
|
// Ratio of empty space, qsb should take up to appear visually centered.
|
|
public static final float QSB_CENTER_FACTOR = .325f;
|
|
private static final int BUBBLE_BAR_ADJUSTMENT_ANIMATION_DURATION_MS = 250;
|
|
|
|
@ViewDebug.ExportedProperty(category = "launcher")
|
|
private boolean mHasVerticalHotseat;
|
|
private Workspace<?> mWorkspace;
|
|
private boolean mSendTouchToWorkspace;
|
|
|
|
private final View mQsb;
|
|
|
|
public Hotseat(Context context) {
|
|
this(context, null);
|
|
}
|
|
|
|
public Hotseat(Context context, AttributeSet attrs) {
|
|
this(context, attrs, 0);
|
|
}
|
|
|
|
public Hotseat(Context context, AttributeSet attrs, int defStyle) {
|
|
super(context, attrs, defStyle);
|
|
|
|
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
|
|
addView(mQsb);
|
|
}
|
|
|
|
/**
|
|
* Returns orientation specific cell X given invariant order in the hotseat
|
|
*/
|
|
public int getCellXFromOrder(int rank) {
|
|
return mHasVerticalHotseat ? 0 : rank;
|
|
}
|
|
|
|
/**
|
|
* Returns orientation specific cell Y given invariant order in the hotseat
|
|
*/
|
|
public int getCellYFromOrder(int rank) {
|
|
return mHasVerticalHotseat ? (getCountY() - (rank + 1)) : 0;
|
|
}
|
|
|
|
boolean isHasVerticalHotseat() {
|
|
return mHasVerticalHotseat;
|
|
}
|
|
|
|
public void resetLayout(boolean hasVerticalHotseat) {
|
|
ActivityContext activityContext = ActivityContext.lookupContext(getContext());
|
|
boolean bubbleBarEnabled = activityContext.isBubbleBarEnabled();
|
|
boolean hasBubbles = activityContext.hasBubbles();
|
|
removeAllViewsInLayout();
|
|
mHasVerticalHotseat = hasVerticalHotseat;
|
|
DeviceProfile dp = mActivity.getDeviceProfile();
|
|
|
|
if (bubbleBarEnabled) {
|
|
float adjustedBorderSpace = dp.getHotseatAdjustedBorderSpaceForBubbleBar(getContext());
|
|
if (hasBubbles && Float.compare(adjustedBorderSpace, 0f) != 0) {
|
|
getShortcutsAndWidgets().setTranslationProvider(child -> {
|
|
int index = getShortcutsAndWidgets().indexOfChild(child);
|
|
float borderSpaceDelta = adjustedBorderSpace - dp.hotseatBorderSpace;
|
|
return dp.iconSizePx + index * borderSpaceDelta;
|
|
});
|
|
if (mQsb instanceof HorizontalInsettableView) {
|
|
HorizontalInsettableView insettableQsb = (HorizontalInsettableView) mQsb;
|
|
final float insetFraction = (float) dp.iconSizePx / dp.hotseatQsbWidth;
|
|
// post this to the looper so that QSB has a chance to redraw itself, e.g.
|
|
// after device rotation
|
|
mQsb.post(() -> insettableQsb.setHorizontalInsets(insetFraction));
|
|
}
|
|
} else {
|
|
getShortcutsAndWidgets().setTranslationProvider(null);
|
|
if (mQsb instanceof HorizontalInsettableView) {
|
|
((HorizontalInsettableView) mQsb).setHorizontalInsets(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
resetCellSize(dp);
|
|
if (hasVerticalHotseat) {
|
|
setGridSize(1, dp.numShownHotseatIcons);
|
|
} else {
|
|
setGridSize(dp.numShownHotseatIcons, 1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Adjust the hotseat icons for the bubble bar.
|
|
*
|
|
* <p>When the bubble bar becomes visible, if needed, this method animates the hotseat icons
|
|
* to reduce the spacing between them and make room for the bubble bar. The QSB width is
|
|
* animated as well to align with the hotseat icons.
|
|
*
|
|
* <p>When the bubble bar goes away, any adjustments that were previously made are reversed.
|
|
*/
|
|
public void adjustForBubbleBar(boolean isBubbleBarVisible) {
|
|
DeviceProfile dp = mActivity.getDeviceProfile();
|
|
float adjustedBorderSpace = dp.getHotseatAdjustedBorderSpaceForBubbleBar(getContext());
|
|
if (Float.compare(adjustedBorderSpace, 0f) == 0) {
|
|
return;
|
|
}
|
|
|
|
ShortcutAndWidgetContainer icons = getShortcutsAndWidgets();
|
|
AnimatorSet animatorSet = new AnimatorSet();
|
|
float borderSpaceDelta = adjustedBorderSpace - dp.hotseatBorderSpace;
|
|
|
|
// update the translation provider for future layout passes of hotseat icons.
|
|
if (isBubbleBarVisible) {
|
|
icons.setTranslationProvider(child -> {
|
|
int index = icons.indexOfChild(child);
|
|
return dp.iconSizePx + index * borderSpaceDelta;
|
|
});
|
|
} else {
|
|
icons.setTranslationProvider(null);
|
|
}
|
|
|
|
for (int i = 0; i < icons.getChildCount(); i++) {
|
|
View child = icons.getChildAt(i);
|
|
float tx = isBubbleBarVisible ? dp.iconSizePx + i * borderSpaceDelta : 0;
|
|
if (child instanceof Reorderable) {
|
|
MultiTranslateDelegate mtd = ((Reorderable) child).getTranslateDelegate();
|
|
animatorSet.play(
|
|
mtd.getTranslationX(INDEX_BUBBLE_ADJUSTMENT_ANIM).animateToValue(tx));
|
|
} else {
|
|
animatorSet.play(ObjectAnimator.ofFloat(child, VIEW_TRANSLATE_X, tx));
|
|
}
|
|
}
|
|
if (mQsb instanceof HorizontalInsettableView) {
|
|
HorizontalInsettableView horizontalInsettableQsb = (HorizontalInsettableView) mQsb;
|
|
ValueAnimator qsbAnimator = ValueAnimator.ofFloat(0f, 1f);
|
|
qsbAnimator.addUpdateListener(animation -> {
|
|
float fraction = qsbAnimator.getAnimatedFraction();
|
|
float insetFraction = isBubbleBarVisible
|
|
? (float) dp.iconSizePx * fraction / dp.hotseatQsbWidth
|
|
: (float) dp.iconSizePx * (1 - fraction) / dp.hotseatQsbWidth;
|
|
horizontalInsettableQsb.setHorizontalInsets(insetFraction);
|
|
});
|
|
animatorSet.play(qsbAnimator);
|
|
}
|
|
animatorSet.setDuration(BUBBLE_BAR_ADJUSTMENT_ANIMATION_DURATION_MS).start();
|
|
}
|
|
|
|
@Override
|
|
public void setInsets(Rect insets) {
|
|
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
|
|
DeviceProfile grid = mActivity.getDeviceProfile();
|
|
|
|
if (grid.isVerticalBarLayout()) {
|
|
mQsb.setVisibility(View.GONE);
|
|
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
if (grid.isSeascape()) {
|
|
lp.gravity = Gravity.LEFT;
|
|
lp.width = grid.hotseatBarSizePx + insets.left;
|
|
} else {
|
|
lp.gravity = Gravity.RIGHT;
|
|
lp.width = grid.hotseatBarSizePx + insets.right;
|
|
}
|
|
} else {
|
|
mQsb.setVisibility(View.VISIBLE);
|
|
lp.gravity = Gravity.BOTTOM;
|
|
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
|
lp.height = grid.hotseatBarSizePx;
|
|
}
|
|
|
|
Rect padding = grid.getHotseatLayoutPadding(getContext());
|
|
setPadding(padding.left, padding.top, padding.right, padding.bottom);
|
|
setLayoutParams(lp);
|
|
InsettableFrameLayout.dispatchInsets(this, insets);
|
|
}
|
|
|
|
public void setWorkspace(Workspace<?> w) {
|
|
mWorkspace = w;
|
|
setCellLayoutContainer(w);
|
|
}
|
|
|
|
@Override
|
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
|
// We allow horizontal workspace scrolling from within the Hotseat. We do this by delegating
|
|
// touch intercept the Workspace, and if it intercepts, delegating touch to the Workspace
|
|
// for the remainder of the this input stream.
|
|
int yThreshold = getMeasuredHeight() - getPaddingBottom();
|
|
if (mWorkspace != null && ev.getY() <= yThreshold) {
|
|
mSendTouchToWorkspace = mWorkspace.onInterceptTouchEvent(ev);
|
|
return mSendTouchToWorkspace;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public boolean onTouchEvent(MotionEvent event) {
|
|
// See comment in #onInterceptTouchEvent
|
|
if (mSendTouchToWorkspace) {
|
|
final int action = event.getAction();
|
|
switch (action & MotionEvent.ACTION_MASK) {
|
|
case MotionEvent.ACTION_UP:
|
|
case MotionEvent.ACTION_CANCEL:
|
|
mSendTouchToWorkspace = false;
|
|
}
|
|
return mWorkspace.onTouchEvent(event);
|
|
}
|
|
// Always let touch follow through to Workspace.
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
|
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
|
|
|
DeviceProfile dp = mActivity.getDeviceProfile();
|
|
mQsb.measure(MeasureSpec.makeMeasureSpec(dp.hotseatQsbWidth, MeasureSpec.EXACTLY),
|
|
MeasureSpec.makeMeasureSpec(dp.hotseatQsbHeight, MeasureSpec.EXACTLY));
|
|
}
|
|
|
|
@Override
|
|
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
|
super.onLayout(changed, l, t, r, b);
|
|
|
|
int qsbMeasuredWidth = mQsb.getMeasuredWidth();
|
|
int left;
|
|
DeviceProfile dp = mActivity.getDeviceProfile();
|
|
if (dp.isQsbInline) {
|
|
int qsbSpace = dp.hotseatBorderSpace;
|
|
left = Utilities.isRtl(getResources()) ? r - getPaddingRight() + qsbSpace
|
|
: l + getPaddingLeft() - qsbMeasuredWidth - qsbSpace;
|
|
} else {
|
|
left = (r - l - qsbMeasuredWidth) / 2;
|
|
}
|
|
int right = left + qsbMeasuredWidth;
|
|
|
|
int bottom = b - t - dp.getQsbOffsetY();
|
|
int top = bottom - dp.hotseatQsbHeight;
|
|
mQsb.layout(left, top, right, bottom);
|
|
}
|
|
|
|
/**
|
|
* Sets the alpha value of just our ShortcutAndWidgetContainer.
|
|
*/
|
|
public void setIconsAlpha(float alpha) {
|
|
getShortcutsAndWidgets().setAlpha(alpha);
|
|
}
|
|
|
|
/**
|
|
* Sets the alpha value of just our QSB.
|
|
*/
|
|
public void setQsbAlpha(float alpha) {
|
|
mQsb.setAlpha(alpha);
|
|
}
|
|
|
|
public float getIconsAlpha() {
|
|
return getShortcutsAndWidgets().getAlpha();
|
|
}
|
|
|
|
/**
|
|
* Returns the QSB inside hotseat
|
|
*/
|
|
public View getQsb() {
|
|
return mQsb;
|
|
}
|
|
|
|
}
|