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