1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.stackdivider; 18 19 import android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 import android.animation.AnimatorSet; 22 import android.animation.ObjectAnimator; 23 import android.annotation.Nullable; 24 import android.content.Context; 25 import android.graphics.Canvas; 26 import android.graphics.Paint; 27 import android.util.AttributeSet; 28 import android.util.Property; 29 import android.view.View; 30 31 import com.android.systemui.Interpolators; 32 import com.android.systemui.R; 33 34 /** 35 * View for the handle in the docked stack divider. 36 */ 37 public class DividerHandleView extends View { 38 39 private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY 40 = new Property<DividerHandleView, Integer>(Integer.class, "width") { 41 42 @Override 43 public Integer get(DividerHandleView object) { 44 return object.mCurrentWidth; 45 } 46 47 @Override 48 public void set(DividerHandleView object, Integer value) { 49 object.mCurrentWidth = value; 50 object.invalidate(); 51 } 52 }; 53 54 private final static Property<DividerHandleView, Integer> HEIGHT_PROPERTY 55 = new Property<DividerHandleView, Integer>(Integer.class, "height") { 56 57 @Override 58 public Integer get(DividerHandleView object) { 59 return object.mCurrentHeight; 60 } 61 62 @Override 63 public void set(DividerHandleView object, Integer value) { 64 object.mCurrentHeight = value; 65 object.invalidate(); 66 } 67 }; 68 69 private final Paint mPaint = new Paint(); 70 private final int mWidth; 71 private final int mHeight; 72 private final int mCircleDiameter; 73 private int mCurrentWidth; 74 private int mCurrentHeight; 75 private AnimatorSet mAnimator; 76 private boolean mTouching; 77 DividerHandleView(Context context, @Nullable AttributeSet attrs)78 public DividerHandleView(Context context, @Nullable AttributeSet attrs) { 79 super(context, attrs); 80 mPaint.setColor(getResources().getColor(R.color.docked_divider_handle, null)); 81 mPaint.setAntiAlias(true); 82 mWidth = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_width); 83 mHeight = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_height); 84 mCurrentWidth = mWidth; 85 mCurrentHeight = mHeight; 86 mCircleDiameter = (mWidth + mHeight) / 3; 87 } 88 setTouching(boolean touching, boolean animate)89 public void setTouching(boolean touching, boolean animate) { 90 if (touching == mTouching) { 91 return; 92 } 93 if (mAnimator != null) { 94 mAnimator.cancel(); 95 mAnimator = null; 96 } 97 if (!animate) { 98 if (touching) { 99 mCurrentWidth = mCircleDiameter; 100 mCurrentHeight = mCircleDiameter; 101 } else { 102 mCurrentWidth = mWidth; 103 mCurrentHeight = mHeight; 104 } 105 invalidate(); 106 } else { 107 animateToTarget(touching ? mCircleDiameter : mWidth, 108 touching ? mCircleDiameter : mHeight, touching); 109 } 110 mTouching = touching; 111 } 112 animateToTarget(int targetWidth, int targetHeight, boolean touching)113 private void animateToTarget(int targetWidth, int targetHeight, boolean touching) { 114 ObjectAnimator widthAnimator = ObjectAnimator.ofInt(this, WIDTH_PROPERTY, 115 mCurrentWidth, targetWidth); 116 ObjectAnimator heightAnimator = ObjectAnimator.ofInt(this, HEIGHT_PROPERTY, 117 mCurrentHeight, targetHeight); 118 mAnimator = new AnimatorSet(); 119 mAnimator.playTogether(widthAnimator, heightAnimator); 120 mAnimator.setDuration(touching 121 ? DividerView.TOUCH_ANIMATION_DURATION 122 : DividerView.TOUCH_RELEASE_ANIMATION_DURATION); 123 mAnimator.setInterpolator(touching 124 ? Interpolators.TOUCH_RESPONSE 125 : Interpolators.FAST_OUT_SLOW_IN); 126 mAnimator.addListener(new AnimatorListenerAdapter() { 127 @Override 128 public void onAnimationEnd(Animator animation) { 129 mAnimator = null; 130 } 131 }); 132 mAnimator.start(); 133 } 134 135 @Override onDraw(Canvas canvas)136 protected void onDraw(Canvas canvas) { 137 int left = getWidth() / 2 - mCurrentWidth / 2; 138 int top = getHeight() / 2 - mCurrentHeight / 2; 139 int radius = Math.min(mCurrentWidth, mCurrentHeight) / 2; 140 canvas.drawRoundRect(left, top, left + mCurrentWidth, top + mCurrentHeight, 141 radius, radius, mPaint); 142 } 143 144 @Override hasOverlappingRendering()145 public boolean hasOverlappingRendering() { 146 return false; 147 } 148 } 149