summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher3/keyboard
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2016-05-09 20:43:21 -0700
committerSunny Goyal <sunnygoyal@google.com>2016-06-08 15:00:09 -0700
commit3333b0ced8e6743c41909f6f6b916f1f9ec5a004 (patch)
tree7fd735821e3393a0dfe8691087f58ebbaa9dafae /src/com/android/launcher3/keyboard
parentab06999a70c773ffbc0aadaf938e0e90f8ca09b2 (diff)
downloadandroid_packages_apps_Trebuchet-3333b0ced8e6743c41909f6f6b916f1f9ec5a004.tar.gz
android_packages_apps_Trebuchet-3333b0ced8e6743c41909f6f6b916f1f9ec5a004.tar.bz2
android_packages_apps_Trebuchet-3333b0ced8e6743c41909f6f6b916f1f9ec5a004.zip
Unifying focus indicator handling for workspace and all-apps
Adding an abstract FocusIndicatorHelper based on FocusIndicatorView which draws the background instead of using a dummy view. Change-Id: Id560195323d2ddad8fcd77ba675cf3f4fd4a94ab
Diffstat (limited to 'src/com/android/launcher3/keyboard')
-rw-r--r--src/com/android/launcher3/keyboard/FocusIndicatorHelper.java242
-rw-r--r--src/com/android/launcher3/keyboard/FocusedItemDecorator.java52
-rw-r--r--src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java85
3 files changed, 379 insertions, 0 deletions
diff --git a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
new file mode 100644
index 000000000..7672f5a79
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2016 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.keyboard;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.animation.RectEvaluator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.TargetApi;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Build.VERSION_CODES;
+import android.util.Property;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+import com.android.launcher3.R;
+
+/**
+ * A helper class to draw background of a focused view.
+ */
+@TargetApi(VERSION_CODES.LOLLIPOP)
+public abstract class FocusIndicatorHelper implements
+ OnFocusChangeListener, AnimatorUpdateListener {
+
+ private static final float MIN_VISIBLE_ALPHA = 0.2f;
+ private static final long ANIM_DURATION = 150;
+
+ public static final Property<FocusIndicatorHelper, Float> ALPHA =
+ new Property<FocusIndicatorHelper, Float>(Float.TYPE, "alpha") {
+ @Override
+ public void set(FocusIndicatorHelper object, Float value) {
+ object.setAlpha(value);
+ }
+
+ @Override
+ public Float get(FocusIndicatorHelper object) {
+ return object.mAlpha;
+ }
+ };
+
+ public static final Property<FocusIndicatorHelper, Float> SHIFT =
+ new Property<FocusIndicatorHelper, Float>(
+ Float.TYPE, "shift") {
+
+ @Override
+ public void set(FocusIndicatorHelper object, Float value) {
+ object.mShift = value;
+ }
+
+ @Override
+ public Float get(FocusIndicatorHelper object) {
+ return object.mShift;
+ }
+ };
+
+ private static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
+ private static final Rect sTempRect1 = new Rect();
+ private static final Rect sTempRect2 = new Rect();
+
+ private final View mContainer;
+ private final Paint mPaint;
+ private final int mMaxAlpha;
+
+ private final Rect mDirtyRect = new Rect();
+ private boolean mIsDirty = false;
+
+ private View mLastFocusedView;
+
+ private View mCurrentView;
+ private View mTargetView;
+ /**
+ * The fraction indicating the position of the focusRect between {@link #mCurrentView}
+ * & {@link #mTargetView}
+ */
+ private float mShift;
+
+ private ObjectAnimator mCurrentAnimation;
+ private float mAlpha;
+
+ public FocusIndicatorHelper(View container) {
+ mContainer = container;
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ int color = container.getResources().getColor(R.color.focused_background);
+ mMaxAlpha = Color.alpha(color);
+ mPaint.setColor(0xFF000000 | color);
+
+ setAlpha(0);
+ mShift = 0;
+ }
+
+ protected void setAlpha(float alpha) {
+ mAlpha = alpha;
+ mPaint.setAlpha((int) (mAlpha * mMaxAlpha));
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ invalidateDirty();
+ }
+
+ protected void invalidateDirty() {
+ if (mIsDirty) {
+ mContainer.invalidate(mDirtyRect);
+ mIsDirty = false;
+ }
+
+ Rect newRect = getDrawRect();
+ if (newRect != null) {
+ mContainer.invalidate(newRect);
+ }
+ }
+
+ public void draw(Canvas c) {
+ if (mAlpha > 0) {
+ Rect newRect = getDrawRect();
+ if (newRect != null) {
+ mDirtyRect.set(newRect);
+ c.drawRect(mDirtyRect, mPaint);
+ mIsDirty = true;
+ }
+ }
+ }
+
+ private Rect getDrawRect() {
+ if (mCurrentView != null) {
+ viewToRect(mCurrentView, sTempRect1);
+
+ if (mShift > 0 && mTargetView != null) {
+ viewToRect(mTargetView, sTempRect2);
+ return RECT_EVALUATOR.evaluate(mShift, sTempRect1, sTempRect2);
+ } else {
+ return sTempRect1;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ endCurrentAnimation();
+
+ if (mAlpha > MIN_VISIBLE_ALPHA) {
+ mTargetView = v;
+
+ mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(ALPHA, 1),
+ PropertyValuesHolder.ofFloat(SHIFT, 1));
+ mCurrentAnimation.addListener(new ViewSetListener(v, true));
+ } else {
+ setCurrentView(v);
+
+ mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(ALPHA, 1));
+ }
+
+ mLastFocusedView = v;
+ } else {
+ if (mLastFocusedView == v) {
+ mLastFocusedView = null;
+ endCurrentAnimation();
+ mCurrentAnimation = ObjectAnimator.ofPropertyValuesHolder(this,
+ PropertyValuesHolder.ofFloat(ALPHA, 0));
+ mCurrentAnimation.addListener(new ViewSetListener(null, false));
+ }
+ }
+
+ // invalidate once
+ invalidateDirty();
+
+ mLastFocusedView = hasFocus ? v : null;
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.addUpdateListener(this);
+ mCurrentAnimation.setDuration(ANIM_DURATION).start();
+ }
+ }
+
+ protected void endCurrentAnimation() {
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.cancel();
+ mCurrentAnimation = null;
+ }
+ }
+
+ protected void setCurrentView(View v) {
+ mCurrentView = v;
+ mShift = 0;
+ mTargetView = null;
+ }
+
+ /**
+ * Gets the position of {@param v} relative to {@link #mContainer}.
+ */
+ public abstract void viewToRect(View v, Rect outRect);
+
+ private class ViewSetListener extends AnimatorListenerAdapter {
+ private final View mViewToSet;
+ private final boolean mCallOnCancel;
+ private boolean mCalled = false;
+
+ public ViewSetListener(View v, boolean callOnCancel) {
+ mViewToSet = v;
+ mCallOnCancel = callOnCancel;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (!mCallOnCancel) {
+ mCalled = true;
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCalled) {
+ setCurrentView(mViewToSet);
+ mCalled = true;
+ }
+ }
+ }
+}
diff --git a/src/com/android/launcher3/keyboard/FocusedItemDecorator.java b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
new file mode 100644
index 000000000..9c80b0f08
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/FocusedItemDecorator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 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.keyboard;
+
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.ItemDecoration;
+import android.support.v7.widget.RecyclerView.State;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+/**
+ * {@link ItemDecoration} for drawing and animating focused view background.
+ */
+public class FocusedItemDecorator extends ItemDecoration {
+
+ private FocusIndicatorHelper mHelper;
+
+ public FocusedItemDecorator(View container) {
+ mHelper = new FocusIndicatorHelper(container) {
+
+ @Override
+ public void viewToRect(View v, Rect outRect) {
+ outRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+ }
+ };
+ }
+
+ public OnFocusChangeListener getFocusListener() {
+ return mHelper;
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, State state) {
+ mHelper.draw(c);
+ }
+}
diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
new file mode 100644
index 000000000..bd5c06e5b
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2016 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.keyboard;
+
+import android.graphics.Rect;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+
+import com.android.launcher3.PagedView;
+
+/**
+ * {@link FocusIndicatorHelper} for a generic view group.
+ */
+public class ViewGroupFocusHelper extends FocusIndicatorHelper {
+
+ private final View mContainer;
+
+ public ViewGroupFocusHelper(View container) {
+ super(container);
+ mContainer = container;
+ }
+
+ @Override
+ public void viewToRect(View v, Rect outRect) {
+ outRect.left = 0;
+ outRect.top = 0;
+
+ computeLocationRelativeToContainer(v, outRect);
+
+ // If a view is scaled, its position will also shift accordingly. For optimization, only
+ // consider this for the last node.
+ outRect.left += (1 - v.getScaleX()) * v.getWidth() / 2;
+ outRect.top += (1 - v.getScaleY()) * v.getHeight() / 2;
+
+ outRect.right = outRect.left + (int) (v.getScaleX() * v.getWidth());
+ outRect.bottom = outRect.top + (int) (v.getScaleY() * v.getHeight());
+ }
+
+ private void computeLocationRelativeToContainer(View child, Rect outRect) {
+ View parent = (View) child.getParent();
+ outRect.left += child.getLeft();
+ outRect.top += child.getTop();
+
+ if (parent != mContainer) {
+ if (parent instanceof PagedView) {
+ PagedView page = (PagedView) parent;
+ outRect.left -= page.getScrollForPage(page.indexOfChild(child));
+ }
+
+ computeLocationRelativeToContainer(parent, outRect);
+ }
+ }
+
+ /**
+ * Sets the alpha of this FocusIndicatorHelper to 0 when a view with this listener
+ * receives focus.
+ */
+ public View.OnFocusChangeListener getHideIndicatorOnFocusListener() {
+ return new OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ endCurrentAnimation();
+ setCurrentView(null);
+ setAlpha(0);
+ invalidateDirty();
+ }
+ }
+ };
+ }
+}