summaryrefslogtreecommitdiffstats
path: root/java/com/android/incallui/incall/impl/InCallPaginator.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/incallui/incall/impl/InCallPaginator.java')
-rw-r--r--java/com/android/incallui/incall/impl/InCallPaginator.java210
1 files changed, 210 insertions, 0 deletions
diff --git a/java/com/android/incallui/incall/impl/InCallPaginator.java b/java/com/android/incallui/incall/impl/InCallPaginator.java
new file mode 100644
index 000000000..8ebbd76a2
--- /dev/null
+++ b/java/com/android/incallui/incall/impl/InCallPaginator.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2017 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.incallui.incall.impl;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.support.annotation.VisibleForTesting;
+import android.support.v4.view.ViewPager;
+import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.util.AttributeSet;
+import android.view.View;
+import com.android.dialer.common.Assert;
+
+/**
+ * This is the view class for incall paginator visible when a user has EC data attached to their
+ * call. It contains animation methods when the swipe gesture is performed.
+ */
+public class InCallPaginator extends View implements OnPageChangeListener {
+
+ private int dotRadius;
+ private int dotsSeparation;
+
+ private Paint activeDotPaintPortrait;
+ private Paint inactiveDotPaintPortrait;
+
+ private Path inactiveDotPath;
+ private ValueAnimator transitionAnimator;
+ private boolean useModeSwitchTransition;
+
+ private float progress;
+ private boolean toFirstPage;
+ private boolean pageChanged;
+
+ public InCallPaginator(Context context) {
+ super(context);
+ init(context);
+ }
+
+ public InCallPaginator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context);
+ }
+
+ private void init(Context context) {
+ dotRadius = getResources().getDimensionPixelSize(R.dimen.paginator_dot_radius);
+ dotsSeparation = getResources().getDimensionPixelSize(R.dimen.paginator_dots_separation);
+
+ int activeDotColor = context.getColor(R.color.paginator_dot);
+ int inactiveDotColor = context.getColor(R.color.paginator_path);
+ activeDotPaintPortrait = new Paint(Paint.ANTI_ALIAS_FLAG);
+ activeDotPaintPortrait.setColor(activeDotColor);
+ inactiveDotPaintPortrait = new Paint(Paint.ANTI_ALIAS_FLAG);
+ inactiveDotPaintPortrait.setColor(inactiveDotColor);
+
+ inactiveDotPath = new Path();
+ transitionAnimator = ValueAnimator.ofFloat(0f, 1f);
+ transitionAnimator.setInterpolator(null);
+ transitionAnimator.setCurrentFraction(0f);
+ transitionAnimator.addUpdateListener(animation -> invalidate());
+ }
+
+ @VisibleForTesting
+ public void setProgress(float progress, boolean toFirstPage) {
+ this.progress = progress;
+ this.toFirstPage = toFirstPage;
+
+ // Ensure the dot transition keeps up with the swipe progress.
+ if (transitionAnimator.isStarted() && progress > transitionAnimator.getAnimatedFraction()) {
+ transitionAnimator.setCurrentFraction(progress);
+ }
+
+ invalidate();
+ }
+
+ private void startTransition() {
+ if (transitionAnimator.getAnimatedFraction() < 1f) {
+ transitionAnimator.setCurrentFraction(progress);
+ useModeSwitchTransition = false;
+ transitionAnimator.cancel();
+ transitionAnimator.start();
+ }
+ }
+
+ private void endTransition(boolean snapBack) {
+ if (transitionAnimator.getAnimatedFraction() > 0f) {
+ useModeSwitchTransition = !snapBack;
+ transitionAnimator.cancel();
+ transitionAnimator.reverse();
+ }
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ int centerX = getWidth() / 2;
+ int centerY = getHeight() / 2;
+
+ float transitionFraction = (float) transitionAnimator.getAnimatedValue();
+
+ // Draw the inactive "dots".
+ inactiveDotPath.reset();
+ if (useModeSwitchTransition) {
+ float trackWidth = 2 * dotRadius + transitionFraction * (2 * dotRadius + dotsSeparation);
+ float indicatorRadius = dotRadius * (1f - 2f * Math.min(transitionFraction, 0.5f));
+ float indicatorOffset = dotRadius + dotsSeparation / 2;
+ if (toFirstPage) {
+ float trackLeft = centerX - indicatorOffset - dotRadius;
+ inactiveDotPath.addRoundRect(
+ trackLeft,
+ centerY - dotRadius,
+ trackLeft + trackWidth,
+ centerY + dotRadius,
+ dotRadius,
+ dotRadius,
+ Path.Direction.CW);
+ inactiveDotPath.addCircle(
+ centerX + indicatorOffset, centerY, indicatorRadius, Path.Direction.CW);
+ } else {
+ float trackRight = centerX + indicatorOffset + dotRadius;
+ inactiveDotPath.addRoundRect(
+ trackRight - trackWidth,
+ centerY - dotRadius,
+ trackRight,
+ centerY + dotRadius,
+ dotRadius,
+ dotRadius,
+ Path.Direction.CW);
+ inactiveDotPath.addCircle(
+ centerX - indicatorOffset, centerY, indicatorRadius, Path.Direction.CW);
+ }
+ } else {
+ float centerOffset = dotsSeparation / 2f;
+ float innerOffset = centerOffset - transitionFraction * (dotRadius + centerOffset);
+ float outerOffset = 2f * dotRadius + centerOffset;
+ inactiveDotPath.addRoundRect(
+ centerX - outerOffset,
+ centerY - dotRadius,
+ centerX - innerOffset,
+ centerY + dotRadius,
+ dotRadius,
+ dotRadius,
+ Path.Direction.CW);
+ inactiveDotPath.addRoundRect(
+ centerX + innerOffset,
+ centerY - dotRadius,
+ centerX + outerOffset,
+ centerY + dotRadius,
+ dotRadius,
+ dotRadius,
+ Path.Direction.CW);
+ }
+ Paint inactivePaint = inactiveDotPaintPortrait;
+ canvas.drawPath(inactiveDotPath, inactivePaint);
+
+ // Draw the white active dot.
+ float activeDotOffset =
+ (toFirstPage ? 1f - 2f * progress : 2f * progress - 1f) * (dotRadius + dotsSeparation / 2);
+ Paint activePaint = activeDotPaintPortrait;
+ canvas.drawCircle(centerX + activeDotOffset, centerY, dotRadius, activePaint);
+ }
+
+ public void setupWithViewPager(ViewPager pager) {
+ Assert.checkArgument(pager.getAdapter().getCount() == 2, "Invalid page count.");
+ pager.addOnPageChangeListener(this);
+ }
+
+ @Override
+ public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ setProgress(positionOffset, position != 0);
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ pageChanged = true;
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ switch (state) {
+ case ViewPager.SCROLL_STATE_IDLE:
+ endTransition(!pageChanged);
+ pageChanged = false;
+ break;
+ case ViewPager.SCROLL_STATE_DRAGGING:
+ startTransition();
+ break;
+ case ViewPager.SCROLL_STATE_SETTLING:
+ default:
+ break;
+ }
+ }
+}