KeyguardWidgetPager.java revision 66b9fb1662b304d24984af1ac4cc02f2ae8f4cc3
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.TimeInterpolator; 19import android.appwidget.AppWidgetHostView; 20import android.content.Context; 21import android.util.AttributeSet; 22import android.view.Gravity; 23import android.view.View; 24import android.view.animation.AccelerateInterpolator; 25import android.view.animation.DecelerateInterpolator; 26 27import android.widget.FrameLayout; 28 29public class KeyguardWidgetPager extends PagedView { 30 ZInterpolator mZInterpolator = new ZInterpolator(0.5f); 31 private static float CAMERA_DISTANCE = 10000; 32 private static float TRANSITION_SCALE_FACTOR = 0.74f; 33 private static float TRANSITION_PIVOT = 0.65f; 34 private static float TRANSITION_MAX_ROTATION = 30; 35 private static final boolean PERFORM_OVERSCROLL_ROTATION = true; 36 private AccelerateInterpolator mAlphaInterpolator = new AccelerateInterpolator(0.9f); 37 private DecelerateInterpolator mLeftScreenAlphaInterpolator = new DecelerateInterpolator(4); 38 39 public KeyguardWidgetPager(Context context, AttributeSet attrs) { 40 this(context, attrs, 0); 41 } 42 43 public KeyguardWidgetPager(Context context) { 44 this(null, null, 0); 45 } 46 47 public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) { 48 super(context, attrs, defStyle); 49 } 50 51 /* 52 * We wrap widgets in a special frame which handles drawing the overscroll foreground. 53 */ 54 public void addWidget(AppWidgetHostView widget) { 55 KeyguardWidgetFrame frame = new KeyguardWidgetFrame(getContext()); 56 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, 57 LayoutParams.MATCH_PARENT); 58 lp.gravity = Gravity.CENTER; 59 // The framework adds a default padding to AppWidgetHostView. We don't need this padding 60 // for the Keyguard, so we override it to be 0. 61 widget.setPadding(0, 0, 0, 0); 62 frame.addView(widget, lp); 63 addView(frame); 64 } 65 66 /* 67 * This interpolator emulates the rate at which the perceived scale of an object changes 68 * as its distance from a camera increases. When this interpolator is applied to a scale 69 * animation on a view, it evokes the sense that the object is shrinking due to moving away 70 * from the camera. 71 */ 72 static class ZInterpolator implements TimeInterpolator { 73 private float focalLength; 74 75 public ZInterpolator(float foc) { 76 focalLength = foc; 77 } 78 79 public float getInterpolation(float input) { 80 return (1.0f - focalLength / (focalLength + input)) / 81 (1.0f - focalLength / (focalLength + 1.0f)); 82 } 83 } 84 85 @Override 86 protected void overScroll(float amount) { 87 acceleratedOverScroll(amount); 88 } 89 90 // In apps customize, we have a scrolling effect which emulates pulling cards off of a stack. 91 @Override 92 protected void screenScrolled(int screenCenter) { 93 super.screenScrolled(screenCenter); 94 95 for (int i = 0; i < getChildCount(); i++) { 96 View v = getPageAt(i); 97 if (v != null) { 98 float scrollProgress = getScrollProgress(screenCenter, v, i); 99 100 float interpolatedProgress = 101 mZInterpolator.getInterpolation(Math.abs(Math.min(scrollProgress, 0))); 102 float scale = (1 - interpolatedProgress) + 103 interpolatedProgress * TRANSITION_SCALE_FACTOR; 104 float translationX = Math.min(0, scrollProgress) * v.getMeasuredWidth(); 105 106 float alpha; 107 108 if (scrollProgress < 0) { 109 alpha = scrollProgress < 0 ? mAlphaInterpolator.getInterpolation( 110 1 - Math.abs(scrollProgress)) : 1.0f; 111 } else { 112 // On large screens we need to fade the page as it nears its leftmost position 113 alpha = mLeftScreenAlphaInterpolator.getInterpolation(1 - scrollProgress); 114 } 115 116 v.setCameraDistance(mDensity * CAMERA_DISTANCE); 117 int pageWidth = v.getMeasuredWidth(); 118 int pageHeight = v.getMeasuredHeight(); 119 120 if (PERFORM_OVERSCROLL_ROTATION) { 121 if (i == 0 && scrollProgress < 0) { 122 // Overscroll to the left 123 v.setPivotX(TRANSITION_PIVOT * pageWidth); 124 v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress); 125 if (v instanceof KeyguardWidgetFrame) { 126 ((KeyguardWidgetFrame) v).setOverScrollAmount(Math.abs(scrollProgress), 127 true); 128 } 129 scale = 1.0f; 130 alpha = 1.0f; 131 // On the first page, we don't want the page to have any lateral motion 132 translationX = 0; 133 } else if (i == getChildCount() - 1 && scrollProgress > 0) { 134 // Overscroll to the right 135 v.setPivotX((1 - TRANSITION_PIVOT) * pageWidth); 136 v.setRotationY(-TRANSITION_MAX_ROTATION * scrollProgress); 137 scale = 1.0f; 138 alpha = 1.0f; 139 if (v instanceof KeyguardWidgetFrame) { 140 ((KeyguardWidgetFrame) v).setOverScrollAmount(Math.abs(scrollProgress), 141 false); 142 } 143 // On the last page, we don't want the page to have any lateral motion. 144 translationX = 0; 145 } else { 146 v.setPivotY(pageHeight / 2.0f); 147 v.setPivotX(pageWidth / 2.0f); 148 v.setRotationY(0f); 149 if (v instanceof KeyguardWidgetFrame) { 150 ((KeyguardWidgetFrame) v).setOverScrollAmount(0, false); 151 } 152 } 153 } 154 155 v.setTranslationX(translationX); 156 v.setScaleX(scale); 157 v.setScaleY(scale); 158 v.setAlpha(alpha); 159 160 // If the view has 0 alpha, we set it to be invisible so as to prevent 161 // it from accepting touches 162 if (alpha == 0) { 163 v.setVisibility(INVISIBLE); 164 } else if (v.getVisibility() != VISIBLE) { 165 v.setVisibility(VISIBLE); 166 } 167 } 168 } 169 } 170} 171