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