Skip to content
This repository has been archived by the owner on Jul 22, 2024. It is now read-only.

Fixes #2524 Honeycomb button clipping #2601

Merged
merged 2 commits into from
Jan 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package org.mozilla.vrbrowser.ui.views;

import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;

import org.mozilla.vrbrowser.utils.ViewUtils;

import java.util.Deque;

public class ClippedEventDelegate implements View.OnHoverListener, View.OnTouchListener {

private View mView;
private Region mRegion;
private boolean mHovered;
private boolean mTouched;
private OnClickListener mClickListener;

public ClippedEventDelegate(@DrawableRes int res, @NonNull View view) {
mView = view;
mHovered = false;
mTouched = false;

view.getViewTreeObserver().addOnGlobalLayoutListener(
() -> {
Path path = createPathFromResource(res);
RectF bounds = new RectF();
path.computeBounds(bounds, true);

bounds = new RectF();
path.computeBounds(bounds, true);
mRegion = new Region();
mRegion.setPath(path, new Region((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom));
});
}

public void setOnClickListener(OnClickListener listener) {
mClickListener = listener;
}

private Path createPathFromResource(@DrawableRes int res) {
VectorShape shape = new VectorShape(mView.getContext(), res);
shape.onResize(mView.getWidth(), mView.getHeight());
Deque<VectorShape.Layer> layers = shape.getLayers();
VectorShape.Layer layer = layers.getFirst();

// TODO Handle state changes and update the Region based on the new current state shape

return layer.transformedPath;
}

@Override
public boolean onHover(View v, MotionEvent event) {
if(!mRegion.contains((int)event.getX(),(int) event.getY())) {
if (mHovered) {
mHovered = false;
event.setAction(MotionEvent.ACTION_HOVER_EXIT);
return v.onHoverEvent(event);
}

return true;

} else {
if (!mHovered) {
mHovered = true;
event.setAction(MotionEvent.ACTION_HOVER_ENTER);
}

return v.onHoverEvent(event);
}
}

@Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);

if(!mRegion.contains((int)event.getX(),(int) event.getY())) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (mTouched) {
v.requestFocus();
v.requestFocusFromTouch();
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
v.setPressed(false);
mTouched = false;
}

return true;

} else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
mTouched = true;
return true;

case MotionEvent.ACTION_UP:
if (mTouched && ViewUtils.isInsideView(v, (int)event.getRawX(), (int)event.getRawY())) {
v.requestFocus();
v.requestFocusFromTouch();
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
v.setPressed(false);
mTouched = false;
return true;

case MotionEvent.ACTION_MOVE:
return true;

case MotionEvent.ACTION_CANCEL:
v.setPressed(false);
mTouched = false;
return true;
}

return false;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import org.mozilla.vrbrowser.R;
import org.mozilla.vrbrowser.utils.DeviceType;
import org.mozilla.vrbrowser.utils.SystemUtils;
import org.mozilla.vrbrowser.utils.ViewUtils;

public class HoneycombButton extends LinearLayout {

Expand All @@ -33,6 +32,7 @@ public class HoneycombButton extends LinearLayout {
private String mSecondaryButtonText;
private Drawable mButtonIcon;
private boolean mButtonIconHover;
private VectorClippedEventDelegate mEventDelegate;

public HoneycombButton(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, R.style.honeycombButtonTheme);
Expand Down Expand Up @@ -109,41 +109,53 @@ private void initialize(Context aContext) {
mSecondaryText.setClickable(false);
}

setOnHoverListener((view, motionEvent) -> false);
mEventDelegate = new VectorClippedEventDelegate(R.drawable.settings_honeycomb_background, this);
setOnHoverListener(mEventDelegate);
setOnTouchListener(mEventDelegate);
}


@Override
public void setOnClickListener(@Nullable OnClickListener aListener) {
ViewUtils.setStickyClickListener(this, aListener);
mEventDelegate.setOnClickListener(aListener);
}

@Override
public void setOnHoverListener(final OnHoverListener l) {
super.setOnHoverListener((view, motionEvent) -> {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.asphalt, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
mText.setTextColor(getContext().getColor(R.color.asphalt));
mSecondaryText.setTextColor(getContext().getColor(R.color.asphalt));
public boolean onHoverEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_HOVER_ENTER:
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.asphalt, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
break;
case MotionEvent.ACTION_HOVER_EXIT:
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.fog, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
mText.setTextColor(getContext().getColor(R.color.fog));
mSecondaryText.setTextColor(getContext().getColor(R.color.fog));
mText.setTextColor(getContext().getColor(R.color.asphalt));
mSecondaryText.setTextColor(getContext().getColor(R.color.asphalt));
}
break;
case MotionEvent.ACTION_HOVER_EXIT:
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.fog, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
break;
}
mText.setTextColor(getContext().getColor(R.color.fog));
mSecondaryText.setTextColor(getContext().getColor(R.color.fog));
}
break;
}

return l.onHover(view, motionEvent);
});
if (mEventDelegate.isInside(event)) {
return super.onHoverEvent(event);

} else {
setHovered(false);
if (mIcon != null && mText != null) {
if (mButtonIconHover) {
mIcon.setColorFilter(new PorterDuffColorFilter(getResources().getColor(R.color.fog, getContext().getTheme()), PorterDuff.Mode.MULTIPLY));
}
mText.setTextColor(getContext().getColor(R.color.fog));
mSecondaryText.setTextColor(getContext().getColor(R.color.fog));
}
return false;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package org.mozilla.vrbrowser.ui.views;

import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewTreeObserver;

import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;

import org.mozilla.vrbrowser.utils.ViewUtils;

import java.util.Deque;

public class VectorClippedEventDelegate implements View.OnHoverListener, View.OnTouchListener {

private View mView;
private @DrawableRes int mRes;
private Region mRegion;
private boolean mHovered;
private boolean mTouched;
private OnClickListener mClickListener;

VectorClippedEventDelegate(@DrawableRes int res, @NonNull View view) {
mView = view;
mRes = res;
mHovered = false;
mTouched = false;

view.getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
}

private ViewTreeObserver.OnGlobalLayoutListener mLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Path path = createPathFromResource(mRes);
RectF bounds = new RectF();
path.computeBounds(bounds, true);

bounds = new RectF();
path.computeBounds(bounds, true);
mRegion = new Region();
mRegion.setPath(path, new Region((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom));

mView.getViewTreeObserver().removeOnGlobalLayoutListener(mLayoutListener);
}
};

public void setOnClickListener(OnClickListener listener) {
mClickListener = listener;
}

private Path createPathFromResource(@DrawableRes int res) {
VectorShape shape = new VectorShape(mView.getContext(), res);
shape.onResize(mView.getWidth(), mView.getHeight());
Deque<VectorShape.Layer> layers = shape.getLayers();
VectorShape.Layer layer = layers.getFirst();

// TODO Handle state changes and update the Region based on the new current state shape

return layer.transformedPath;
}

@Override
public boolean onHover(View v, MotionEvent event) {
if(!isInside(event)) {
if (mHovered) {
mHovered = false;
event.setAction(MotionEvent.ACTION_HOVER_EXIT);
return v.onHoverEvent(event);
}

return false;

} else {
if (!mHovered) {
mHovered = true;
event.setAction(MotionEvent.ACTION_HOVER_ENTER);
}

return v.onHoverEvent(event);
}
}

@Override
public boolean onTouch(View v, MotionEvent event) {
v.getParent().requestDisallowInterceptTouchEvent(true);

if(!isInside(event)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
if (mTouched) {
v.requestFocus();
v.requestFocusFromTouch();
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
v.setPressed(false);
mTouched = false;
}

return true;

} else {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
v.setPressed(true);
mTouched = true;
return true;

case MotionEvent.ACTION_UP:
if (mTouched && ViewUtils.isInsideView(v, (int)event.getRawX(), (int)event.getRawY())) {
v.requestFocus();
v.requestFocusFromTouch();
if (mClickListener != null) {
mClickListener.onClick(v);
}
}
v.setPressed(false);
mTouched = false;
return true;

case MotionEvent.ACTION_MOVE:
return true;

case MotionEvent.ACTION_CANCEL:
v.setPressed(false);
mTouched = false;
return true;
}

return false;
}
}

public boolean isInside(MotionEvent event) {
return mRegion.contains((int)event.getX(),(int) event.getY());
}

}
Loading