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