GhostView.java revision 50ac6cb9820da352bd5e89596b17561878e969cc
154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project/*
254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Copyright (C) 2014 The Android Open Source Project
354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project *
454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * you may not use this file except in compliance with the License.
654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * You may obtain a copy of the License at
754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project *
854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project *
1054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * See the License for the specific language governing permissions and
1454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * limitations under the License.
1554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project */
1654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectpackage android.view;
1754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
1854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.graphics.Canvas;
19911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viveretteimport android.graphics.Matrix;
2054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport android.widget.FrameLayout;
21911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
2254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectimport java.util.ArrayList;
2354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
24661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette/**
25911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette * This view draws another View in an Overlay without changing the parent. It will not be drawn
2654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * by its parent because its visibility is set to INVISIBLE, but will be drawn
27661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette * here using its render node. When the GhostView is set to INVISIBLE, the View it is
2854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * shadowing will become VISIBLE and when the GhostView becomes VISIBLE, the shadowed
29c826b7d8fa330970d1ab29fd3b2790a5bc01e26calanv * view becomes INVISIBLE.
3054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project * @hide
31b798689749c64baba81f02e10cf2157c747d6b46The Android Open Source Project */
3254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Projectpublic class GhostView extends View {
331029866a12e04e9db52485e2ec0353e764d15549Adam Powell    private final View mView;
348a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    private int mReferences;
358a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov    private boolean mBeingMoved;
3654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
37911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    private GhostView(View view) {
38911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        super(view.getContext());
3954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        mView = view;
40661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        mView.mGhostView = this;
41661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        final ViewGroup parent = (ViewGroup) mView.getParent();
4254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        setGhostedVisibility(View.INVISIBLE);
43a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        parent.mRecreateDisplayList = true;
44b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        parent.getDisplayList();
45911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
46b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
47911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    @Override
4854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected void onDraw(Canvas canvas) {
49661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (canvas instanceof HardwareCanvas) {
50661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            HardwareCanvas hwCanvas = (HardwareCanvas) canvas;
5154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            mView.mRecreateDisplayList = true;
5254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            RenderNode renderNode = mView.getDisplayList();
5354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            if (renderNode.isValid()) {
5454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                hwCanvas.insertReorderBarrier(); // enable shadow for this rendernode
5554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                hwCanvas.drawRenderNode(renderNode);
5654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                hwCanvas.insertInorderBarrier(); // re-disable reordering/shadows
5754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            }
5854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
5954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
6054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setMatrix(Matrix matrix) {
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mRenderNode.setAnimationMatrix(matrix);
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVisibility(@Visibility int visibility) {
67661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        super.setVisibility(visibility);
6854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (mView.mGhostView == this) {
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int inverseVisibility = (visibility == View.VISIBLE) ? View.INVISIBLE : View.VISIBLE;
70661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            setGhostedVisibility(inverseVisibility);
711029866a12e04e9db52485e2ec0353e764d15549Adam Powell        }
721029866a12e04e9db52485e2ec0353e764d15549Adam Powell    }
731029866a12e04e9db52485e2ec0353e764d15549Adam Powell
741029866a12e04e9db52485e2ec0353e764d15549Adam Powell    private void setGhostedVisibility(int visibility) {
7554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        mView.mViewFlags = (mView.mViewFlags & ~View.VISIBILITY_MASK) | visibility;
7654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
7754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
7854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    @Override
7954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    protected void onDetachedFromWindow() {
8054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        super.onDetachedFromWindow();
8154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (!mBeingMoved) {
8254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            setGhostedVisibility(View.VISIBLE);
83617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette            mView.mGhostView = null;
84617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette            final ViewGroup parent = (ViewGroup) mView.getParent();
85617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette            if (parent != null) {
86617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                parent.mRecreateDisplayList = true;
87617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette                parent.getDisplayList();
88617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette            }
8954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
90617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette    }
91617feb99a06e7ffb3894e86a286bf30e085f321aAlan Viverette
92661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    public static void calculateMatrix(View view, ViewGroup host, Matrix matrix) {
93661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        ViewGroup parent = (ViewGroup) view.getParent();
94661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        matrix.reset();
95661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        parent.transformMatrixToGlobal(matrix);
96b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        matrix.preTranslate(-parent.getScrollX(), -parent.getScrollY());
97b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        host.transformMatrixToLocal(matrix);
98b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette    }
99b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
100b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette    public static GhostView addGhost(View view, ViewGroup viewGroup, Matrix matrix) {
1014f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette        if (!(view.getParent() instanceof ViewGroup)) {
102911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            throw new IllegalArgumentException("Ghosted views must be parented by a ViewGroup");
103a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        }
104911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        ViewGroupOverlay overlay = viewGroup.getOverlay();
105911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        ViewOverlay.OverlayViewGroup overlayViewGroup = overlay.mOverlayViewGroup;
106911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        GhostView ghostView = view.mGhostView;
107661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        int previousRefCount = 0;
108661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (ghostView != null) {
109992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            View oldParent = (View) ghostView.getParent();
110992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy            ViewGroup oldGrandParent = (ViewGroup) oldParent.getParent();
111661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            if (oldGrandParent != overlayViewGroup) {
112661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                previousRefCount = ghostView.mReferences;
11354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                oldGrandParent.removeView(oldParent);
11454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                ghostView = null;
11554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            }
11654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
11754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (ghostView == null) {
11854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            if (matrix == null) {
1191029866a12e04e9db52485e2ec0353e764d15549Adam Powell                matrix = new Matrix();
120b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette                calculateMatrix(view, viewGroup, matrix);
121b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            }
1221029866a12e04e9db52485e2ec0353e764d15549Adam Powell            ghostView = new GhostView(view);
12354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            ghostView.setMatrix(matrix);
12454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            FrameLayout parent = new FrameLayout(view.getContext());
12554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            parent.setClipChildren(false);
1268d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            copySize(viewGroup, parent);
1278d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            copySize(viewGroup, ghostView);
1288d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            parent.addView(ghostView);
1298d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            ArrayList<View> tempViews = new ArrayList<View>();
130661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            int firstGhost = moveGhostViewsToTop(overlay.mOverlayViewGroup, tempViews);
13154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            insertIntoOverlay(overlay.mOverlayViewGroup, parent, ghostView, tempViews, firstGhost);
13254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            ghostView.mReferences = previousRefCount;
13354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        } else if (matrix != null) {
134911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            ghostView.setMatrix(matrix);
1352e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        }
1362e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        ghostView.mReferences++;
1372e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        return ghostView;
1382e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    }
1392e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato
1402e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    public static GhostView addGhost(View view, ViewGroup viewGroup) {
1412e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        return addGhost(view, viewGroup, null);
1422e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    }
1432e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato
144911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    public static void removeGhost(View view) {
14554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        GhostView ghostView = view.mGhostView;
14654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (ghostView != null) {
1470af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio            ghostView.mReferences--;
148e56ffdc7b31b0937628609cc3bbaa15879023569Fabrice Di Meglio            if (ghostView.mReferences == 0) {
1490af4b8b0c8b038bca9b4f60eb81f71e186f471ceFabrice Di Meglio                ViewGroup parent = (ViewGroup) ghostView.getParent();
1508d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler                ViewGroup grandParent = (ViewGroup) parent.getParent();
1518d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler                grandParent.removeView(parent);
1528d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler            }
1538d28c3b3bdab63fab132b81e38d54bc4c132ea8aDaniel Sandler        }
154992cc4282e92c0b7c192247261c54933acab5ad0Romain Guy    }
1552e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato
1562e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    public static GhostView getGhost(View view) {
1572e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        return view.mGhostView;
1582e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    }
1592e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato
1602e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    private static void copySize(View from, View to) {
1612e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        to.setLeft(0);
16254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        to.setTop(0);
163911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        to.setRight(from.getWidth());
16454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        to.setBottom(from.getHeight());
165911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
166911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
16754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
168911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * Move the GhostViews to the end so that they are on top of other views and it is easier
1692e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato     * to do binary search for the correct location for the GhostViews in insertIntoOverlay.
170661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     *
1710283a5573c0a8b239f88147fe4ecf1b379e2f0a4Adam Powell     * @return The index of the first GhostView or -1 if no GhostView is in the ViewGroup
1722e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato     */
1732e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato    private static int moveGhostViewsToTop(ViewGroup viewGroup, ArrayList<View> tempViews) {
1742e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        final int numChildren = viewGroup.getChildCount();
1752e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        if (numChildren == 0) {
1762e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato            return -1;
1772e585f7e22efef11dc6af36acfbf1c3040d6a511Joe Onorato        } else if (isGhostWrapper(viewGroup.getChildAt(numChildren - 1))) {
17854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            // GhostViews are already at the end
17954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            int firstGhost = numChildren - 1;
18054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            for (int i = numChildren - 2; i >= 0; i--) {
1813004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell                if (!isGhostWrapper(viewGroup.getChildAt(i))) {
1823004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell                    break;
1833004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell                }
1843004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell                firstGhost = i;
1853004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell            }
1863004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell            return firstGhost;
1873004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell        }
1883004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell
1893004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell        // Remove all GhostViews from the middle
1903004cc50f22e724efb791aa80e9d6c566d2ddb5dAdam Powell        for (int i = numChildren - 2; i >= 0; i--) {
1914f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette            View child = viewGroup.getChildAt(i);
192b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            if (isGhostWrapper(child)) {
193911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                tempViews.add(child);
194911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                GhostView ghostView = (GhostView)((ViewGroup)child).getChildAt(0);
195911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                ghostView.mBeingMoved = true;
196a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette                viewGroup.removeViewAt(i);
197911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                ghostView.mBeingMoved = false;
198911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            }
199911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        }
200911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
201a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        final int firstGhost;
202a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        if (tempViews.isEmpty()) {
203911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            firstGhost = -1;
204a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        } else {
205a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette            firstGhost = viewGroup.getChildCount();
206911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            // Add the GhostViews to the end
207911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            for (int i = tempViews.size() - 1; i >= 0; i--) {
208911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                viewGroup.addView(tempViews.get(i));
209911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            }
210911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            tempViews.clear();
211911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        }
212b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        return firstGhost;
213b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette    }
214911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
215911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    /**
216a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette     * Inserts a GhostView into the overlay's ViewGroup in the order in which they
217911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     * should be displayed by the UI.
218911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     */
219a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette    private static void insertIntoOverlay(ViewGroup viewGroup, ViewGroup wrapper,
220a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette            GhostView ghostView, ArrayList<View> tempParents, int firstGhost) {
221911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        if (firstGhost == -1) {
222911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            viewGroup.addView(wrapper);
223911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        } else {
224911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            ArrayList<View> viewParents = new ArrayList<View>();
225a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette            getParents(ghostView.mView, viewParents);
226b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
227911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            int index = getInsertIndex(viewGroup, viewParents, tempParents, firstGhost);
228911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            if (index < 0 || index >= viewGroup.getChildCount()) {
229911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                viewGroup.addView(wrapper);
2304f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette            } else {
231911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                viewGroup.addView(wrapper, index);
2324f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette            }
233a426445dfdab43886dd894f2ba8a1d55bfcbb278Alan Viverette        }
234911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
235911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
2364f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette    /**
237b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     * Find the index into the overlay to insert the GhostView based on the order that the
2384f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * views should be drawn. This keeps GhostViews layered in the same order
2394f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette     * that they are ordered in the UI.
240911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette     */
241911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    private static int getInsertIndex(ViewGroup overlayViewGroup, ArrayList<View> viewParents,
242911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            ArrayList<View> tempParents, int firstGhost) {
243b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        int low = firstGhost;
244b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        int high = overlayViewGroup.getChildCount() - 1;
245b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
246911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        while (low <= high) {
247911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            int mid = (low + high) / 2;
2484f64c048505a432e549ccb756634ecebf28f9e80Alan Viverette            ViewGroup wrapper = (ViewGroup) overlayViewGroup.getChildAt(mid);
249911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            GhostView midView = (GhostView) wrapper.getChildAt(0);
250911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            getParents(midView.mView, tempParents);
251911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            if (isOnTop(viewParents, tempParents)) {
252911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                low = mid + 1;
253911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            } else {
254911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette                high = mid - 1;
255911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette            }
256b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette            tempParents.clear();
257911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        }
258b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
259b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette        return low;
260b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette    }
261b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette
262b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette    /**
263b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     * Returns true if view is a GhostView's FrameLayout wrapper.
264b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette     */
265b56f5d2ab18f881eb075b698e9ce1b4a4a09ff64Alan Viverette    private static boolean isGhostWrapper(View view) {
266d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette        if (view instanceof FrameLayout) {
267d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette            FrameLayout frameLayout = (FrameLayout) view;
268d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette            if (frameLayout.getChildCount() == 1) {
269d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette                View child = frameLayout.getChildAt(0);
270d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette                return child instanceof GhostView;
271d5133792391443521dc15f7da7de5d280e6703ddAlan Viverette            }
272911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        }
273911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette        return false;
274911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette    }
275911743652b597057a1bd7ef8a921e9ff8dce0f4aAlan Viverette
27654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    /**
27754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * Returns true if viewParents is from a View that is on top of the comparedWith's view.
27854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * The ArrayLists contain the ancestors of views in order from top most grandparent, to
27954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * the view itself, in order. The goal is to find the first matching parent and then
28054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     * compare the draw order of the siblings.
28154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project     */
28254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    private static boolean isOnTop(ArrayList<View> viewParents, ArrayList<View> comparedWith) {
28354b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (viewParents.isEmpty() || comparedWith.isEmpty() ||
28454b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project                viewParents.get(0) != comparedWith.get(0)) {
285661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            // Not the same decorView -- arbitrary ordering
28654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            return true;
28754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
28854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        int depth = Math.min(viewParents.size(), comparedWith.size());
28954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        for (int i = 1; i < depth; i++) {
29054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            View viewParent = viewParents.get(i);
29154b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            View comparedWithParent = comparedWith.get(i);
29254b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (viewParent != comparedWithParent) {
294661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                // i - 1 is the same parent, but these are different children.
295661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                return isOnTop(viewParent, comparedWithParent);
296661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            }
297661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
298661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
299661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        // one of these is the parent of the other
300661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        boolean isComparedWithTheParent = (comparedWith.size() == depth);
301661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        return isComparedWithTheParent;
302661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    }
303661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
304661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    /**
305661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     * Adds all the parents, grandparents, etc. of view to parents.
306661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette     */
307661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette    private static void getParents(View view, ArrayList<View> parents) {
308661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        ViewParent parent = view.getParent();
309661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        if (parent != null && parent instanceof ViewGroup) {
310661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            getParents((View) parent, parents);
311661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        }
312661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette        parents.add(view);
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
314661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Returns true if view would be drawn on top of comparedWith or false otherwise.
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * view and comparedWith are siblings with the same parent. This uses the logic
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * that dispatchDraw uses to determine which View should be drawn first.
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean isOnTop(View view, View comparedWith) {
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ViewGroup parent = (ViewGroup) view.getParent();
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int childrenCount = parent.getChildCount();
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<View> preorderedList = parent.buildOrderedChildList();
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final boolean customOrder = preorderedList == null
326661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette                && parent.isChildrenDrawingOrderEnabled();
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // This default value shouldn't be used because both view and comparedWith
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // should be in the list. If there is an error, then just return an arbitrary
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // view is on top.
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean isOnTop = true;
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < childrenCount; i++) {
333661e63658da39cccfe49a129e4860455716ff3c9Alan Viverette            int childIndex = customOrder ? parent.getChildDrawingOrder(childrenCount, i) : i;
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final View child = (preorderedList == null)
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ? parent.getChildAt(childIndex) : preorderedList.get(childIndex);
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (child == view) {
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                isOnTop = false;
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (child == comparedWith) {
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                isOnTop = true;
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34554b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        if (preorderedList != null) {
34654b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project            preorderedList.clear();
34754b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        }
34854b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project        return isOnTop;
34954b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project    }
35054b6cfa9a9e5b861a9930af873580d6dc20f773The Android Open Source Project}
351e213677037f836529efcc0ac201fc61dd95481c5Dianne Hackborn