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