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