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