1/* 2 * Copyright (C) 2012 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 */ 16package com.android.internal.policy.impl.keyguard; 17 18import android.animation.Animator; 19import android.animation.AnimatorListenerAdapter; 20import android.animation.AnimatorSet; 21import android.animation.ObjectAnimator; 22import android.animation.PropertyValuesHolder; 23import android.content.Context; 24import android.util.AttributeSet; 25import android.view.View; 26import android.view.animation.AccelerateInterpolator; 27import android.view.animation.DecelerateInterpolator; 28import android.view.animation.Interpolator; 29 30import java.util.ArrayList; 31 32import com.android.internal.R; 33 34public class KeyguardWidgetCarousel extends KeyguardWidgetPager { 35 36 private float mAdjacentPagesAngle; 37 private static float MAX_SCROLL_PROGRESS = 1.3f; 38 private static float CAMERA_DISTANCE = 10000; 39 protected AnimatorSet mChildrenTransformsAnimator; 40 float[] mTmpTransform = new float[3]; 41 42 public KeyguardWidgetCarousel(Context context, AttributeSet attrs) { 43 this(context, attrs, 0); 44 } 45 46 public KeyguardWidgetCarousel(Context context) { 47 this(context, null, 0); 48 } 49 50 public KeyguardWidgetCarousel(Context context, AttributeSet attrs, int defStyle) { 51 super(context, attrs, defStyle); 52 mAdjacentPagesAngle = context.getResources().getInteger(R.integer.kg_carousel_angle); 53 } 54 55 protected float getMaxScrollProgress() { 56 return MAX_SCROLL_PROGRESS; 57 } 58 59 public float getAlphaForPage(int screenCenter, int index) { 60 View child = getChildAt(index); 61 if (child == null) return 0f; 62 63 float scrollProgress = getScrollProgress(screenCenter, child, index); 64 if (!isOverScrollChild(index, scrollProgress)) { 65 scrollProgress = getBoundedScrollProgress(screenCenter, child, index); 66 float alpha = 1.0f - 1.0f * Math.abs(scrollProgress / MAX_SCROLL_PROGRESS); 67 return alpha; 68 } else { 69 return 1.0f; 70 } 71 } 72 73 private void updatePageAlphaValues(int screenCenter) { 74 if (mChildrenOutlineFadeAnimation != null) { 75 mChildrenOutlineFadeAnimation.cancel(); 76 mChildrenOutlineFadeAnimation = null; 77 } 78 if (!isReordering(false)) { 79 for (int i = 0; i < getChildCount(); i++) { 80 KeyguardWidgetFrame child = getWidgetPageAt(i); 81 if (child != null) { 82 child.setBackgroundAlpha(getOutlineAlphaForPage(screenCenter, i)); 83 child.setContentAlpha(getAlphaForPage(screenCenter, i)); 84 } 85 } 86 } 87 } 88 89 public void showInitialPageHints() { 90 int count = getChildCount(); 91 for (int i = 0; i < count; i++) { 92 KeyguardWidgetFrame child = getWidgetPageAt(i); 93 if (i >= mCurrentPage - 1 && i <= mCurrentPage + 1) { 94 child.fadeFrame(this, true, KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER, 95 CHILDREN_OUTLINE_FADE_IN_DURATION); 96 } 97 } 98 } 99 100 @Override 101 protected void screenScrolled(int screenCenter) { 102 mScreenCenter = screenCenter; 103 updatePageAlphaValues(screenCenter); 104 if (isReordering(false)) return; 105 for (int i = 0; i < getChildCount(); i++) { 106 KeyguardWidgetFrame v = getWidgetPageAt(i); 107 float scrollProgress = getScrollProgress(screenCenter, v, i); 108 float boundedProgress = getBoundedScrollProgress(screenCenter, v, i); 109 if (v == mDragView || v == null) continue; 110 v.setCameraDistance(CAMERA_DISTANCE); 111 112 if (isOverScrollChild(i, scrollProgress)) { 113 v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress); 114 v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0); 115 } else { 116 int width = v.getMeasuredWidth(); 117 float pivotX = (width / 2f) + boundedProgress * (width / 2f); 118 float pivotY = v.getMeasuredHeight() / 2; 119 float rotationY = - mAdjacentPagesAngle * boundedProgress; 120 v.setPivotX(pivotX); 121 v.setPivotY(pivotY); 122 v.setRotationY(rotationY); 123 v.setOverScrollAmount(0f, false); 124 } 125 float alpha = v.getAlpha(); 126 // If the view has 0 alpha, we set it to be invisible so as to prevent 127 // it from accepting touches 128 if (alpha == 0) { 129 v.setVisibility(INVISIBLE); 130 } else if (v.getVisibility() != VISIBLE) { 131 v.setVisibility(VISIBLE); 132 } 133 } 134 } 135 136 void animatePagesToNeutral() { 137 if (mChildrenTransformsAnimator != null) { 138 mChildrenTransformsAnimator.cancel(); 139 mChildrenTransformsAnimator = null; 140 } 141 142 int count = getChildCount(); 143 PropertyValuesHolder alpha; 144 PropertyValuesHolder outlineAlpha; 145 PropertyValuesHolder rotationY; 146 ArrayList<Animator> anims = new ArrayList<Animator>(); 147 148 for (int i = 0; i < count; i++) { 149 KeyguardWidgetFrame child = getWidgetPageAt(i); 150 boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1); 151 if (!inVisibleRange) { 152 child.setRotationY(0f); 153 } 154 alpha = PropertyValuesHolder.ofFloat("contentAlpha", 1.0f); 155 outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", 156 KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER); 157 rotationY = PropertyValuesHolder.ofFloat("rotationY", 0f); 158 ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, rotationY); 159 child.setVisibility(VISIBLE); 160 if (!inVisibleRange) { 161 a.setInterpolator(mSlowFadeInterpolator); 162 } 163 anims.add(a); 164 } 165 166 int duration = REORDERING_ZOOM_IN_OUT_DURATION; 167 mChildrenTransformsAnimator = new AnimatorSet(); 168 mChildrenTransformsAnimator.playTogether(anims); 169 170 mChildrenTransformsAnimator.setDuration(duration); 171 mChildrenTransformsAnimator.start(); 172 } 173 174 private void getTransformForPage(int screenCenter, int index, float[] transform) { 175 View child = getChildAt(index); 176 float boundedProgress = getBoundedScrollProgress(screenCenter, child, index); 177 float rotationY = - mAdjacentPagesAngle * boundedProgress; 178 int width = child.getMeasuredWidth(); 179 float pivotX = (width / 2f) + boundedProgress * (width / 2f); 180 float pivotY = child.getMeasuredHeight() / 2; 181 182 transform[0] = pivotX; 183 transform[1] = pivotY; 184 transform[2] = rotationY; 185 } 186 187 Interpolator mFastFadeInterpolator = new Interpolator() { 188 Interpolator mInternal = new DecelerateInterpolator(1.5f); 189 float mFactor = 2.5f; 190 @Override 191 public float getInterpolation(float input) { 192 return mInternal.getInterpolation(Math.min(mFactor * input, 1f)); 193 } 194 }; 195 196 Interpolator mSlowFadeInterpolator = new Interpolator() { 197 Interpolator mInternal = new AccelerateInterpolator(1.5f); 198 float mFactor = 1.3f; 199 @Override 200 public float getInterpolation(float input) { 201 input -= (1 - 1 / mFactor); 202 input = mFactor * Math.max(input, 0f); 203 return mInternal.getInterpolation(input); 204 } 205 }; 206 207 void animatePagesToCarousel() { 208 if (mChildrenTransformsAnimator != null) { 209 mChildrenTransformsAnimator.cancel(); 210 mChildrenTransformsAnimator = null; 211 } 212 213 int count = getChildCount(); 214 PropertyValuesHolder alpha; 215 PropertyValuesHolder outlineAlpha; 216 PropertyValuesHolder rotationY; 217 PropertyValuesHolder pivotX; 218 PropertyValuesHolder pivotY; 219 ArrayList<Animator> anims = new ArrayList<Animator>(); 220 221 for (int i = 0; i < count; i++) { 222 KeyguardWidgetFrame child = getWidgetPageAt(i); 223 float finalAlpha = getAlphaForPage(mScreenCenter, i); 224 float finalOutlineAlpha = getOutlineAlphaForPage(mScreenCenter, i); 225 getTransformForPage(mScreenCenter, i, mTmpTransform); 226 227 boolean inVisibleRange = (i >= mCurrentPage - 1 && i <= mCurrentPage + 1); 228 229 ObjectAnimator a; 230 alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalAlpha); 231 outlineAlpha = PropertyValuesHolder.ofFloat("backgroundAlpha", finalOutlineAlpha); 232 pivotX = PropertyValuesHolder.ofFloat("pivotX", mTmpTransform[0]); 233 pivotY = PropertyValuesHolder.ofFloat("pivotY", mTmpTransform[1]); 234 rotationY = PropertyValuesHolder.ofFloat("rotationY", mTmpTransform[2]); 235 236 if (inVisibleRange) { 237 // for the central pages we animate into a rotated state 238 a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha, 239 pivotX, pivotY, rotationY); 240 } else { 241 a = ObjectAnimator.ofPropertyValuesHolder(child, alpha, outlineAlpha); 242 a.setInterpolator(mFastFadeInterpolator); 243 } 244 anims.add(a); 245 } 246 247 int duration = REORDERING_ZOOM_IN_OUT_DURATION; 248 mChildrenTransformsAnimator = new AnimatorSet(); 249 mChildrenTransformsAnimator.playTogether(anims); 250 251 mChildrenTransformsAnimator.setDuration(duration); 252 mChildrenTransformsAnimator.start(); 253 } 254 255 protected void reorderStarting() { 256 mViewStateManager.fadeOutSecurity(REORDERING_ZOOM_IN_OUT_DURATION); 257 animatePagesToNeutral(); 258 } 259 260 protected boolean zoomIn(final Runnable onCompleteRunnable) { 261 animatePagesToCarousel(); 262 return super.zoomIn(onCompleteRunnable); 263 } 264 265 @Override 266 protected void onEndReordering() { 267 super.onEndReordering(); 268 mViewStateManager.fadeInSecurity(REORDERING_ZOOM_IN_OUT_DURATION); 269 } 270} 271