KeyguardWidgetPager.java revision 6cf53bb3a94ec5a6eebc96a315dac32d042f1945
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.animation.TimeInterpolator; 24import android.appwidget.AppWidgetHostView; 25import android.appwidget.AppWidgetProviderInfo; 26import android.content.Context; 27import android.content.res.Resources; 28import android.os.Handler; 29import android.os.HandlerThread; 30import android.util.AttributeSet; 31import android.util.Slog; 32import android.view.Gravity; 33import android.view.MotionEvent; 34import android.view.View; 35import android.view.View.OnLongClickListener; 36import android.view.ViewGroup; 37import android.view.accessibility.AccessibilityEvent; 38import android.view.accessibility.AccessibilityManager; 39import android.widget.FrameLayout; 40 41import com.android.internal.R; 42import com.android.internal.widget.LockPatternUtils; 43 44import java.util.ArrayList; 45 46public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener, 47 OnLongClickListener, ChallengeLayout.OnBouncerStateChangedListener { 48 49 ZInterpolator mZInterpolator = new ZInterpolator(0.5f); 50 private static float CAMERA_DISTANCE = 10000; 51 protected static float OVERSCROLL_MAX_ROTATION = 30; 52 private static final boolean PERFORM_OVERSCROLL_ROTATION = true; 53 54 protected KeyguardViewStateManager mViewStateManager; 55 private LockPatternUtils mLockPatternUtils; 56 57 // Related to the fading in / out background outlines 58 public static final int CHILDREN_OUTLINE_FADE_OUT_DURATION = 375; 59 public static final int CHILDREN_OUTLINE_FADE_IN_DURATION = 100; 60 protected AnimatorSet mChildrenOutlineFadeAnimation; 61 protected int mScreenCenter; 62 private boolean mHasMeasure = false; 63 boolean showHintsAfterLayout = false; 64 65 private static final long CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT = 30000; 66 private static final String TAG = "KeyguardWidgetPager"; 67 private boolean mCenterSmallWidgetsVertically; 68 69 private int mPage = 0; 70 private Callbacks mCallbacks; 71 72 private boolean mCameraWidgetEnabled; 73 74 private int mWidgetToResetAfterFadeOut; 75 76 // Bouncer 77 protected int BOUNCER_ZOOM_IN_OUT_DURATION = 250; 78 private float BOUNCER_SCALE_FACTOR = 0.67f; 79 80 // Background worker thread: used here for persistence, also made available to widget frames 81 private final HandlerThread mBackgroundWorkerThread; 82 private final Handler mBackgroundWorkerHandler; 83 84 public KeyguardWidgetPager(Context context, AttributeSet attrs) { 85 this(context, attrs, 0); 86 } 87 88 public KeyguardWidgetPager(Context context) { 89 this(null, null, 0); 90 } 91 92 public KeyguardWidgetPager(Context context, AttributeSet attrs, int defStyle) { 93 super(context, attrs, defStyle); 94 if (getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 95 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); 96 } 97 98 setPageSwitchListener(this); 99 100 Resources r = getResources(); 101 mCameraWidgetEnabled = r.getBoolean(R.bool.kg_enable_camera_default_widget); 102 mCenterSmallWidgetsVertically = 103 r.getBoolean(com.android.internal.R.bool.kg_center_small_widgets_vertically); 104 mBackgroundWorkerThread = new HandlerThread("KeyguardWidgetPager Worker"); 105 mBackgroundWorkerThread.start(); 106 mBackgroundWorkerHandler = new Handler(mBackgroundWorkerThread.getLooper()); 107 } 108 109 @Override 110 protected void onDetachedFromWindow() { 111 super.onDetachedFromWindow(); 112 113 // Clean up the worker thread 114 mBackgroundWorkerThread.quit(); 115 } 116 117 public void setViewStateManager(KeyguardViewStateManager viewStateManager) { 118 mViewStateManager = viewStateManager; 119 } 120 121 public void setLockPatternUtils(LockPatternUtils l) { 122 mLockPatternUtils = l; 123 } 124 125 @Override 126 public void onPageSwitching(View newPage, int newPageIndex) { 127 if (mViewStateManager != null) { 128 mViewStateManager.onPageSwitching(newPage, newPageIndex); 129 } 130 } 131 132 @Override 133 public void onPageSwitched(View newPage, int newPageIndex) { 134 boolean showingStatusWidget = false; 135 if (newPage instanceof ViewGroup) { 136 ViewGroup vg = (ViewGroup) newPage; 137 if (vg.getChildAt(0) instanceof KeyguardStatusView) { 138 showingStatusWidget = true; 139 } 140 } 141 142 // Disable the status bar clock if we're showing the default status widget 143 if (showingStatusWidget) { 144 setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK); 145 } else { 146 setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK); 147 } 148 149 // Extend the display timeout if the user switches pages 150 if (mPage != newPageIndex) { 151 int oldPageIndex = mPage; 152 mPage = newPageIndex; 153 userActivity(); 154 KeyguardWidgetFrame oldWidgetPage = getWidgetPageAt(oldPageIndex); 155 if (oldWidgetPage != null) { 156 oldWidgetPage.onActive(false); 157 } 158 KeyguardWidgetFrame newWidgetPage = getWidgetPageAt(newPageIndex); 159 if (newWidgetPage != null) { 160 newWidgetPage.onActive(true); 161 newWidgetPage.requestAccessibilityFocus(); 162 } 163 if (mParent != null && AccessibilityManager.getInstance(mContext).isEnabled()) { 164 AccessibilityEvent event = AccessibilityEvent.obtain( 165 AccessibilityEvent.TYPE_VIEW_SCROLLED); 166 onInitializeAccessibilityEvent(event); 167 onPopulateAccessibilityEvent(event); 168 mParent.requestSendAccessibilityEvent(this, event); 169 } 170 } 171 if (mViewStateManager != null) { 172 mViewStateManager.onPageSwitched(newPage, newPageIndex); 173 } 174 } 175 176 @Override 177 public void sendAccessibilityEvent(int eventType) { 178 if (eventType != AccessibilityEvent.TYPE_VIEW_SCROLLED || isPageMoving()) { 179 super.sendAccessibilityEvent(eventType); 180 } 181 } 182 183 private void userActivity() { 184 if (mCallbacks != null) { 185 mCallbacks.onUserActivityTimeoutChanged(); 186 mCallbacks.userActivity(); 187 } 188 } 189 190 @Override 191 public boolean onTouchEvent(MotionEvent ev) { 192 return captureUserInteraction(ev) || super.onTouchEvent(ev); 193 } 194 195 @Override 196 public boolean onInterceptTouchEvent(MotionEvent ev) { 197 return captureUserInteraction(ev) || super.onInterceptTouchEvent(ev); 198 } 199 200 private boolean captureUserInteraction(MotionEvent ev) { 201 KeyguardWidgetFrame currentWidgetPage = getWidgetPageAt(getCurrentPage()); 202 return currentWidgetPage != null && currentWidgetPage.onUserInteraction(ev); 203 } 204 205 public void showPagingFeedback() { 206 // Nothing yet. 207 } 208 209 public long getUserActivityTimeout() { 210 View page = getPageAt(mPage); 211 if (page instanceof ViewGroup) { 212 ViewGroup vg = (ViewGroup) page; 213 View view = vg.getChildAt(0); 214 if (!(view instanceof KeyguardStatusView) 215 && !(view instanceof KeyguardMultiUserSelectorView)) { 216 return CUSTOM_WIDGET_USER_ACTIVITY_TIMEOUT; 217 } 218 } 219 return -1; 220 } 221 222 public void setCallbacks(Callbacks callbacks) { 223 mCallbacks = callbacks; 224 } 225 226 public interface Callbacks { 227 public void userActivity(); 228 public void onUserActivityTimeoutChanged(); 229 } 230 231 public void addWidget(View widget) { 232 addWidget(widget, -1); 233 } 234 235 236 public void onRemoveView(View v) { 237 final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId(); 238 mBackgroundWorkerHandler.post(new Runnable() { 239 @Override 240 public void run() { 241 mLockPatternUtils.removeAppWidget(appWidgetId); 242 } 243 }); 244 } 245 246 public void onAddView(View v, final int index) { 247 final int appWidgetId = ((KeyguardWidgetFrame) v).getContentAppWidgetId(); 248 final int[] pagesRange = new int[mTempVisiblePagesRange.length]; 249 getVisiblePages(pagesRange); 250 boundByReorderablePages(true, pagesRange); 251 // Subtract from the index to take into account pages before the reorderable 252 // pages (e.g. the "add widget" page) 253 mBackgroundWorkerHandler.post(new Runnable() { 254 @Override 255 public void run() { 256 mLockPatternUtils.addAppWidget(appWidgetId, index - pagesRange[0]); 257 } 258 }); 259 } 260 261 /* 262 * We wrap widgets in a special frame which handles drawing the over scroll foreground. 263 */ 264 public void addWidget(View widget, int pageIndex) { 265 KeyguardWidgetFrame frame; 266 // All views contained herein should be wrapped in a KeyguardWidgetFrame 267 if (!(widget instanceof KeyguardWidgetFrame)) { 268 frame = new KeyguardWidgetFrame(getContext()); 269 FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, 270 LayoutParams.MATCH_PARENT); 271 lp.gravity = Gravity.TOP; 272 273 // The framework adds a default padding to AppWidgetHostView. We don't need this padding 274 // for the Keyguard, so we override it to be 0. 275 widget.setPadding(0, 0, 0, 0); 276 frame.addView(widget, lp); 277 278 // We set whether or not this widget supports vertical resizing. 279 if (widget instanceof AppWidgetHostView) { 280 AppWidgetHostView awhv = (AppWidgetHostView) widget; 281 AppWidgetProviderInfo info = awhv.getAppWidgetInfo(); 282 if ((info.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) { 283 frame.setWidgetLockedSmall(false); 284 } else { 285 // Lock the widget to be small. 286 frame.setWidgetLockedSmall(true); 287 if (mCenterSmallWidgetsVertically) { 288 lp.gravity = Gravity.CENTER; 289 } 290 } 291 } 292 } else { 293 frame = (KeyguardWidgetFrame) widget; 294 } 295 296 ViewGroup.LayoutParams pageLp = new ViewGroup.LayoutParams( 297 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); 298 frame.setOnLongClickListener(this); 299 frame.setWorkerHandler(mBackgroundWorkerHandler); 300 301 if (pageIndex == -1) { 302 addView(frame, pageLp); 303 } else { 304 addView(frame, pageIndex, pageLp); 305 } 306 307 // Update the frame content description. 308 View content = (widget == frame) ? frame.getContent() : widget; 309 if (content != null) { 310 String contentDescription = mContext.getString( 311 com.android.internal.R.string.keyguard_accessibility_widget, 312 content.getContentDescription()); 313 frame.setContentDescription(contentDescription); 314 } 315 } 316 317 /** 318 * Use addWidget() instead. 319 * @deprecated 320 */ 321 @Override 322 public void addView(View child, int index) { 323 enforceKeyguardWidgetFrame(child); 324 super.addView(child, index); 325 } 326 327 /** 328 * Use addWidget() instead. 329 * @deprecated 330 */ 331 @Override 332 public void addView(View child, int width, int height) { 333 enforceKeyguardWidgetFrame(child); 334 super.addView(child, width, height); 335 } 336 337 /** 338 * Use addWidget() instead. 339 * @deprecated 340 */ 341 @Override 342 public void addView(View child, LayoutParams params) { 343 enforceKeyguardWidgetFrame(child); 344 super.addView(child, params); 345 } 346 347 /** 348 * Use addWidget() instead. 349 * @deprecated 350 */ 351 @Override 352 public void addView(View child, int index, LayoutParams params) { 353 enforceKeyguardWidgetFrame(child); 354 super.addView(child, index, params); 355 } 356 357 private void enforceKeyguardWidgetFrame(View child) { 358 if (!(child instanceof KeyguardWidgetFrame)) { 359 throw new IllegalArgumentException( 360 "KeyguardWidgetPager children must be KeyguardWidgetFrames"); 361 } 362 } 363 364 public KeyguardWidgetFrame getWidgetPageAt(int index) { 365 // This is always a valid cast as we've guarded the ability to 366 return (KeyguardWidgetFrame) getChildAt(index); 367 } 368 369 protected void onUnhandledTap(MotionEvent ev) { 370 showPagingFeedback(); 371 } 372 373 @Override 374 protected void onPageBeginMoving() { 375 if (mViewStateManager != null) { 376 mViewStateManager.onPageBeginMoving(); 377 } 378 if (!isReordering(false)) { 379 showOutlinesAndSidePages(); 380 } 381 userActivity(); 382 } 383 384 @Override 385 protected void onPageEndMoving() { 386 if (mViewStateManager != null) { 387 mViewStateManager.onPageEndMoving(); 388 } 389 390 // In the reordering case, the pages will be faded appropriately on completion 391 // of the zoom in animation. 392 if (!isReordering(false)) { 393 hideOutlinesAndSidePages(); 394 } 395 } 396 397 protected void enablePageContentLayers() { 398 int children = getChildCount(); 399 for (int i = 0; i < children; i++) { 400 getWidgetPageAt(i).enableHardwareLayersForContent(); 401 } 402 } 403 404 protected void disablePageContentLayers() { 405 int children = getChildCount(); 406 for (int i = 0; i < children; i++) { 407 getWidgetPageAt(i).disableHardwareLayersForContent(); 408 } 409 } 410 411 /* 412 * This interpolator emulates the rate at which the perceived scale of an object changes 413 * as its distance from a camera increases. When this interpolator is applied to a scale 414 * animation on a view, it evokes the sense that the object is shrinking due to moving away 415 * from the camera. 416 */ 417 static class ZInterpolator implements TimeInterpolator { 418 private float focalLength; 419 420 public ZInterpolator(float foc) { 421 focalLength = foc; 422 } 423 424 public float getInterpolation(float input) { 425 return (1.0f - focalLength / (focalLength + input)) / 426 (1.0f - focalLength / (focalLength + 1.0f)); 427 } 428 } 429 430 @Override 431 protected void overScroll(float amount) { 432 acceleratedOverScroll(amount); 433 } 434 435 float backgroundAlphaInterpolator(float r) { 436 return Math.min(1f, r); 437 } 438 439 private void updatePageAlphaValues(int screenCenter) { 440 } 441 442 public float getAlphaForPage(int screenCenter, int index) { 443 return 1f; 444 } 445 446 public float getOutlineAlphaForPage(int screenCenter, int index) { 447 return getAlphaForPage(screenCenter, index) * KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER; 448 } 449 450 protected boolean isOverScrollChild(int index, float scrollProgress) { 451 boolean isInOverscroll = mOverScrollX < 0 || mOverScrollX > mMaxScrollX; 452 return (isInOverscroll && (index == 0 && scrollProgress < 0 || 453 index == getChildCount() - 1 && scrollProgress > 0)); 454 } 455 456 @Override 457 protected void screenScrolled(int screenCenter) { 458 mScreenCenter = screenCenter; 459 updatePageAlphaValues(screenCenter); 460 for (int i = 0; i < getChildCount(); i++) { 461 KeyguardWidgetFrame v = getWidgetPageAt(i); 462 if (v == mDragView) continue; 463 if (v != null) { 464 float scrollProgress = getScrollProgress(screenCenter, v, i); 465 466 v.setCameraDistance(mDensity * CAMERA_DISTANCE); 467 468 if (isOverScrollChild(i, scrollProgress) && PERFORM_OVERSCROLL_ROTATION) { 469 v.setRotationY(- OVERSCROLL_MAX_ROTATION * scrollProgress); 470 v.setOverScrollAmount(Math.abs(scrollProgress), scrollProgress < 0); 471 } else { 472 v.setRotationY(0f); 473 v.setOverScrollAmount(0, false); 474 } 475 476 float alpha = v.getAlpha(); 477 // If the view has 0 alpha, we set it to be invisible so as to prevent 478 // it from accepting touches 479 if (alpha == 0) { 480 v.setVisibility(INVISIBLE); 481 } else if (v.getVisibility() != VISIBLE) { 482 v.setVisibility(VISIBLE); 483 } 484 } 485 } 486 } 487 488 @Override 489 void boundByReorderablePages(boolean isReordering, int[] range) { 490 if (isReordering) { 491 if (isAddWidgetPageVisible()) { 492 range[0]++; 493 } 494 if (isMusicWidgetVisible()) { 495 range[1]--; 496 } 497 if (isCameraWidgetVisible()) { 498 range[1]--; 499 } 500 } 501 } 502 503 /* 504 * Special widgets 505 */ 506 boolean isAddWidgetPageVisible() { 507 // TODO: Make proper test once we decide whether the add-page is always showing 508 return true; 509 } 510 boolean isMusicWidgetVisible() { 511 return mViewStateManager.getTransportState() != KeyguardViewStateManager.TRANSPORT_GONE; 512 } 513 boolean isCameraWidgetVisible() { 514 return mCameraWidgetEnabled; 515 } 516 517 protected void reorderStarting() { 518 showOutlinesAndSidePages(); 519 } 520 521 @Override 522 protected void onStartReordering() { 523 super.onStartReordering(); 524 enablePageContentLayers(); 525 reorderStarting(); 526 } 527 528 @Override 529 protected void onEndReordering() { 530 super.onEndReordering(); 531 hideOutlinesAndSidePages(); 532 } 533 534 void showOutlinesAndSidePages() { 535 animateOutlinesAndSidePages(true); 536 } 537 538 void hideOutlinesAndSidePages() { 539 animateOutlinesAndSidePages(false); 540 } 541 542 public void showInitialPageHints() { 543 int count = getChildCount(); 544 for (int i = 0; i < count; i++) { 545 KeyguardWidgetFrame child = getWidgetPageAt(i); 546 if (i != mCurrentPage) { 547 child.fadeFrame(this, true, KeyguardWidgetFrame.OUTLINE_ALPHA_MULTIPLIER, 548 CHILDREN_OUTLINE_FADE_IN_DURATION); 549 child.setContentAlpha(0f); 550 } else { 551 child.setBackgroundAlpha(0f); 552 child.setContentAlpha(1f); 553 } 554 } 555 } 556 557 public void showSidePageHints() { 558 animateOutlinesAndSidePages(true, -1); 559 } 560 561 @Override 562 public void onAttachedToWindow() { 563 super.onAttachedToWindow(); 564 mHasMeasure = false; 565 } 566 567 @Override 568 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 569 super.onLayout(changed, left, top, right, bottom); 570 } 571 572 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 573 int maxChallengeTop = -1; 574 View parent = (View) getParent(); 575 boolean challengeShowing = false; 576 // Widget pages need to know where the top of the sliding challenge is so that they 577 // now how big the widget should be when the challenge is up. We compute it here and 578 // then propagate it to each of our children. 579 if (parent.getParent() instanceof SlidingChallengeLayout) { 580 SlidingChallengeLayout scl = (SlidingChallengeLayout) parent.getParent(); 581 int top = scl.getMaxChallengeTop(); 582 583 // This is a bit evil, but we need to map a coordinate relative to the SCL into a 584 // coordinate relative to our children, hence we subtract the top padding.s 585 maxChallengeTop = top - getPaddingTop(); 586 challengeShowing = scl.isChallengeShowing(); 587 588 int count = getChildCount(); 589 for (int i = 0; i < count; i++) { 590 KeyguardWidgetFrame frame = getWidgetPageAt(i); 591 frame.setMaxChallengeTop(maxChallengeTop); 592 // On the very first measure pass, if the challenge is showing, we need to make sure 593 // that the widget on the current page is small. 594 if (challengeShowing && i == mCurrentPage && !mHasMeasure) { 595 frame.shrinkWidget(); 596 } 597 } 598 } 599 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 600 mHasMeasure = true; 601 } 602 603 void animateOutlinesAndSidePages(final boolean show) { 604 animateOutlinesAndSidePages(show, -1); 605 } 606 607 public void setWidgetToResetOnPageFadeOut(int widget) { 608 mWidgetToResetAfterFadeOut = widget; 609 } 610 611 public int getWidgetToResetOnPageFadeOut() { 612 return mWidgetToResetAfterFadeOut; 613 } 614 615 void animateOutlinesAndSidePages(final boolean show, int duration) { 616 if (mChildrenOutlineFadeAnimation != null) { 617 mChildrenOutlineFadeAnimation.cancel(); 618 mChildrenOutlineFadeAnimation = null; 619 } 620 int count = getChildCount(); 621 PropertyValuesHolder alpha; 622 ArrayList<Animator> anims = new ArrayList<Animator>(); 623 624 if (duration == -1) { 625 duration = show ? CHILDREN_OUTLINE_FADE_IN_DURATION : 626 CHILDREN_OUTLINE_FADE_OUT_DURATION; 627 } 628 629 int curPage = getNextPage(); 630 for (int i = 0; i < count; i++) { 631 float finalContentAlpha; 632 if (show) { 633 finalContentAlpha = getAlphaForPage(mScreenCenter, i); 634 } else if (!show && i == curPage) { 635 finalContentAlpha = 1f; 636 } else { 637 finalContentAlpha = 0f; 638 } 639 KeyguardWidgetFrame child = getWidgetPageAt(i); 640 641 alpha = PropertyValuesHolder.ofFloat("contentAlpha", finalContentAlpha); 642 ObjectAnimator a = ObjectAnimator.ofPropertyValuesHolder(child, alpha); 643 anims.add(a); 644 645 float finalOutlineAlpha = show ? getOutlineAlphaForPage(mScreenCenter, i) : 0f; 646 child.fadeFrame(this, show, finalOutlineAlpha, duration); 647 } 648 649 mChildrenOutlineFadeAnimation = new AnimatorSet(); 650 mChildrenOutlineFadeAnimation.playTogether(anims); 651 652 mChildrenOutlineFadeAnimation.setDuration(duration); 653 mChildrenOutlineFadeAnimation.addListener(new AnimatorListenerAdapter() { 654 @Override 655 public void onAnimationStart(Animator animation) { 656 if (show) { 657 enablePageContentLayers(); 658 } 659 } 660 661 @Override 662 public void onAnimationEnd(Animator animation) { 663 if (!show) { 664 disablePageContentLayers(); 665 KeyguardWidgetFrame frame = getWidgetPageAt(mWidgetToResetAfterFadeOut); 666 if (frame != null && !(frame == getWidgetPageAt(mCurrentPage) && 667 mViewStateManager.isChallengeOverlapping())) { 668 frame.resetSize(); 669 } 670 mWidgetToResetAfterFadeOut = -1; 671 } 672 } 673 }); 674 mChildrenOutlineFadeAnimation.start(); 675 } 676 677 @Override 678 public boolean onLongClick(View v) { 679 // Disallow long pressing to reorder if the challenge is showing 680 boolean isChallengeOverlapping = mViewStateManager.isChallengeShowing() && 681 mViewStateManager.isChallengeOverlapping(); 682 if (!isChallengeOverlapping && startReordering()) { 683 return true; 684 } 685 return false; 686 } 687 688 public void removeWidget(View view) { 689 if (view instanceof KeyguardWidgetFrame) { 690 removeView(view); 691 } else { 692 // Assume view was wrapped by a KeyguardWidgetFrame in KeyguardWidgetPager#addWidget(). 693 // This supports legacy hard-coded "widgets" like KeyguardTransportControlView. 694 int pos = getWidgetPageIndex(view); 695 if (pos != -1) { 696 KeyguardWidgetFrame frame = (KeyguardWidgetFrame) getChildAt(pos); 697 frame.removeView(view); 698 removeView(frame); 699 } else { 700 Slog.w(TAG, "removeWidget() can't find:" + view); 701 } 702 } 703 } 704 705 public int getWidgetPageIndex(View view) { 706 if (view instanceof KeyguardWidgetFrame) { 707 return indexOfChild(view); 708 } else { 709 // View was wrapped by a KeyguardWidgetFrame by KeyguardWidgetPager#addWidget() 710 return indexOfChild((KeyguardWidgetFrame)view.getParent()); 711 } 712 } 713 714 @Override 715 protected void setPageHoveringOverDeleteDropTarget(int viewIndex, boolean isHovering) { 716 KeyguardWidgetFrame child = getWidgetPageAt(viewIndex); 717 child.setIsHoveringOverDeleteDropTarget(isHovering); 718 } 719 720 // ChallengeLayout.OnBouncerStateChangedListener 721 @Override 722 public void onBouncerStateChanged(boolean bouncerActive) { 723 if (bouncerActive) { 724 zoomOutToBouncer(); 725 } else { 726 zoomInFromBouncer(); 727 } 728 } 729 730 // Zoom in after the bouncer is dismissed 731 void zoomInFromBouncer() { 732 if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) { 733 mZoomInOutAnim.cancel(); 734 } 735 final View currentPage = getPageAt(getCurrentPage()); 736 if (currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f) { 737 mZoomInOutAnim = new AnimatorSet(); 738 mZoomInOutAnim.setDuration(BOUNCER_ZOOM_IN_OUT_DURATION); 739 mZoomInOutAnim.playTogether( 740 ObjectAnimator.ofFloat(currentPage, "scaleX", 1f), 741 ObjectAnimator.ofFloat(currentPage , "scaleY", 1f)); 742 mZoomInOutAnim.start(); 743 } 744 } 745 746 // Zoom out after the bouncer is initiated 747 void zoomOutToBouncer() { 748 if (mZoomInOutAnim != null && mZoomInOutAnim.isRunning()) { 749 mZoomInOutAnim.cancel(); 750 } 751 View currentPage = getPageAt(getCurrentPage()); 752 if (!(currentPage.getScaleX() < 1f || currentPage.getScaleY() < 1f)) { 753 mZoomInOutAnim = new AnimatorSet(); 754 mZoomInOutAnim.setDuration(BOUNCER_ZOOM_IN_OUT_DURATION); 755 mZoomInOutAnim.playTogether( 756 ObjectAnimator.ofFloat(currentPage, "scaleX", BOUNCER_SCALE_FACTOR), 757 ObjectAnimator.ofFloat(currentPage, "scaleY", BOUNCER_SCALE_FACTOR)); 758 mZoomInOutAnim.start(); 759 } 760 } 761 762 boolean isAddPage(int pageIndex) { 763 View v = getChildAt(pageIndex); 764 return v != null && v.getId() == R.id.keyguard_add_widget; 765 } 766 767 boolean isCameraPage(int pageIndex) { 768 View v = getChildAt(pageIndex); 769 return v != null && v instanceof CameraWidgetFrame; 770 } 771 772 @Override 773 protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) { 774 return !isCameraPage(childIndex) && super.shouldSetTopAlignedPivotForWidget(childIndex); 775 } 776} 777