blob: 99f775787cec6be621195ce4218c4b5955094b47 [file] [log] [blame]
Jim Millerdcb3d842012-08-23 19:18:12 -07001/*
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 */
Jim Miller5ecd8112013-01-09 18:50:26 -080016package com.android.keyguard;
Jim Millerdcb3d842012-08-23 19:18:12 -070017
Adam Cohenf9048cd2012-10-27 16:36:10 -070018import android.animation.Animator;
19import android.animation.AnimatorListenerAdapter;
20import android.animation.AnimatorSet;
Jim Millerd6523da2012-10-21 16:47:02 -070021import android.animation.ObjectAnimator;
Adam Cohen6fb841f2012-10-24 13:15:38 -070022import android.animation.PropertyValuesHolder;
Jim Millerdcb3d842012-08-23 19:18:12 -070023import android.animation.TimeInterpolator;
Adam Cohen4ddcd572012-11-01 17:36:32 -070024import android.appwidget.AppWidgetHostView;
Jim Miller51117262012-11-04 17:58:09 -080025import android.appwidget.AppWidgetManager;
Adam Cohen4ddcd572012-11-01 17:36:32 -070026import android.appwidget.AppWidgetProviderInfo;
Jim Millerdcb3d842012-08-23 19:18:12 -070027import android.content.Context;
Winson Chungf8f59662012-10-30 12:03:18 -070028import android.os.Handler;
29import android.os.HandlerThread;
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -080030import android.text.format.DateFormat;
Jim Millerdcb3d842012-08-23 19:18:12 -070031import android.util.AttributeSet;
Jim Millerbdca3c02012-10-29 19:11:50 -070032import android.util.Slog;
Jim Millerf2dfc352012-08-29 18:42:21 -070033import android.view.Gravity;
Jim Millerc1aa6a52012-09-28 19:37:26 -070034import android.view.MotionEvent;
Jim Millerdcb3d842012-08-23 19:18:12 -070035import android.view.View;
Jim Millerd6523da2012-10-21 16:47:02 -070036import android.view.View.OnLongClickListener;
Adam Cohen4ddcd572012-11-01 17:36:32 -070037import android.view.ViewGroup;
Svetoslav Ganovc4842c12012-10-31 14:33:32 -070038import android.view.accessibility.AccessibilityEvent;
39import android.view.accessibility.AccessibilityManager;
Winson Chung70c2f872012-11-07 21:47:12 -080040import android.view.animation.DecelerateInterpolator;
Jim Millerf2dfc352012-08-29 18:42:21 -070041import android.widget.FrameLayout;
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -080042import android.widget.TextClock;
Jim Miller4d20ed32013-10-19 01:00:16 +000043
Michael Jurka1254f2f2012-10-25 11:44:31 -070044import com.android.internal.widget.LockPatternUtils;
Svetoslav Ganov6526fdd2012-10-02 16:21:20 -070045
Adam Cohenf9048cd2012-10-27 16:36:10 -070046import java.util.ArrayList;
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -080047import java.util.TimeZone;
Adam Cohenf9048cd2012-10-27 16:36:10 -070048
Jim Millerd6523da2012-10-21 16:47:02 -070049public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener,
Winson Chung48275d22012-11-05 10:56:31 -080050 OnLongClickListener, ChallengeLayout.OnBouncerStateChangedListener {
Jim Millerd6523da2012-10-21 16:47:02 -070051
Jim Millerdcb3d842012-08-23 19:18:12 -070052 ZInterpolator mZInterpolator = new ZInterpolator(0.5f);
Jim Millerf2dfc352012-08-29 18:42:21 -070053 private static float CAMERA_DISTANCE = 10000;
Adam Cohenf9048cd2012-10-27 16:36:10 -070054 protected static float OVERSCROLL_MAX_ROTATION = 30;
Jim Millerdcb3d842012-08-23 19:18:12 -070055 private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
Adam Cohen9ec871d2012-10-24 19:25:44 -070056
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -080057 private static final int FLAG_HAS_LOCAL_HOUR = 0x1;
58 private static final int FLAG_HAS_LOCAL_MINUTE = 0x2;
59
Adam Cohen70009e42012-10-30 16:48:22 -070060 protected KeyguardViewStateManager mViewStateManager;
Michael Jurka1254f2f2012-10-25 11:44:31 -070061 private LockPatternUtils mLockPatternUtils;
Jim Millerd6523da2012-10-21 16:47:02 -070062
63 // Related to the fading in / out background outlines
Adam Cohendb1c5d52012-11-03 17:10:07 -070064 public static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375;
65 public static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100;
Adam Cohenf9048cd2012-10-27 16:36:10 -070066 protected AnimatorSet mChildrenOutlineFadeAnimation;
Adam Cohenf9048cd2012-10-27 16:36:10 -070067 protected int mScreenCenter;
Adam Cohen8a7785c2012-10-29 22:01:33 -070068 private boolean mHasMeasure = false;
Adam Cohen70009e42012-10-30 16:48:22 -070069 boolean showHintsAfterLayout = false;
Jim Millerf2dfc352012-08-29 18:42:21 -070070
Jim Miller838906b2012-10-19 18:41:25 -070071 private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000;
Jim Millerbdca3c02012-10-29 19:11:50 -070072 private static final String TAG = "KeyguardWidgetPager";
Adam Cohen6f72b1c2012-11-05 15:20:30 -080073 private boolean mCenterSmallWidgetsVertically;
Jim Miller838906b2012-10-19 18:41:25 -070074
75 private int mPage = 0;
76 private Callbacks mCallbacks;
77
Adam Cohen8caabad2012-11-04 17:23:25 -080078 private int mWidgetToResetAfterFadeOut;
Adam Cohen2b0501b2012-11-21 16:49:13 -080079 protected boolean mShowingInitialHints = false;
Adam Cohendb1c5d52012-11-03 17:10:07 -070080
Winson Chung4752e7d2012-11-20 17:06:04 -080081 // A temporary handle to the Add-Widget view
82 private View mAddWidgetView;
83 private int mLastWidthMeasureSpec;
84 private int mLastHeightMeasureSpec;
85
Winson Chung48275d22012-11-05 10:56:31 -080086 // Bouncer
Winson Chung70c2f872012-11-07 21:47:12 -080087 private int mBouncerZoomInOutDuration = 250;
Winson Chung48275d22012-11-05 10:56:31 -080088 private float BOUNCER_SCALE_FACTOR = 0.67f;
89
John Spurlock37d84ae2012-11-04 11:11:47 -050090 // Background worker thread: used here for persistence, also made available to widget frames
91 private final HandlerThread mBackgroundWorkerThread;
92 private final Handler mBackgroundWorkerHandler;
Jim Miller8de9e442013-09-20 14:21:50 -070093 private boolean mCameraEventInProgress;
Winson Chungf8f59662012-10-30 12:03:18 -070094
Jim Millerf2dfc352012-08-29 18:42:21 -070095 public KeyguardWidgetPager(Context context, AttributeSet attrs) {
96 this(context, attrs, 0);
97 }
98
99 public KeyguardWidgetPager(Context context) {
100 this(null, null, 0);
101 }
102
103 public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) {
104 super(context, attrs, defStyle);
Svetoslav Ganov6526fdd2012-10-02 16:21:20 -0700105 if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
106 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
107 }
Jim Miller838906b2012-10-19 18:41:25 -0700108
109 setPageSwitchListener(this);
Winson Chungefc49252012-10-26 15:41:27 -0700110
John Spurlock37d84ae2012-11-04 11:11:47 -0500111 mBackgroundWorkerThread = new HandlerThread("KeyguardWidgetPager Worker");
112 mBackgroundWorkerThread.start();
113 mBackgroundWorkerHandler = new Handler(mBackgroundWorkerThread.getLooper());
Jim Millerf2dfc352012-08-29 18:42:21 -0700114 }
115
Winson Chunge72855e2012-11-01 18:05:04 -0700116 @Override
117 protected void onDetachedFromWindow() {
118 super.onDetachedFromWindow();
119
John Spurlock37d84ae2012-11-04 11:11:47 -0500120 // Clean up the worker thread
121 mBackgroundWorkerThread.quit();
Winson Chunge72855e2012-11-01 18:05:04 -0700122 }
123
Jim Millerd6523da2012-10-21 16:47:02 -0700124 public void setViewStateManager(KeyguardViewStateManager viewStateManager) {
125 mViewStateManager = viewStateManager;
126 }
127
Michael Jurka1254f2f2012-10-25 11:44:31 -0700128 public void setLockPatternUtils(LockPatternUtils l) {
129 mLockPatternUtils = l;
130 }
131
Jim Miller838906b2012-10-19 18:41:25 -0700132 @Override
John Spurlockbb5c9412012-10-31 09:46:15 -0400133 public void onPageSwitching(View newPage, int newPageIndex) {
134 if (mViewStateManager != null) {
135 mViewStateManager.onPageSwitching(newPage, newPageIndex);
136 }
137 }
138
139 @Override
140 public void onPageSwitched(View newPage, int newPageIndex) {
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -0800141 boolean showingClock = false;
Jim Miller838906b2012-10-19 18:41:25 -0700142 if (newPage instanceof ViewGroup) {
143 ViewGroup vg = (ViewGroup) newPage;
144 if (vg.getChildAt(0) instanceof KeyguardStatusView) {
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -0800145 showingClock = true;
Jim Miller838906b2012-10-19 18:41:25 -0700146 }
147 }
148
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -0800149 if (newPage != null &&
150 findClockInHierarchy(newPage) == (FLAG_HAS_LOCAL_HOUR | FLAG_HAS_LOCAL_MINUTE)) {
151 showingClock = true;
152 }
153
Jim Miller838906b2012-10-19 18:41:25 -0700154 // Disable the status bar clock if we're showing the default status widget
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -0800155 if (showingClock) {
Jim Miller838906b2012-10-19 18:41:25 -0700156 setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK);
157 } else {
158 setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK);
159 }
160
161 // Extend the display timeout if the user switches pages
162 if (mPage != newPageIndex) {
John Spurlock86b63572012-10-24 11:24:25 -0400163 int oldPageIndex = mPage;
Jim Miller838906b2012-10-19 18:41:25 -0700164 mPage = newPageIndex;
Chris Wren32c557c2012-10-29 11:16:42 -0400165 userActivity();
John Spurlock86b63572012-10-24 11:24:25 -0400166 KeyguardWidgetFrame oldWidgetPage = getWidgetPageAt(oldPageIndex);
167 if (oldWidgetPage != null) {
168 oldWidgetPage.onActive(false);
169 }
170 KeyguardWidgetFrame newWidgetPage = getWidgetPageAt(newPageIndex);
171 if (newWidgetPage != null) {
172 newWidgetPage.onActive(true);
Svetoslav4293e232013-04-25 13:25:06 -0700173 newWidgetPage.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
Svetoslav Ganovc4842c12012-10-31 14:33:32 -0700174 newWidgetPage.requestAccessibilityFocus();
John Spurlock86b63572012-10-24 11:24:25 -0400175 }
Svetoslav Ganov45942ca2012-10-31 19:46:24 -0700176 if (mParent != null && AccessibilityManager.getInstance(mContext).isEnabled()) {
177 AccessibilityEvent event = AccessibilityEvent.obtain(
178 AccessibilityEvent.TYPE_VIEW_SCROLLED);
179 onInitializeAccessibilityEvent(event);
180 onPopulateAccessibilityEvent(event);
181 mParent.requestSendAccessibilityEvent(this, event);
182 }
Jim Miller838906b2012-10-19 18:41:25 -0700183 }
Jim Millerd6523da2012-10-21 16:47:02 -0700184 if (mViewStateManager != null) {
John Spurlockbb5c9412012-10-31 09:46:15 -0400185 mViewStateManager.onPageSwitched(newPage, newPageIndex);
Jim Millerd6523da2012-10-21 16:47:02 -0700186 }
Svetoslav Ganovc4842c12012-10-31 14:33:32 -0700187 }
188
189 @Override
Jim Millercaf24fc2013-09-10 18:37:01 -0700190 public void onPageBeginWarp() {
Jim Millerc162dd02013-09-25 18:57:43 -0700191 showOutlinesAndSidePages();
Jim Millercaf24fc2013-09-10 18:37:01 -0700192 mViewStateManager.onPageBeginWarp();
193 }
194
195 @Override
196 public void onPageEndWarp() {
Jim Miller6b0afad2013-10-28 19:08:42 -0700197 // if we're moving to the warp page, then immediately hide the other widgets.
198 int duration = getPageWarpIndex() == getNextPage() ? 0 : -1;
199 animateOutlinesAndSidePages(false, duration);
Jim Millercaf24fc2013-09-10 18:37:01 -0700200 mViewStateManager.onPageEndWarp();
201 }
202
203 @Override
Svetoslav Ganovc4842c12012-10-31 14:33:32 -0700204 public void sendAccessibilityEvent(int eventType) {
205 if (eventType != AccessibilityEvent.TYPE_VIEW_SCROLLED || isPageMoving()) {
206 super.sendAccessibilityEvent(eventType);
207 }
Jim Miller838906b2012-10-19 18:41:25 -0700208 }
209
Svetoslav Ganova90a18d2012-11-06 15:22:11 -0800210 private void updateWidgetFramesImportantForAccessibility() {
211 final int pageCount = getPageCount();
212 for (int i = 0; i < pageCount; i++) {
213 KeyguardWidgetFrame frame = getWidgetPageAt(i);
214 updateWidgetFrameImportantForAccessibility(frame);
215 }
216 }
217
218 private void updateWidgetFrameImportantForAccessibility(KeyguardWidgetFrame frame) {
219 if (frame.getContentAlpha() <= 0) {
220 frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
221 } else {
222 frame.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
223 }
224 }
225
Chris Wren32c557c2012-10-29 11:16:42 -0400226 private void userActivity() {
227 if (mCallbacks != null) {
228 mCallbacks.onUserActivityTimeoutChanged();
229 mCallbacks.userActivity();
230 }
231 }
232
John Spurlock4b976ea2012-10-28 12:34:11 -0400233 @Override
234 public boolean onTouchEvent(MotionEvent ev) {
John Spurlockf70239a2012-11-04 09:42:42 -0500235 return captureUserInteraction(ev) || super.onTouchEvent(ev);
236 }
237
238 @Override
239 public boolean onInterceptTouchEvent(MotionEvent ev) {
240 return captureUserInteraction(ev) || super.onInterceptTouchEvent(ev);
241 }
242
243 private boolean captureUserInteraction(MotionEvent ev) {
John Spurlock4b976ea2012-10-28 12:34:11 -0400244 KeyguardWidgetFrame currentWidgetPage = getWidgetPageAt(getCurrentPage());
John Spurlockf70239a2012-11-04 09:42:42 -0500245 return currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev);
John Spurlock4b976ea2012-10-28 12:34:11 -0400246 }
247
Jim Miller838906b2012-10-19 18:41:25 -0700248 public void showPagingFeedback() {
249 // Nothing yet.
250 }
Jim Millerd6523da2012-10-21 16:47:02 -0700251
Jim Miller838906b2012-10-19 18:41:25 -0700252 public long getUserActivityTimeout() {
253 View page = getPageAt(mPage);
254 if (page instanceof ViewGroup) {
255 ViewGroup vg = (ViewGroup) page;
256 View view = vg.getChildAt(0);
257 if (!(view instanceof KeyguardStatusView)
258 && !(view instanceof KeyguardMultiUserSelectorView)) {
259 return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT;
260 }
261 }
262 return -1;
263 }
264
265 public void setCallbacks(Callbacks callbacks) {
266 mCallbacks = callbacks;
267 }
268
269 public interface Callbacks {
270 public void userActivity();
271 public void onUserActivityTimeoutChanged();
Winson Chung40f82112012-11-08 11:54:55 -0800272 public void onAddView(View v);
Michael Jurka75b5cfb2012-11-15 18:22:47 -0800273 public void onRemoveView(View v, boolean deletePermanently);
Winson Chung4752e7d2012-11-20 17:06:04 -0800274 public void onRemoveViewAnimationCompleted();
Jim Miller838906b2012-10-19 18:41:25 -0700275 }
Jim Millerd6523da2012-10-21 16:47:02 -0700276
277 public void addWidget(View widget) {
278 addWidget(widget, -1);
279 }
280
Michael Jurka75b5cfb2012-11-15 18:22:47 -0800281 public void onRemoveView(View v, final boolean deletePermanently) {
Winson Chungf8f59662012-10-30 12:03:18 -0700282 final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
Michael Jurkaeb963f02012-11-08 00:32:29 -0800283 if (mCallbacks != null) {
Michael Jurka75b5cfb2012-11-15 18:22:47 -0800284 mCallbacks.onRemoveView(v, deletePermanently);
Michael Jurkaeb963f02012-11-08 00:32:29 -0800285 }
John Spurlock37d84ae2012-11-04 11:11:47 -0500286 mBackgroundWorkerHandler.post(new Runnable() {
Winson Chungf8f59662012-10-30 12:03:18 -0700287 @Override
288 public void run() {
289 mLockPatternUtils.removeAppWidget(appWidgetId);
290 }
291 });
Michael Jurka1254f2f2012-10-25 11:44:31 -0700292 }
293
Winson Chung4752e7d2012-11-20 17:06:04 -0800294 @Override
295 public void onRemoveViewAnimationCompleted() {
296 if (mCallbacks != null) {
297 mCallbacks.onRemoveViewAnimationCompleted();
298 }
299 }
300
Winson Chungf8f59662012-10-30 12:03:18 -0700301 public void onAddView(View v, final int index) {
302 final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId();
303 final int[] pagesRange = new int[mTempVisiblePagesRange.length];
304 getVisiblePages(pagesRange);
305 boundByReorderablePages(true, pagesRange);
Winson Chung40f82112012-11-08 11:54:55 -0800306 if (mCallbacks != null) {
307 mCallbacks.onAddView(v);
308 }
Michael Jurka1254f2f2012-10-25 11:44:31 -0700309 // Subtract from the index to take into account pages before the reorderable
310 // pages (e.g. the "add widget" page)
John Spurlock37d84ae2012-11-04 11:11:47 -0500311 mBackgroundWorkerHandler.post(new Runnable() {
Winson Chungf8f59662012-10-30 12:03:18 -0700312 @Override
313 public void run() {
314 mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]);
315 }
316 });
Michael Jurka1254f2f2012-10-25 11:44:31 -0700317 }
318
Jim Millerf2dfc352012-08-29 18:42:21 -0700319 /*
Jim Millerd6523da2012-10-21 16:47:02 -0700320 * We wrap widgets in a special frame which handles drawing the over scroll foreground.
Jim Millerf2dfc352012-08-29 18:42:21 -0700321 */
Jim Millerd6523da2012-10-21 16:47:02 -0700322 public void addWidget(View widget, int pageIndex) {
323 KeyguardWidgetFrame frame;
324 // All views contained herein should be wrapped in a KeyguardWidgetFrame
325 if (!(widget instanceof KeyguardWidgetFrame)) {
326 frame = new KeyguardWidgetFrame(getContext());
327 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
328 LayoutParams.MATCH_PARENT);
329 lp.gravity = Gravity.TOP;
Adam Cohen4ddcd572012-11-01 17:36:32 -0700330
Jim Millerd6523da2012-10-21 16:47:02 -0700331 // The framework adds a default padding to AppWidgetHostView. We don't need this padding
332 // for the Keyguard, so we override it to be 0.
333 widget.setPadding(0, 0, 0, 0);
Jim Millerd6523da2012-10-21 16:47:02 -0700334 frame.addView(widget, lp);
Adam Cohen4ddcd572012-11-01 17:36:32 -0700335
336 // We set whether or not this widget supports vertical resizing.
337 if (widget instanceof AppWidgetHostView) {
338 AppWidgetHostView awhv = (AppWidgetHostView) widget;
339 AppWidgetProviderInfo info = awhv.getAppWidgetInfo();
340 if ((info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
341 frame.setWidgetLockedSmall(false);
342 } else {
343 // Lock the widget to be small.
344 frame.setWidgetLockedSmall(true);
Adam Cohen6f72b1c2012-11-05 15:20:30 -0800345 if (mCenterSmallWidgetsVertically) {
346 lp.gravity = Gravity.CENTER;
347 }
Adam Cohen4ddcd572012-11-01 17:36:32 -0700348 }
349 }
Jim Millerd6523da2012-10-21 16:47:02 -0700350 } else {
351 frame = (KeyguardWidgetFrame) widget;
352 }
353
354 ViewGroup.LayoutParams pageLp = new ViewGroup.LayoutParams(
355 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
356 frame.setOnLongClickListener(this);
John Spurlock37d84ae2012-11-04 11:11:47 -0500357 frame.setWorkerHandler(mBackgroundWorkerHandler);
Jim Millerd6523da2012-10-21 16:47:02 -0700358
359 if (pageIndex == -1) {
360 addView(frame, pageLp);
361 } else {
362 addView(frame, pageIndex, pageLp);
363 }
Svetoslav Ganovc4842c12012-10-31 14:33:32 -0700364
365 // Update the frame content description.
366 View content = (widget == frame) ? frame.getContent() : widget;
367 if (content != null) {
368 String contentDescription = mContext.getString(
Jim Miller5ecd8112013-01-09 18:50:26 -0800369 R.string.keyguard_accessibility_widget,
Svetoslav Ganovc4842c12012-10-31 14:33:32 -0700370 content.getContentDescription());
371 frame.setContentDescription(contentDescription);
372 }
Svetoslav Ganova90a18d2012-11-06 15:22:11 -0800373 updateWidgetFrameImportantForAccessibility(frame);
Jim Millerd6523da2012-10-21 16:47:02 -0700374 }
375
Jim Millerbdca3c02012-10-29 19:11:50 -0700376 /**
377 * Use addWidget() instead.
378 * @deprecated
379 */
Jim Millerd6523da2012-10-21 16:47:02 -0700380 @Override
381 public void addView(View child, int index) {
382 enforceKeyguardWidgetFrame(child);
383 super.addView(child, index);
384 }
385
Jim Millerbdca3c02012-10-29 19:11:50 -0700386 /**
387 * Use addWidget() instead.
388 * @deprecated
389 */
Jim Millerd6523da2012-10-21 16:47:02 -0700390 @Override
391 public void addView(View child, int width, int height) {
392 enforceKeyguardWidgetFrame(child);
393 super.addView(child, width, height);
394 }
395
Jim Millerbdca3c02012-10-29 19:11:50 -0700396 /**
397 * Use addWidget() instead.
398 * @deprecated
399 */
Jim Millerd6523da2012-10-21 16:47:02 -0700400 @Override
401 public void addView(View child, LayoutParams params) {
402 enforceKeyguardWidgetFrame(child);
403 super.addView(child, params);
404 }
405
Jim Millerbdca3c02012-10-29 19:11:50 -0700406 /**
407 * Use addWidget() instead.
408 * @deprecated
409 */
Jim Millerd6523da2012-10-21 16:47:02 -0700410 @Override
411 public void addView(View child, int index, LayoutParams params) {
412 enforceKeyguardWidgetFrame(child);
413 super.addView(child, index, params);
414 }
415
416 private void enforceKeyguardWidgetFrame(View child) {
417 if (!(child instanceof KeyguardWidgetFrame)) {
418 throw new IllegalArgumentException(
419 "KeyguardWidgetPager children must be KeyguardWidgetFrames");
420 }
421 }
422
423 public KeyguardWidgetFrame getWidgetPageAt(int index) {
424 // This is always a valid cast as we've guarded the ability to
425 return (KeyguardWidgetFrame) getChildAt(index);
Jim Millerf2dfc352012-08-29 18:42:21 -0700426 }
427
Jim Millerc1aa6a52012-09-28 19:37:26 -0700428 protected void onUnhandledTap(MotionEvent ev) {
Jim Miller838906b2012-10-19 18:41:25 -0700429 showPagingFeedback();
Jim Millerc1aa6a52012-09-28 19:37:26 -0700430 }
431
Jim Millereeadda52012-10-02 17:32:38 -0700432 @Override
433 protected void onPageBeginMoving() {
Jim Millerd6523da2012-10-21 16:47:02 -0700434 if (mViewStateManager != null) {
435 mViewStateManager.onPageBeginMoving();
436 }
Adam Cohen70009e42012-10-30 16:48:22 -0700437 if (!isReordering(false)) {
438 showOutlinesAndSidePages();
439 }
Chris Wren32c557c2012-10-29 11:16:42 -0400440 userActivity();
Jim Millereeadda52012-10-02 17:32:38 -0700441 }
442
443 @Override
444 protected void onPageEndMoving() {
Jim Millerd6523da2012-10-21 16:47:02 -0700445 if (mViewStateManager != null) {
446 mViewStateManager.onPageEndMoving();
447 }
Adam Cohen70009e42012-10-30 16:48:22 -0700448
449 // In the reordering case, the pages will be faded appropriately on completion
450 // of the zoom in animation.
451 if (!isReordering(false)) {
452 hideOutlinesAndSidePages();
453 }
Jim Millereeadda52012-10-02 17:32:38 -0700454 }
455
Adam Cohen5d47a8d2012-11-03 19:10:56 -0700456 protected void enablePageContentLayers() {
Adam Cohenf9048cd2012-10-27 16:36:10 -0700457 int children = getChildCount();
458 for (int i = 0; i < children; i++) {
459 getWidgetPageAt(i).enableHardwareLayersForContent();
460 }
461 }
462
Adam Cohen5d47a8d2012-11-03 19:10:56 -0700463 protected void disablePageContentLayers() {
Adam Cohenf9048cd2012-10-27 16:36:10 -0700464 int children = getChildCount();
465 for (int i = 0; i < children; i++) {
466 getWidgetPageAt(i).disableHardwareLayersForContent();
467 }
468 }
469
Jim Millerdcb3d842012-08-23 19:18:12 -0700470 /*
471 * This interpolator emulates the rate at which the perceived scale of an object changes
472 * as its distance from a camera increases. When this interpolator is applied to a scale
473 * animation on a view, it evokes the sense that the object is shrinking due to moving away
474 * from the camera.
475 */
476 static class ZInterpolator implements TimeInterpolator {
477 private float focalLength;
478
479 public ZInterpolator(float foc) {
480 focalLength = foc;
481 }
482
483 public float getInterpolation(float input) {
484 return (1.0f - focalLength / (focalLength + input)) /
485 (1.0f - focalLength / (focalLength + 1.0f));
486 }
487 }
488
Jim Millerf2dfc352012-08-29 18:42:21 -0700489 @Override
490 protected void overScroll(float amount) {
491 acceleratedOverScroll(amount);
492 }
493
Jim Millerd6523da2012-10-21 16:47:02 -0700494 float backgroundAlphaInterpolator(float r) {
Adam Cohen9ec871d2012-10-24 19:25:44 -0700495 return Math.min(1f, r);
Jim Millerd6523da2012-10-21 16:47:02 -0700496 }
497
498 private void updatePageAlphaValues(int screenCenter) {
Adam Cohenf9048cd2012-10-27 16:36:10 -0700499 }
500
Adam Cohen2b0501b2012-11-21 16:49:13 -0800501 public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
Jim Millerc162dd02013-09-25 18:57:43 -0700502 if (isWarping()) {
Jim Millerf4db8f92013-09-20 14:21:50 -0700503 return index == getPageWarpIndex() ? 1.0f : 0.0f;
504 }
Adam Cohen2b0501b2012-11-21 16:49:13 -0800505 if (showSidePages) {
506 return 1f;
507 } else {
508 return index == mCurrentPage ? 1.0f : 0f;
509 }
Adam Cohenf9048cd2012-10-27 16:36:10 -0700510 }
511
Adam Cohen2b0501b2012-11-21 16:49:13 -0800512 public float getOutlineAlphaForPage(int screenCenter, int index, boolean showSidePages) {
513 if (showSidePages) {
514 return getAlphaForPage(screenCenter, index, showSidePages)
515 * KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER;
516 } else {
517 return 0f;
518 }
Adam Powellcfc30862012-10-29 18:21:31 -0700519 }
520
Adam Cohenf9048cd2012-10-27 16:36:10 -0700521 protected boolean isOverScrollChild(int index, float scrollProgress) {
Jim Millerd6523da2012-10-21 16:47:02 -0700522 boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX;
Adam Cohenf9048cd2012-10-27 16:36:10 -0700523 return (isInOverscroll && (index == 0 && scrollProgress < 0 ||
524 index == getChildCount() - 1 && scrollProgress > 0));
Jim Millerd6523da2012-10-21 16:47:02 -0700525 }
526
Jim Millerdcb3d842012-08-23 19:18:12 -0700527 @Override
528 protected void screenScrolled(int screenCenter) {
Adam Cohenf9048cd2012-10-27 16:36:10 -0700529 mScreenCenter = screenCenter;
Jim Millerd6523da2012-10-21 16:47:02 -0700530 updatePageAlphaValues(screenCenter);
Jim Millerdcb3d842012-08-23 19:18:12 -0700531 for (int i = 0; i < getChildCount(); i++) {
Jim Millerd6523da2012-10-21 16:47:02 -0700532 KeyguardWidgetFrame v = getWidgetPageAt(i);
533 if (v == mDragView) continue;
Jim Millerdcb3d842012-08-23 19:18:12 -0700534 if (v != null) {
535 float scrollProgress = getScrollProgress(screenCenter, v, i);
Jim Millerd6523da2012-10-21 16:47:02 -0700536
Jim Millerdcb3d842012-08-23 19:18:12 -0700537 v.setCameraDistance(mDensity * CAMERA_DISTANCE);
Jim Millerdcb3d842012-08-23 19:18:12 -0700538
Adam Cohenf9048cd2012-10-27 16:36:10 -0700539 if (isOverScrollChild(i, scrollProgress) && PERFORM_OVERSCROLL_ROTATION) {
Adam Cohend51700b32012-11-07 16:26:46 -0800540 float pivotX = v.getMeasuredWidth() / 2;
541 float pivotY = v.getMeasuredHeight() / 2;
542 v.setPivotX(pivotX);
543 v.setPivotY(pivotY);
Adam Cohenf9048cd2012-10-27 16:36:10 -0700544 v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress);
545 v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0);
546 } else {
547 v.setRotationY(0f);
548 v.setOverScrollAmount(0, false);
Jim Millerdcb3d842012-08-23 19:18:12 -0700549 }
Jim Millerdcb3d842012-08-23 19:18:12 -0700550
Adam Cohenf9048cd2012-10-27 16:36:10 -0700551 float alpha = v.getAlpha();
Jim Millerdcb3d842012-08-23 19:18:12 -0700552 // If the view has 0 alpha, we set it to be invisible so as to prevent
553 // it from accepting touches
554 if (alpha == 0) {
555 v.setVisibility(INVISIBLE);
556 } else if (v.getVisibility() != VISIBLE) {
557 v.setVisibility(VISIBLE);
558 }
559 }
560 }
561 }
Adam Cohenf9048cd2012-10-27 16:36:10 -0700562
Jim Miller51117262012-11-04 17:58:09 -0800563 public boolean isWidgetPage(int pageIndex) {
564 if (pageIndex < 0 || pageIndex >= getChildCount()) {
565 return false;
566 }
567 View v = getChildAt(pageIndex);
568 if (v != null && v instanceof KeyguardWidgetFrame) {
569 KeyguardWidgetFrame kwf = (KeyguardWidgetFrame) v;
570 return kwf.getContentAppWidgetId() != AppWidgetManager.INVALID_APPWIDGET_ID;
571 }
572 return false;
573 }
574
Winson Chungc065a5d2012-11-07 17:17:33 -0800575 /**
576 * Returns the bounded set of pages that are re-orderable. The range is fully inclusive.
577 */
Jim Millerd6523da2012-10-21 16:47:02 -0700578 @Override
Winson Chungefc49252012-10-26 15:41:27 -0700579 void boundByReorderablePages(boolean isReordering, int[] range) {
580 if (isReordering) {
Jim Miller51117262012-11-04 17:58:09 -0800581 // Remove non-widget pages from the range
Winson Chungc065a5d2012-11-07 17:17:33 -0800582 while (range[1] >= range[0] && !isWidgetPage(range[1])) {
Jim Miller51117262012-11-04 17:58:09 -0800583 range[1]--;
584 }
Winson Chungc065a5d2012-11-07 17:17:33 -0800585 while (range[0] <= range[1] && !isWidgetPage(range[0])) {
Winson Chungefc49252012-10-26 15:41:27 -0700586 range[0]++;
587 }
Winson Chungefc49252012-10-26 15:41:27 -0700588 }
589 }
590
Adam Cohen70009e42012-10-30 16:48:22 -0700591 protected void reorderStarting() {
592 showOutlinesAndSidePages();
593 }
594
Winson Chungefc49252012-10-26 15:41:27 -0700595 @Override
Jim Millerd6523da2012-10-21 16:47:02 -0700596 protected void onStartReordering() {
597 super.onStartReordering();
Adam Cohen5d47a8d2012-11-03 19:10:56 -0700598 enablePageContentLayers();
Adam Cohen70009e42012-10-30 16:48:22 -0700599 reorderStarting();
Jim Millerd6523da2012-10-21 16:47:02 -0700600 }
601
602 @Override
603 protected void onEndReordering() {
604 super.onEndReordering();
Adam Cohen6fb841f2012-10-24 13:15:38 -0700605 hideOutlinesAndSidePages();
Jim Millerd6523da2012-10-21 16:47:02 -0700606 }
607
Adam Cohen6fb841f2012-10-24 13:15:38 -0700608 void showOutlinesAndSidePages() {
Adam Cohenf9048cd2012-10-27 16:36:10 -0700609 animateOutlinesAndSidePages(true);
610 }
Adam Cohen6fb841f2012-10-24 13:15:38 -0700611
Adam Cohenf9048cd2012-10-27 16:36:10 -0700612 void hideOutlinesAndSidePages() {
613 animateOutlinesAndSidePages(false);
Jim Millerd6523da2012-10-21 16:47:02 -0700614 }
615
Jim Millere5fb5e42013-04-10 16:10:06 -0700616 void updateChildrenContentAlpha(float sidePageAlpha) {
Adam Cohen45adaa72012-11-02 22:00:57 -0700617 int count = getChildCount();
618 for (int i = 0; i < count; i++) {
619 KeyguardWidgetFrame child = getWidgetPageAt(i);
620 if (i != mCurrentPage) {
Jim Millere5fb5e42013-04-10 16:10:06 -0700621 child.setBackgroundAlpha(sidePageAlpha);
Adam Cohen45adaa72012-11-02 22:00:57 -0700622 child.setContentAlpha(0f);
623 } else {
624 child.setBackgroundAlpha(0f);
625 child.setContentAlpha(1f);
626 }
Adam Cohen8a7785c2012-10-29 22:01:33 -0700627 }
628 }
629
Jim Millere5fb5e42013-04-10 16:10:06 -0700630 public void showInitialPageHints() {
631 mShowingInitialHints = true;
632 updateChildrenContentAlpha(KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER);
633 }
634
Adam Cohen8a7785c2012-10-29 22:01:33 -0700635 @Override
Svetoslav Ganova90a18d2012-11-06 15:22:11 -0800636 void setCurrentPage(int currentPage) {
637 super.setCurrentPage(currentPage);
Jim Millere5fb5e42013-04-10 16:10:06 -0700638 updateChildrenContentAlpha(0.0f);
Svetoslav Ganova90a18d2012-11-06 15:22:11 -0800639 updateWidgetFramesImportantForAccessibility();
640 }
641
642 @Override
Adam Cohen8a7785c2012-10-29 22:01:33 -0700643 public void onAttachedToWindow() {
644 super.onAttachedToWindow();
645 mHasMeasure = false;
Adam Cohen8a7785c2012-10-29 22:01:33 -0700646 }
647
Adam Cohen8a7785c2012-10-29 22:01:33 -0700648 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Winson Chung4752e7d2012-11-20 17:06:04 -0800649 mLastWidthMeasureSpec = widthMeasureSpec;
650 mLastHeightMeasureSpec = heightMeasureSpec;
651
Adam Cohen8a7785c2012-10-29 22:01:33 -0700652 int maxChallengeTop = -1;
653 View parent = (View) getParent();
654 boolean challengeShowing = false;
655 // Widget pages need to know where the top of the sliding challenge is so that they
656 // now how big the widget should be when the challenge is up. We compute it here and
657 // then propagate it to each of our children.
658 if (parent.getParent() instanceof SlidingChallengeLayout) {
659 SlidingChallengeLayout scl = (SlidingChallengeLayout) parent.getParent();
660 int top = scl.getMaxChallengeTop();
661
662 // This is a bit evil, but we need to map a coordinate relative to the SCL into a
663 // coordinate relative to our children, hence we subtract the top padding.s
664 maxChallengeTop = top - getPaddingTop();
665 challengeShowing = scl.isChallengeShowing();
Adam Cohen8a7785c2012-10-29 22:01:33 -0700666
Adam Cohen4ddcd572012-11-01 17:36:32 -0700667 int count = getChildCount();
668 for (int i = 0; i < count; i++) {
669 KeyguardWidgetFrame frame = getWidgetPageAt(i);
670 frame.setMaxChallengeTop(maxChallengeTop);
671 // On the very first measure pass, if the challenge is showing, we need to make sure
672 // that the widget on the current page is small.
673 if (challengeShowing && i == mCurrentPage && !mHasMeasure) {
Jim Miller6b0afad2013-10-28 19:08:42 -0700674 frame.shrinkWidget(true);
Adam Cohen4ddcd572012-11-01 17:36:32 -0700675 }
Adam Cohen8a7785c2012-10-29 22:01:33 -0700676 }
677 }
678 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
Adam Cohen4ddcd572012-11-01 17:36:32 -0700679 mHasMeasure = true;
Adam Cohen6fb841f2012-10-24 13:15:38 -0700680 }
681
Adam Cohenf9048cd2012-10-27 16:36:10 -0700682 void animateOutlinesAndSidePages(final boolean show) {
Adam Cohen70009e42012-10-30 16:48:22 -0700683 animateOutlinesAndSidePages(show, -1);
684 }
685
Adam Cohen8caabad2012-11-04 17:23:25 -0800686 public void setWidgetToResetOnPageFadeOut(int widget) {
Adam Cohendb1c5d52012-11-03 17:10:07 -0700687 mWidgetToResetAfterFadeOut = widget;
688 }
689
Adam Cohen8caabad2012-11-04 17:23:25 -0800690 public int getWidgetToResetOnPageFadeOut() {
691 return mWidgetToResetAfterFadeOut;
692 }
693
Adam Cohen70009e42012-10-30 16:48:22 -0700694 void animateOutlinesAndSidePages(final boolean show, int duration) {
Adam Cohenf9048cd2012-10-27 16:36:10 -0700695 if (mChildrenOutlineFadeAnimation != null) {
696 mChildrenOutlineFadeAnimation.cancel();
697 mChildrenOutlineFadeAnimation = null;
698 }
Adam Cohenf9048cd2012-10-27 16:36:10 -0700699 int count = getChildCount();
700 PropertyValuesHolder alpha;
Adam Cohenf9048cd2012-10-27 16:36:10 -0700701 ArrayList<Animator> anims = new ArrayList<Animator>();
Adam Cohen6fb841f2012-10-24 13:15:38 -0700702
Adam Cohen70009e42012-10-30 16:48:22 -0700703 if (duration == -1) {
704 duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION :
705 CHILDREN_OUTLINE_FADE_OUT_DURATION;
706 }
Adam Cohene3643132012-10-28 18:29:17 -0700707
Adam Cohenf9048cd2012-10-27 16:36:10 -0700708 int curPage = getNextPage();
709 for (int i = 0; i < count; i++) {
710 float finalContentAlpha;
711 if (show) {
Adam Cohen2b0501b2012-11-21 16:49:13 -0800712 finalContentAlpha = getAlphaForPage(mScreenCenter, i, true);
Adam Cohenf9048cd2012-10-27 16:36:10 -0700713 } else if (!show && i == curPage) {
714 finalContentAlpha = 1f;
715 } else {
716 finalContentAlpha = 0f;
717 }
Adam Cohenf9048cd2012-10-27 16:36:10 -0700718 KeyguardWidgetFrame child = getWidgetPageAt(i);
Adam Cohen45adaa72012-11-02 22:00:57 -0700719
Adam Cohenf9048cd2012-10-27 16:36:10 -0700720 alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalContentAlpha);
Adam Cohene3643132012-10-28 18:29:17 -0700721 ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha);
Adam Cohenf9048cd2012-10-27 16:36:10 -0700722 anims.add(a);
Adam Cohene3643132012-10-28 18:29:17 -0700723
Adam Cohen2b0501b2012-11-21 16:49:13 -0800724 float finalOutlineAlpha = show ? getOutlineAlphaForPage(mScreenCenter, i, true) : 0f;
Adam Cohene3643132012-10-28 18:29:17 -0700725 child.fadeFrame(this, show, finalOutlineAlpha, duration);
Adam Cohenf9048cd2012-10-27 16:36:10 -0700726 }
727
Adam Cohenf9048cd2012-10-27 16:36:10 -0700728 mChildrenOutlineFadeAnimation = new AnimatorSet();
729 mChildrenOutlineFadeAnimation.playTogether(anims);
730
731 mChildrenOutlineFadeAnimation.setDuration(duration);
732 mChildrenOutlineFadeAnimation.addListener(new AnimatorListenerAdapter() {
733 @Override
Adam Cohen70009e42012-10-30 16:48:22 -0700734 public void onAnimationStart(Animator animation) {
735 if (show) {
Adam Cohen5d47a8d2012-11-03 19:10:56 -0700736 enablePageContentLayers();
Adam Cohen70009e42012-10-30 16:48:22 -0700737 }
738 }
Adam Cohendb1c5d52012-11-03 17:10:07 -0700739
Adam Cohen70009e42012-10-30 16:48:22 -0700740 @Override
Adam Cohenf9048cd2012-10-27 16:36:10 -0700741 public void onAnimationEnd(Animator animation) {
742 if (!show) {
Adam Cohen5d47a8d2012-11-03 19:10:56 -0700743 disablePageContentLayers();
Adam Cohen8caabad2012-11-04 17:23:25 -0800744 KeyguardWidgetFrame frame = getWidgetPageAt(mWidgetToResetAfterFadeOut);
745 if (frame != null && !(frame == getWidgetPageAt(mCurrentPage) &&
746 mViewStateManager.isChallengeOverlapping())) {
747 frame.resetSize();
Adam Cohendb1c5d52012-11-03 17:10:07 -0700748 }
Adam Cohen8caabad2012-11-04 17:23:25 -0800749 mWidgetToResetAfterFadeOut = -1;
Adam Cohen2b0501b2012-11-21 16:49:13 -0800750 mShowingInitialHints = false;
Adam Cohenf9048cd2012-10-27 16:36:10 -0700751 }
Svetoslav Ganova90a18d2012-11-06 15:22:11 -0800752 updateWidgetFramesImportantForAccessibility();
Adam Cohenf9048cd2012-10-27 16:36:10 -0700753 }
754 });
755 mChildrenOutlineFadeAnimation.start();
Jim Millerd6523da2012-10-21 16:47:02 -0700756 }
757
Jim Millerd6523da2012-10-21 16:47:02 -0700758 @Override
759 public boolean onLongClick(View v) {
Winson Chung9dc99232012-10-29 17:43:18 -0700760 // Disallow long pressing to reorder if the challenge is showing
Winson Chung70aa5282012-10-30 10:56:37 -0700761 boolean isChallengeOverlapping = mViewStateManager.isChallengeShowing() &&
762 mViewStateManager.isChallengeOverlapping();
763 if (!isChallengeOverlapping && startReordering()) {
Jim Miller19a52672012-10-23 19:52:04 -0700764 return true;
765 }
766 return false;
Jim Millerd6523da2012-10-21 16:47:02 -0700767 }
Jim Millerbdca3c02012-10-29 19:11:50 -0700768
769 public void removeWidget(View view) {
770 if (view instanceof KeyguardWidgetFrame) {
771 removeView(view);
772 } else {
773 // Assume view was wrapped by a KeyguardWidgetFrame in KeyguardWidgetPager#addWidget().
774 // This supports legacy hard-coded "widgets" like KeyguardTransportControlView.
775 int pos = getWidgetPageIndex(view);
776 if (pos != -1) {
777 KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(pos);
778 frame.removeView(view);
779 removeView(frame);
780 } else {
781 Slog.w(TAG, "removeWidget() can't find:" + view);
782 }
783 }
784 }
785
786 public int getWidgetPageIndex(View view) {
787 if (view instanceof KeyguardWidgetFrame) {
788 return indexOfChild(view);
789 } else {
790 // View was wrapped by a KeyguardWidgetFrame by KeyguardWidgetPager#addWidget()
791 return indexOfChild((KeyguardWidgetFrame)view.getParent());
792 }
793 }
Winson Chungf3b9ec82012-11-01 14:48:51 -0700794
795 @Override
796 protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) {
797 KeyguardWidgetFrame child = getWidgetPageAt(viewIndex);
798 child.setIsHoveringOverDeleteDropTarget(isHovering);
799 }
Winson Chung48275d22012-11-05 10:56:31 -0800800
801 // ChallengeLayout.OnBouncerStateChangedListener
802 @Override
803 public void onBouncerStateChanged(boolean bouncerActive) {
804 if (bouncerActive) {
805 zoomOutToBouncer();
806 } else {
807 zoomInFromBouncer();
808 }
809 }
810
Winson Chung70c2f872012-11-07 21:47:12 -0800811 void setBouncerAnimationDuration(int duration) {
812 mBouncerZoomInOutDuration = duration;
813 }
814
Winson Chung48275d22012-11-05 10:56:31 -0800815 // Zoom in after the bouncer is dismissed
816 void zoomInFromBouncer() {
817 if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
818 mZoomInOutAnim.cancel();
819 }
820 final View currentPage = getPageAt(getCurrentPage());
821 if (currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f) {
822 mZoomInOutAnim = new AnimatorSet();
Winson Chung48275d22012-11-05 10:56:31 -0800823 mZoomInOutAnim.playTogether(
824 ObjectAnimator.ofFloat(currentPage, "scaleX", 1f),
825 ObjectAnimator.ofFloat(currentPage , "scaleY", 1f));
Winson Chung70c2f872012-11-07 21:47:12 -0800826 mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration);
827 mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
Winson Chung48275d22012-11-05 10:56:31 -0800828 mZoomInOutAnim.start();
829 }
John Spurlock0552c5d2012-11-15 08:04:45 -0500830 if (currentPage instanceof KeyguardWidgetFrame) {
831 ((KeyguardWidgetFrame)currentPage).onBouncerShowing(false);
832 }
Winson Chung48275d22012-11-05 10:56:31 -0800833 }
834
835 // Zoom out after the bouncer is initiated
836 void zoomOutToBouncer() {
837 if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) {
838 mZoomInOutAnim.cancel();
839 }
Winson Chung70c2f872012-11-07 21:47:12 -0800840 int curPage = getCurrentPage();
841 View currentPage = getPageAt(curPage);
842 if (shouldSetTopAlignedPivotForWidget(curPage)) {
843 currentPage.setPivotY(0);
844 // Note: we are working around the issue that setting the x-pivot to the same value as it
845 // was does not actually work.
846 currentPage.setPivotX(0);
847 currentPage.setPivotX(currentPage.getMeasuredWidth() / 2);
848 }
Winson Chung48275d22012-11-05 10:56:31 -0800849 if (!(currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f)) {
850 mZoomInOutAnim = new AnimatorSet();
Winson Chung48275d22012-11-05 10:56:31 -0800851 mZoomInOutAnim.playTogether(
852 ObjectAnimator.ofFloat(currentPage, "scaleX", BOUNCER_SCALE_FACTOR),
853 ObjectAnimator.ofFloat(currentPage, "scaleY", BOUNCER_SCALE_FACTOR));
Winson Chung70c2f872012-11-07 21:47:12 -0800854 mZoomInOutAnim.setDuration(mBouncerZoomInOutDuration);
855 mZoomInOutAnim.setInterpolator(new DecelerateInterpolator(1.5f));
Winson Chung48275d22012-11-05 10:56:31 -0800856 mZoomInOutAnim.start();
857 }
John Spurlock0552c5d2012-11-15 08:04:45 -0500858 if (currentPage instanceof KeyguardWidgetFrame) {
859 ((KeyguardWidgetFrame)currentPage).onBouncerShowing(true);
860 }
Winson Chung48275d22012-11-05 10:56:31 -0800861 }
Winson Chung6cf53bb2012-11-05 17:55:42 -0800862
Winson Chung4752e7d2012-11-20 17:06:04 -0800863 void setAddWidgetEnabled(boolean enabled) {
864 if (mAddWidgetView != null && enabled) {
865 addView(mAddWidgetView, 0);
866 // We need to force measure the PagedView so that the calls to update the scroll
867 // position below work
868 measure(mLastWidthMeasureSpec, mLastHeightMeasureSpec);
869 // Bump up the current page to account for the addition of the new page
870 setCurrentPage(mCurrentPage + 1);
871 mAddWidgetView = null;
872 } else if (mAddWidgetView == null && !enabled) {
Jim Miller5ecd8112013-01-09 18:50:26 -0800873 View addWidget = findViewById(R.id.keyguard_add_widget);
Winson Chung4752e7d2012-11-20 17:06:04 -0800874 if (addWidget != null) {
875 mAddWidgetView = addWidget;
876 removeView(addWidget);
877 }
878 }
879 }
880
Winson Chung6cf53bb2012-11-05 17:55:42 -0800881 boolean isAddPage(int pageIndex) {
882 View v = getChildAt(pageIndex);
Jim Miller5ecd8112013-01-09 18:50:26 -0800883 return v != null && v.getId() == R.id.keyguard_add_widget;
Winson Chung6cf53bb2012-11-05 17:55:42 -0800884 }
885
886 boolean isCameraPage(int pageIndex) {
887 View v = getChildAt(pageIndex);
888 return v != null && v instanceof CameraWidgetFrame;
889 }
890
891 @Override
892 protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
893 return !isCameraPage(childIndex) && super.shouldSetTopAlignedPivotForWidget(childIndex);
894 }
Jeff Sharkey06c5f8a2012-12-04 09:53:44 -0800895
896 /**
897 * Search given {@link View} hierarchy for {@link TextClock} instances that
898 * show various time components. Returns combination of
899 * {@link #FLAG_HAS_LOCAL_HOUR} and {@link #FLAG_HAS_LOCAL_MINUTE}.
900 */
901 private static int findClockInHierarchy(View view) {
902 if (view instanceof TextClock) {
903 return getClockFlags((TextClock) view);
904 } else if (view instanceof ViewGroup) {
905 int flags = 0;
906 final ViewGroup group = (ViewGroup) view;
907 final int size = group.getChildCount();
908 for (int i = 0; i < size; i++) {
909 flags |= findClockInHierarchy(group.getChildAt(i));
910 }
911 return flags;
912 } else {
913 return 0;
914 }
915 }
916
917 /**
918 * Return combination of {@link #FLAG_HAS_LOCAL_HOUR} and
919 * {@link #FLAG_HAS_LOCAL_MINUTE} describing the time represented described
920 * by the given {@link TextClock}.
921 */
922 private static int getClockFlags(TextClock clock) {
923 int flags = 0;
924
925 final String timeZone = clock.getTimeZone();
926 if (timeZone != null && !TimeZone.getDefault().equals(TimeZone.getTimeZone(timeZone))) {
927 // Ignore clocks showing another timezone
928 return 0;
929 }
930
931 final CharSequence format = clock.getFormat();
932 final char hour = clock.is24HourModeEnabled() ? DateFormat.HOUR_OF_DAY
933 : DateFormat.HOUR;
934
935 if (DateFormat.hasDesignator(format, hour)) {
936 flags |= FLAG_HAS_LOCAL_HOUR;
937 }
938 if (DateFormat.hasDesignator(format, DateFormat.MINUTE)) {
939 flags |= FLAG_HAS_LOCAL_MINUTE;
940 }
941
942 return flags;
943 }
Jim Millercaf24fc2013-09-10 18:37:01 -0700944
945 public void handleExternalCameraEvent(MotionEvent event) {
946 beginCameraEvent();
947 int cameraPage = getPageCount() - 1;
948 boolean endWarp = false;
Jim Miller8de9e442013-09-20 14:21:50 -0700949 if (isCameraPage(cameraPage) || mCameraEventInProgress) {
Jim Millercaf24fc2013-09-10 18:37:01 -0700950 switch (event.getAction()) {
951 case MotionEvent.ACTION_DOWN:
Jim Miller8de9e442013-09-20 14:21:50 -0700952 // Once we start dispatching camera events, we must continue to do so
953 // to keep event dispatch happy.
954 mCameraEventInProgress = true;
Jim Millercaf24fc2013-09-10 18:37:01 -0700955 userActivity();
Jim Millerc162dd02013-09-25 18:57:43 -0700956 startPageWarp(cameraPage);
Jim Millercaf24fc2013-09-10 18:37:01 -0700957 break;
958 case MotionEvent.ACTION_UP:
959 case MotionEvent.ACTION_CANCEL:
Jim Miller8de9e442013-09-20 14:21:50 -0700960 mCameraEventInProgress = false;
Jim Millerc162dd02013-09-25 18:57:43 -0700961 endWarp = isWarping();
Jim Millercaf24fc2013-09-10 18:37:01 -0700962 break;
963 }
964 dispatchTouchEvent(event);
965 // This has to happen after the event has been handled by the real widget pager
Jim Millerc162dd02013-09-25 18:57:43 -0700966 if (endWarp) stopPageWarp();
Jim Millercaf24fc2013-09-10 18:37:01 -0700967 }
968 endCameraEvent();
969 }
970
Jim Millerdcb3d842012-08-23 19:18:12 -0700971}