summaryrefslogtreecommitdiff
path: root/library/src/main/java/com/android/systemui
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/main/java/com/android/systemui')
-rw-r--r--library/src/main/java/com/android/systemui/qr/PageIndicator.java239
1 files changed, 239 insertions, 0 deletions
diff --git a/library/src/main/java/com/android/systemui/qr/PageIndicator.java b/library/src/main/java/com/android/systemui/qr/PageIndicator.java
new file mode 100644
index 0000000..0205e71
--- /dev/null
+++ b/library/src/main/java/com/android/systemui/qr/PageIndicator.java
@@ -0,0 +1,239 @@
+package com.android.systemui.qr;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.drawable.AnimatedVectorDrawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import java.util.ArrayList;
+
+import moe.yuuta.lib.pageindicator.BuildConfig;
+import moe.yuuta.lib.pageindicator.R;
+
+public class PageIndicator extends ViewGroup {
+
+ private static final String TAG = "PageIndicator";
+ // Note by Yuuta: [CHANGED] use BuildConfig instead of hardcoded value.
+ private static final boolean DEBUG = BuildConfig.DEBUG;
+
+ private static final long ANIMATION_DURATION = 250;
+
+ // The size of a single dot in relation to the whole animation.
+ private static final float SINGLE_SCALE = .4f;
+
+ private static final float MINOR_ALPHA = .42f;
+
+ private final ArrayList<Integer> mQueuedPositions = new ArrayList<>();
+
+ private final int mPageIndicatorWidth;
+ private final int mPageIndicatorHeight;
+ private final int mPageDotWidth;
+
+ private int mPosition = -1;
+ private boolean mAnimating;
+
+ public PageIndicator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mPageIndicatorWidth =
+ (int) getContext().getResources().getDimension(R.dimen.qs_page_indicator_width);
+ mPageIndicatorHeight =
+ (int) getContext().getResources().getDimension(R.dimen.qs_page_indicator_height);
+ mPageDotWidth = (int) (mPageIndicatorWidth * SINGLE_SCALE);
+ }
+
+ public void setNumPages(int numPages) {
+ setVisibility(numPages > 1 ? View.VISIBLE : View.GONE);
+ if (mAnimating) {
+ Log.w(TAG, "setNumPages during animation");
+ }
+ while (numPages < getChildCount()) {
+ removeViewAt(getChildCount() - 1);
+ }
+ TypedArray array = getContext().obtainStyledAttributes(
+ new int[]{android.R.attr.colorControlActivated});
+ int color = array.getColor(0, 0);
+ array.recycle();
+ while (numPages > getChildCount()) {
+ ImageView v = new ImageView(getContext());
+ v.setImageResource(R.drawable.minor_a_b);
+ v.setImageTintList(ColorStateList.valueOf(color));
+ addView(v, new LayoutParams(mPageIndicatorWidth, mPageIndicatorHeight));
+ }
+ // Refresh state.
+ setIndex(mPosition >> 1);
+ }
+
+ public void setLocation(float location) {
+ int index = (int) location;
+ setContentDescription(getContext().getString(R.string.accessibility_quick_settings_page,
+ (index + 1), getChildCount()));
+ int position = index << 1 | ((location != index) ? 1 : 0);
+ if (DEBUG) Log.d(TAG, "setLocation " + location + " " + index + " " + position);
+
+ int lastPosition = mPosition;
+ if (mQueuedPositions.size() != 0) {
+ lastPosition = mQueuedPositions.get(mQueuedPositions.size() - 1);
+ }
+ if (position == lastPosition) return;
+ if (mAnimating) {
+ if (DEBUG) Log.d(TAG, "Queueing transition to " + Integer.toHexString(position));
+ mQueuedPositions.add(position);
+ return;
+ }
+
+ setPosition(position);
+ }
+
+ /**
+ * Note by Yuuta: [CHANGED] isUserVisible() has been ignored because it's a hidden api.
+ */
+ private void setPosition(int position) {
+ if (Math.abs(mPosition - position) == 1) {
+ animate(mPosition, position);
+ } else {
+ if (DEBUG) Log.d(TAG, "Skipping animation " + mPosition
+ + " " + position);
+ setIndex(position >> 1);
+ }
+ mPosition = position;
+ }
+
+ private void setIndex(int index) {
+ final int N = getChildCount();
+ for (int i = 0; i < N; i++) {
+ ImageView v = (ImageView) getChildAt(i);
+ // Clear out any animation positioning.
+ v.setTranslationX(0);
+ v.setImageResource(R.drawable.major_a_b);
+ v.setAlpha(getAlpha(i == index));
+ }
+ }
+
+ private void animate(int from, int to) {
+ if (DEBUG) Log.d(TAG, "Animating from " + Integer.toHexString(from) + " to "
+ + Integer.toHexString(to));
+ int fromIndex = from >> 1;
+ int toIndex = to >> 1;
+
+ // Set the position of everything, then we will manually control the two views involved
+ // in the animation.
+ setIndex(fromIndex);
+
+ boolean fromTransition = (from & 1) != 0;
+ boolean isAState = fromTransition ? from > to : from < to;
+ int firstIndex = Math.min(fromIndex, toIndex);
+ int secondIndex = Math.max(fromIndex, toIndex);
+ if (secondIndex == firstIndex) {
+ secondIndex++;
+ }
+ ImageView first = (ImageView) getChildAt(firstIndex);
+ ImageView second = (ImageView) getChildAt(secondIndex);
+ if (first == null || second == null) {
+ // may happen during reInflation or other weird cases
+ return;
+ }
+ // Lay the two views on top of each other.
+ second.setTranslationX(first.getX() - second.getX());
+
+ playAnimation(first, getTransition(fromTransition, isAState, false));
+ first.setAlpha(getAlpha(false));
+
+ playAnimation(second, getTransition(fromTransition, isAState, true));
+ second.setAlpha(getAlpha(true));
+
+ mAnimating = true;
+ }
+
+ private float getAlpha(boolean isMajor) {
+ return isMajor ? 1 : MINOR_ALPHA;
+ }
+
+ private void playAnimation(ImageView imageView, int res) {
+ final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) getContext().getDrawable(res);
+ imageView.setImageDrawable(avd);
+ // Note by Yuuta: [CHANGED] forceAnimationOnUI() has been ignored because it's a hidden api.
+ // avd.forceAnimationOnUI();
+ avd.start();
+ // TODO: Figure out how to user an AVD animation callback instead, which doesn't
+ // seem to be working right now...
+ postDelayed(mAnimationDone, ANIMATION_DURATION);
+ }
+
+ private int getTransition(boolean fromB, boolean isMajorAState, boolean isMajor) {
+ if (isMajor) {
+ if (fromB) {
+ if (isMajorAState) {
+ return R.drawable.major_b_a_animation;
+ } else {
+ return R.drawable.major_b_c_animation;
+ }
+ } else {
+ if (isMajorAState) {
+ return R.drawable.major_a_b_animation;
+ } else {
+ return R.drawable.major_c_b_animation;
+ }
+ }
+ } else {
+ if (fromB) {
+ if (isMajorAState) {
+ return R.drawable.minor_b_c_animation;
+ } else {
+ return R.drawable.minor_b_a_animation;
+ }
+ } else {
+ if (isMajorAState) {
+ return R.drawable.minor_c_b_animation;
+ } else {
+ return R.drawable.minor_a_b_animation;
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int N = getChildCount();
+ if (N == 0) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ return;
+ }
+ final int widthChildSpec = MeasureSpec.makeMeasureSpec(mPageIndicatorWidth,
+ MeasureSpec.EXACTLY);
+ final int heightChildSpec = MeasureSpec.makeMeasureSpec(mPageIndicatorHeight,
+ MeasureSpec.EXACTLY);
+ for (int i = 0; i < N; i++) {
+ getChildAt(i).measure(widthChildSpec, heightChildSpec);
+ }
+ int width = (mPageIndicatorWidth - mPageDotWidth) * (N - 1) + mPageDotWidth;
+ setMeasuredDimension(width, mPageIndicatorHeight);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ final int N = getChildCount();
+ if (N == 0) {
+ return;
+ }
+ for (int i = 0; i < N; i++) {
+ int left = (mPageIndicatorWidth - mPageDotWidth) * i;
+ getChildAt(i).layout(left, 0, mPageIndicatorWidth + left, mPageIndicatorHeight);
+ }
+ }
+
+ private final Runnable mAnimationDone = new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) Log.d(TAG, "onAnimationEnd - queued: " + mQueuedPositions.size());
+ mAnimating = false;
+ if (mQueuedPositions.size() != 0) {
+ setPosition(mQueuedPositions.remove(0));
+ }
+ }
+ };
+}