blob: 82175b721df061a470341e2f8dc3d42254c5aaa0 [file] [log] [blame]
/*
* Copyright (C) 2015 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 android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.FrameLayout;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.TransformingTouchDelegate;
/**
* A base container view, which supports resizing.
*/
public abstract class BaseContainerView extends FrameLayout
implements DeviceProfile.LauncherLayoutChangeListener {
private static final Rect sBgPaddingRect = new Rect();
protected final Drawable mBaseDrawable;
private View mRevealView;
private View mContent;
private TransformingTouchDelegate mTouchDelegate;
private final PointF mLastTouchDownPosPx = new PointF(-1.0f, -1.0f);
public BaseContainerView(Context context) {
this(context, null);
}
public BaseContainerView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (this instanceof AllAppsContainerView) {
mBaseDrawable = new ColorDrawable();
} else {
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BaseContainerView, defStyleAttr, 0);
mBaseDrawable = a.getDrawable(R.styleable.BaseContainerView_revealBackground);
a.recycle();
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
grid.addLauncherLayoutChangedListener(this);
View touchDelegateTargetView = getTouchDelegateTargetView();
if (touchDelegateTargetView != null) {
mTouchDelegate = new TransformingTouchDelegate(touchDelegateTargetView);
((View) touchDelegateTargetView.getParent()).setTouchDelegate(mTouchDelegate);
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
grid.removeLauncherLayoutChangedListener(this);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mContent = findViewById(R.id.main_content);
mRevealView = findViewById(R.id.reveal_view);
updatePaddings();
}
@Override
public void onLauncherLayoutChanged() {
updatePaddings();
}
/**
* Calculate the background padding as it can change due to insets/content padding change.
*/
private void updatePaddings() {
DeviceProfile grid = Launcher.getLauncher(getContext()).getDeviceProfile();
int[] padding = grid.getContainerPadding();
int paddingLeft = padding[0];
int paddingRight = padding[1];
int paddingTop = 0;
int paddingBottom = 0;
if (!grid.isVerticalBarLayout()) {
paddingLeft += grid.edgeMarginPx;
paddingRight += grid.edgeMarginPx;
paddingTop = paddingBottom = grid.edgeMarginPx;
}
updateBackground(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
/**
* Update the background for the reveal view and content view based on the background padding.
*/
protected void updateBackground(int paddingLeft, int paddingTop,
int paddingRight, int paddingBottom) {
mRevealView.setBackground(new InsetDrawable(mBaseDrawable,
paddingLeft, paddingTop, paddingRight, paddingBottom));
mContent.setBackground(new InsetDrawable(mBaseDrawable,
paddingLeft, paddingTop, paddingRight, paddingBottom));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
View touchDelegateTargetView = getTouchDelegateTargetView();
if (touchDelegateTargetView != null) {
getRevealView().getBackground().getPadding(sBgPaddingRect);
mTouchDelegate.setBounds(
touchDelegateTargetView.getLeft() - sBgPaddingRect.left,
touchDelegateTargetView.getTop() - sBgPaddingRect.top,
touchDelegateTargetView.getRight() + sBgPaddingRect.right,
touchDelegateTargetView.getBottom() + sBgPaddingRect.bottom);
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return handleTouchEvent(ev);
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent ev) {
return handleTouchEvent(ev);
}
public void setRevealDrawableColor(int color) {
((ColorDrawable) mBaseDrawable).setColor(color);
}
public final View getContentView() {
return mContent;
}
public final View getRevealView() {
return mRevealView;
}
/**
* Handles the touch events that shows the workspace when clicking outside the bounds of the
* touch delegate target view.
*/
private boolean handleTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// Check if the touch is outside touch delegate target view
View touchDelegateTargetView = getTouchDelegateTargetView();
float leftBoundPx = touchDelegateTargetView.getLeft();
if (ev.getX() < leftBoundPx ||
ev.getX() > (touchDelegateTargetView.getWidth() + leftBoundPx)) {
mLastTouchDownPosPx.set((int) ev.getX(), (int) ev.getY());
}
break;
case MotionEvent.ACTION_UP:
if (mLastTouchDownPosPx.x > -1) {
ViewConfiguration viewConfig = ViewConfiguration.get(getContext());
float dx = ev.getX() - mLastTouchDownPosPx.x;
float dy = ev.getY() - mLastTouchDownPosPx.y;
float distance = PointF.length(dx, dy);
if (distance < viewConfig.getScaledTouchSlop()) {
// The background was clicked, so just go home
Launcher.getLauncher(getContext()).showWorkspace(true);
return true;
}
}
// Fall through
case MotionEvent.ACTION_CANCEL:
mLastTouchDownPosPx.set(-1, -1);
break;
}
return false;
}
public abstract View getTouchDelegateTargetView();
}