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