[go: nahoru, domu]

1807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount/*
2807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * Copyright (C) 2014 The Android Open Source Project
3807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount *
4807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * Licensed under the Apache License, Version 2.0 (the "License");
5807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * you may not use this file except in compliance with the License.
6807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * You may obtain a copy of the License at
7807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount *
8807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount *      http://www.apache.org/licenses/LICENSE-2.0
9807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount *
10807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * Unless required by applicable law or agreed to in writing, software
11807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * distributed under the License is distributed on an "AS IS" BASIS,
12807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * See the License for the specific language governing permissions and
14807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * limitations under the License.
15807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount */
16807e40c55cd74004ecc2392f8655fb89b3bb5304George Mountpackage android.view;
17807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
18807e40c55cd74004ecc2392f8655fb89b3bb5304George Mountimport android.graphics.Canvas;
19807e40c55cd74004ecc2392f8655fb89b3bb5304George Mountimport android.graphics.Matrix;
200017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Guimport android.widget.FrameLayout;
21807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
228120652bb1155d762d945c1a3bf1636b6825dbd2George Mountimport java.util.ArrayList;
238120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
24807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount/**
25807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * This view draws another View in an Overlay without changing the parent. It will not be drawn
26807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * by its parent because its visibility is set to INVISIBLE, but will be drawn
27807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * here using its render node. When the GhostView is set to INVISIBLE, the View it is
28807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * shadowing will become VISIBLE and when the GhostView becomes VISIBLE, the shadowed
29807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * view becomes INVISIBLE.
30807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount * @hide
31807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount */
32807e40c55cd74004ecc2392f8655fb89b3bb5304George Mountpublic class GhostView extends View {
33807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    private final View mView;
340017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu    private int mReferences;
358120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    private boolean mBeingMoved;
36807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
370017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu    private GhostView(View view) {
38807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        super(view.getContext());
39807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        mView = view;
40807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        mView.mGhostView = this;
41807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        final ViewGroup parent = (ViewGroup) mView.getParent();
42e5a93aa81ce79bf7fa529b09b50d7473f07a74a2George Mount        mView.setTransitionVisibility(View.INVISIBLE);
438261a3f5ed1dbd5aa63b7819f2ef7a8e4a6ee9a1George Mount        parent.invalidate();
44807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    }
45807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
46807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    @Override
47807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    protected void onDraw(Canvas canvas) {
48f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik        if (canvas instanceof DisplayListCanvas) {
49f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik            DisplayListCanvas dlCanvas = (DisplayListCanvas) canvas;
50807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount            mView.mRecreateDisplayList = true;
5131a2d063df5111e730abe7d07be064690deedc34Chris Craik            RenderNode renderNode = mView.updateDisplayListIfDirty();
52807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount            if (renderNode.isValid()) {
53f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik                dlCanvas.insertReorderBarrier(); // enable shadow for this rendernode
54f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik                dlCanvas.drawRenderNode(renderNode);
55f6829a0a618b4523619ec53c996b04d67e3186b9Chris Craik                dlCanvas.insertInorderBarrier(); // re-disable reordering/shadows
56807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount            }
57807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        }
58807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    }
59807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
60fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    public void setMatrix(Matrix matrix) {
61fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        mRenderNode.setAnimationMatrix(matrix);
62fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    }
63fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount
64807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    @Override
65807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    public void setVisibility(@Visibility int visibility) {
66807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        super.setVisibility(visibility);
67807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        if (mView.mGhostView == this) {
68807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount            int inverseVisibility = (visibility == View.VISIBLE) ? View.INVISIBLE : View.VISIBLE;
69e5a93aa81ce79bf7fa529b09b50d7473f07a74a2George Mount            mView.setTransitionVisibility(inverseVisibility);
70807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        }
71807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    }
72807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
73807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    @Override
74807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    protected void onDetachedFromWindow() {
75807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        super.onDetachedFromWindow();
768120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        if (!mBeingMoved) {
77e5a93aa81ce79bf7fa529b09b50d7473f07a74a2George Mount            mView.setTransitionVisibility(View.VISIBLE);
788120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            mView.mGhostView = null;
798120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            final ViewGroup parent = (ViewGroup) mView.getParent();
808120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            if (parent != null) {
810006e88863e5f88e6b1cbd047a8b08ad4d8913c7George Mount                parent.invalidate();
828120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
83fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        }
84807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    }
85807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
86fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    public static void calculateMatrix(View view, ViewGroup host, Matrix matrix) {
87fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        ViewGroup parent = (ViewGroup) view.getParent();
88fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        matrix.reset();
89fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        parent.transformMatrixToGlobal(matrix);
90fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        matrix.preTranslate(-parent.getScrollX(), -parent.getScrollY());
91fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        host.transformMatrixToLocal(matrix);
92807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    }
93807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
94fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    public static GhostView addGhost(View view, ViewGroup viewGroup, Matrix matrix) {
95807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        if (!(view.getParent() instanceof ViewGroup)) {
96807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount            throw new IllegalArgumentException("Ghosted views must be parented by a ViewGroup");
97807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        }
98807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        ViewGroupOverlay overlay = viewGroup.getOverlay();
99807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        ViewOverlay.OverlayViewGroup overlayViewGroup = overlay.mOverlayViewGroup;
100807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        GhostView ghostView = view.mGhostView;
1010017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu        int previousRefCount = 0;
102807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        if (ghostView != null) {
1030017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            View oldParent = (View) ghostView.getParent();
1040017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            ViewGroup oldGrandParent = (ViewGroup) oldParent.getParent();
1050017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            if (oldGrandParent != overlayViewGroup) {
1060017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu                previousRefCount = ghostView.mReferences;
1070017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu                oldGrandParent.removeView(oldParent);
108807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount                ghostView = null;
109807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount            }
110807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        }
111807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        if (ghostView == null) {
112fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            if (matrix == null) {
113fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                matrix = new Matrix();
114fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount                calculateMatrix(view, viewGroup, matrix);
115fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount            }
1160017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            ghostView = new GhostView(view);
1170017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            ghostView.setMatrix(matrix);
1180017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            FrameLayout parent = new FrameLayout(view.getContext());
1190017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            parent.setClipChildren(false);
1200017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            copySize(viewGroup, parent);
1210017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            copySize(viewGroup, ghostView);
1220017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            parent.addView(ghostView);
1238120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            ArrayList<View> tempViews = new ArrayList<View>();
1248120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            int firstGhost = moveGhostViewsToTop(overlay.mOverlayViewGroup, tempViews);
1258120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            insertIntoOverlay(overlay.mOverlayViewGroup, parent, ghostView, tempViews, firstGhost);
1260017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            ghostView.mReferences = previousRefCount;
1270017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu        } else if (matrix != null) {
1280017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            ghostView.setMatrix(matrix);
129807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        }
1300017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu        ghostView.mReferences++;
131807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        return ghostView;
132807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    }
133807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
134fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    public static GhostView addGhost(View view, ViewGroup viewGroup) {
135fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount        return addGhost(view, viewGroup, null);
136fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount    }
137fe361d2113b8f3c54797d7bd720ca739328bd7aaGeorge Mount
138807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    public static void removeGhost(View view) {
139807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        GhostView ghostView = view.mGhostView;
140807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        if (ghostView != null) {
1410017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            ghostView.mReferences--;
1420017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            if (ghostView.mReferences == 0) {
1430017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu                ViewGroup parent = (ViewGroup) ghostView.getParent();
1440017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu                ViewGroup grandParent = (ViewGroup) parent.getParent();
1450017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu                grandParent.removeView(parent);
1460017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu            }
147807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        }
148807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    }
149807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount
150807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    public static GhostView getGhost(View view) {
151807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount        return view.mGhostView;
152807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount    }
1530017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu
1540017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu    private static void copySize(View from, View to) {
1550017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu        to.setLeft(0);
1560017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu        to.setTop(0);
1570017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu        to.setRight(from.getWidth());
1580017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu        to.setBottom(from.getHeight());
1590017ef9ee1ca342863a76fd44d1cce4709a7ce67Dake Gu    }
1608120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
1618120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    /**
1628120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * Move the GhostViews to the end so that they are on top of other views and it is easier
1638120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * to do binary search for the correct location for the GhostViews in insertIntoOverlay.
1648120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     *
1658120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * @return The index of the first GhostView or -1 if no GhostView is in the ViewGroup
1668120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     */
1678120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    private static int moveGhostViewsToTop(ViewGroup viewGroup, ArrayList<View> tempViews) {
1688120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        final int numChildren = viewGroup.getChildCount();
1698120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        if (numChildren == 0) {
1708120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            return -1;
1718120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        } else if (isGhostWrapper(viewGroup.getChildAt(numChildren - 1))) {
1728120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            // GhostViews are already at the end
1738120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            int firstGhost = numChildren - 1;
1748120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            for (int i = numChildren - 2; i >= 0; i--) {
1758120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                if (!isGhostWrapper(viewGroup.getChildAt(i))) {
1768120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                    break;
1778120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                }
1788120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                firstGhost = i;
1798120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
1808120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            return firstGhost;
1818120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
1828120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
1838120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        // Remove all GhostViews from the middle
1848120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        for (int i = numChildren - 2; i >= 0; i--) {
1858120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            View child = viewGroup.getChildAt(i);
1868120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            if (isGhostWrapper(child)) {
1878120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                tempViews.add(child);
1888120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                GhostView ghostView = (GhostView)((ViewGroup)child).getChildAt(0);
1898120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                ghostView.mBeingMoved = true;
1908120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                viewGroup.removeViewAt(i);
1918120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                ghostView.mBeingMoved = false;
1928120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
1938120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
1948120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
1958120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        final int firstGhost;
1968120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        if (tempViews.isEmpty()) {
1978120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            firstGhost = -1;
1988120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        } else {
1998120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            firstGhost = viewGroup.getChildCount();
2008120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            // Add the GhostViews to the end
2018120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            for (int i = tempViews.size() - 1; i >= 0; i--) {
2028120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                viewGroup.addView(tempViews.get(i));
2038120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
2048120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            tempViews.clear();
2058120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
2068120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        return firstGhost;
2078120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    }
2088120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2098120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    /**
2108120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * Inserts a GhostView into the overlay's ViewGroup in the order in which they
2118120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * should be displayed by the UI.
2128120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     */
2138120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    private static void insertIntoOverlay(ViewGroup viewGroup, ViewGroup wrapper,
2148120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            GhostView ghostView, ArrayList<View> tempParents, int firstGhost) {
2158120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        if (firstGhost == -1) {
2168120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            viewGroup.addView(wrapper);
2178120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        } else {
2188120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            ArrayList<View> viewParents = new ArrayList<View>();
2198120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            getParents(ghostView.mView, viewParents);
2208120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2218120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            int index = getInsertIndex(viewGroup, viewParents, tempParents, firstGhost);
2228120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            if (index < 0 || index >= viewGroup.getChildCount()) {
2238120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                viewGroup.addView(wrapper);
2248120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            } else {
2258120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                viewGroup.addView(wrapper, index);
2268120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
2278120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
2288120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    }
2298120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2308120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    /**
2318120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * Find the index into the overlay to insert the GhostView based on the order that the
2328120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * views should be drawn. This keeps GhostViews layered in the same order
2338120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * that they are ordered in the UI.
2348120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     */
2358120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    private static int getInsertIndex(ViewGroup overlayViewGroup, ArrayList<View> viewParents,
2368120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            ArrayList<View> tempParents, int firstGhost) {
2378120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        int low = firstGhost;
2388120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        int high = overlayViewGroup.getChildCount() - 1;
2398120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2408120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        while (low <= high) {
2418120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            int mid = (low + high) / 2;
2428120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            ViewGroup wrapper = (ViewGroup) overlayViewGroup.getChildAt(mid);
2438120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            GhostView midView = (GhostView) wrapper.getChildAt(0);
2448120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            getParents(midView.mView, tempParents);
2458120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            if (isOnTop(viewParents, tempParents)) {
2468120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                low = mid + 1;
2478120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            } else {
2488120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                high = mid - 1;
2498120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
2508120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            tempParents.clear();
2518120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
2528120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2538120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        return low;
2548120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    }
2558120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2568120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    /**
2578120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * Returns true if view is a GhostView's FrameLayout wrapper.
2588120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     */
2598120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    private static boolean isGhostWrapper(View view) {
2608120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        if (view instanceof FrameLayout) {
2618120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            FrameLayout frameLayout = (FrameLayout) view;
2628120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            if (frameLayout.getChildCount() == 1) {
2638120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                View child = frameLayout.getChildAt(0);
2648120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                return child instanceof GhostView;
2658120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
2668120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
2678120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        return false;
2688120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    }
2698120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2708120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    /**
2718120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * Returns true if viewParents is from a View that is on top of the comparedWith's view.
2728120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * The ArrayLists contain the ancestors of views in order from top most grandparent, to
2738120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * the view itself, in order. The goal is to find the first matching parent and then
2748120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * compare the draw order of the siblings.
2758120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     */
2768120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    private static boolean isOnTop(ArrayList<View> viewParents, ArrayList<View> comparedWith) {
2778120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        if (viewParents.isEmpty() || comparedWith.isEmpty() ||
2788120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                viewParents.get(0) != comparedWith.get(0)) {
2798120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            // Not the same decorView -- arbitrary ordering
2808120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            return true;
2818120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
2828120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        int depth = Math.min(viewParents.size(), comparedWith.size());
2838120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        for (int i = 1; i < depth; i++) {
2848120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            View viewParent = viewParents.get(i);
2858120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            View comparedWithParent = comparedWith.get(i);
2868120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2878120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            if (viewParent != comparedWithParent) {
2888120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                // i - 1 is the same parent, but these are different children.
2898120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                return isOnTop(viewParent, comparedWithParent);
2908120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
2918120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
2928120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2938120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        // one of these is the parent of the other
2948120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        boolean isComparedWithTheParent = (comparedWith.size() == depth);
2958120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        return isComparedWithTheParent;
2968120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    }
2978120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
2988120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    /**
2998120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * Adds all the parents, grandparents, etc. of view to parents.
3008120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     */
3018120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    private static void getParents(View view, ArrayList<View> parents) {
3028120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        ViewParent parent = view.getParent();
3038120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        if (parent != null && parent instanceof ViewGroup) {
3048120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            getParents((View) parent, parents);
3058120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
3068120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        parents.add(view);
3078120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    }
3088120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
3098120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    /**
3108120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * Returns true if view would be drawn on top of comparedWith or false otherwise.
3118120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * view and comparedWith are siblings with the same parent. This uses the logic
3128120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     * that dispatchDraw uses to determine which View should be drawn first.
3138120652bb1155d762d945c1a3bf1636b6825dbd2George Mount     */
3148120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    private static boolean isOnTop(View view, View comparedWith) {
3158120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        ViewGroup parent = (ViewGroup) view.getParent();
3168120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
3178120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        final int childrenCount = parent.getChildCount();
3188120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        final ArrayList<View> preorderedList = parent.buildOrderedChildList();
3198120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        final boolean customOrder = preorderedList == null
3208120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                && parent.isChildrenDrawingOrderEnabled();
32150ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount
32250ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount        // This default value shouldn't be used because both view and comparedWith
32350ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount        // should be in the list. If there is an error, then just return an arbitrary
32450ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount        // view is on top.
32550ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount        boolean isOnTop = true;
3268120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        for (int i = 0; i < childrenCount; i++) {
3278120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            int childIndex = customOrder ? parent.getChildDrawingOrder(childrenCount, i) : i;
3288120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            final View child = (preorderedList == null)
3298120652bb1155d762d945c1a3bf1636b6825dbd2George Mount                    ? parent.getChildAt(childIndex) : preorderedList.get(childIndex);
3308120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            if (child == view) {
33150ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount                isOnTop = false;
33250ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount                break;
3338120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            } else if (child == comparedWith) {
33450ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount                isOnTop = true;
33550ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount                break;
3368120652bb1155d762d945c1a3bf1636b6825dbd2George Mount            }
3378120652bb1155d762d945c1a3bf1636b6825dbd2George Mount        }
3388120652bb1155d762d945c1a3bf1636b6825dbd2George Mount
33950ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount        if (preorderedList != null) {
34050ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount            preorderedList.clear();
34150ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount        }
34250ac6cb9820da352bd5e89596b17561878e969ccGeorge Mount        return isOnTop;
3438120652bb1155d762d945c1a3bf1636b6825dbd2George Mount    }
344807e40c55cd74004ecc2392f8655fb89b3bb5304George Mount}
345