Loading core/java/android/view/GhostView.java 0 → 100644 +125 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import android.graphics.Canvas; import android.graphics.Matrix; /** * This view draws another View in an Overlay without changing the parent. It will not be drawn * by its parent because its visibility is set to INVISIBLE, but will be drawn * here using its render node. When the GhostView is set to INVISIBLE, the View it is * shadowing will become VISIBLE and when the GhostView becomes VISIBLE, the shadowed * view becomes INVISIBLE. * @hide */ public class GhostView extends View { private final Matrix mMatrix = new Matrix(); private final View mView; private GhostView(View view, ViewGroup host) { super(view.getContext()); mView = view; setMatrix(host); mView.mGhostView = this; final ViewGroup parent = (ViewGroup) mView.getParent(); setLeft(0); setTop(0); setRight(host.getWidth()); setBottom(host.getHeight()); setGhostedVisibility(View.INVISIBLE); parent.mRecreateDisplayList = true; parent.getDisplayList(); } @Override protected void onDraw(Canvas canvas) { if (canvas instanceof HardwareCanvas) { HardwareCanvas hwCanvas = (HardwareCanvas) canvas; int saveCount = hwCanvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.concat(mMatrix); mView.mRecreateDisplayList = true; RenderNode renderNode = mView.getDisplayList(); if (renderNode.isValid()) { hwCanvas.drawRenderNode(renderNode); } hwCanvas.restoreToCount(saveCount); } } @Override public void setVisibility(@Visibility int visibility) { super.setVisibility(visibility); if (mView.mGhostView == this) { int inverseVisibility = (visibility == View.VISIBLE) ? View.INVISIBLE : View.VISIBLE; setGhostedVisibility(inverseVisibility); } } private void setGhostedVisibility(int visibility) { mView.mViewFlags = (mView.mViewFlags & ~View.VISIBILITY_MASK) | visibility; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); setGhostedVisibility(View.VISIBLE); mView.mGhostView = null; final ViewGroup parent = (ViewGroup) mView.getParent(); parent.mRecreateDisplayList = true; parent.getDisplayList(); } private void setMatrix(ViewGroup host) { host.transformMatrixToLocal(mMatrix); ViewGroup parent = (ViewGroup) mView.getParent(); parent.transformMatrixToGlobal(mMatrix); mMatrix.postTranslate(-parent.getScrollX(), -parent.getScrollY()); } public static GhostView addGhost(View view, ViewGroup viewGroup) { if (!(view.getParent() instanceof ViewGroup)) { throw new IllegalArgumentException("Ghosted views must be parented by a ViewGroup"); } ViewGroupOverlay overlay = viewGroup.getOverlay(); ViewOverlay.OverlayViewGroup overlayViewGroup = overlay.mOverlayViewGroup; GhostView ghostView = view.mGhostView; if (ghostView != null) { ViewGroup oldParent = (ViewGroup) ghostView.getParent(); if (oldParent != overlayViewGroup) { oldParent.removeView(ghostView); ghostView = null; } } if (ghostView == null) { ghostView = new GhostView(view, (ViewGroup) overlayViewGroup.mHostView); overlay.add(ghostView); } return ghostView; } public static void removeGhost(View view) { GhostView ghostView = view.mGhostView; if (ghostView != null) { ViewGroup parent = (ViewGroup) ghostView.getParent(); parent.removeView(ghostView); } } public static GhostView getGhost(View view) { return view.mGhostView; } } core/java/android/view/View.java +15 −3 Original line number Diff line number Diff line Loading @@ -17,9 +17,7 @@ package android.view; import android.animation.AnimatorInflater; import android.animation.RevealAnimator; import android.animation.StateListAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -3519,6 +3517,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private int[] mTempNestedScrollConsumed; /** * An overlay is going to draw this View instead of being drawn as part of this * View's parent. mGhostView is the View in the Overlay that must be invalidated * when this view is invalidated. */ GhostView mGhostView; /** * Simple constructor to use when creating a view from code. * Loading Loading @@ -10284,6 +10289,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ @ViewDebug.ExportedProperty(category = "drawing") public float getTransitionAlpha() { return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; } Loading Loading @@ -11371,6 +11377,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) { if (mGhostView != null) { mGhostView.invalidate(invalidateCache); return; } if (skipInvalidate()) { return; } Loading Loading @@ -11408,7 +11419,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } // Damage the entire IsolatedZVolume recieving this view's shadow. // Damage the entire IsolatedZVolume receiving this view's shadow. if (isHardwareAccelerated() && getZ() != 0) { damageShadowReceiver(); } Loading Loading @@ -19397,6 +19408,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The name used of the View to be used to identify Views in Transitions or null * if no name has been given. */ @ViewDebug.ExportedProperty public String getTransitionName() { return mTransitionName; } Loading
core/java/android/view/GhostView.java 0 → 100644 +125 −0 Original line number Diff line number Diff line /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view; import android.graphics.Canvas; import android.graphics.Matrix; /** * This view draws another View in an Overlay without changing the parent. It will not be drawn * by its parent because its visibility is set to INVISIBLE, but will be drawn * here using its render node. When the GhostView is set to INVISIBLE, the View it is * shadowing will become VISIBLE and when the GhostView becomes VISIBLE, the shadowed * view becomes INVISIBLE. * @hide */ public class GhostView extends View { private final Matrix mMatrix = new Matrix(); private final View mView; private GhostView(View view, ViewGroup host) { super(view.getContext()); mView = view; setMatrix(host); mView.mGhostView = this; final ViewGroup parent = (ViewGroup) mView.getParent(); setLeft(0); setTop(0); setRight(host.getWidth()); setBottom(host.getHeight()); setGhostedVisibility(View.INVISIBLE); parent.mRecreateDisplayList = true; parent.getDisplayList(); } @Override protected void onDraw(Canvas canvas) { if (canvas instanceof HardwareCanvas) { HardwareCanvas hwCanvas = (HardwareCanvas) canvas; int saveCount = hwCanvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.concat(mMatrix); mView.mRecreateDisplayList = true; RenderNode renderNode = mView.getDisplayList(); if (renderNode.isValid()) { hwCanvas.drawRenderNode(renderNode); } hwCanvas.restoreToCount(saveCount); } } @Override public void setVisibility(@Visibility int visibility) { super.setVisibility(visibility); if (mView.mGhostView == this) { int inverseVisibility = (visibility == View.VISIBLE) ? View.INVISIBLE : View.VISIBLE; setGhostedVisibility(inverseVisibility); } } private void setGhostedVisibility(int visibility) { mView.mViewFlags = (mView.mViewFlags & ~View.VISIBILITY_MASK) | visibility; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); setGhostedVisibility(View.VISIBLE); mView.mGhostView = null; final ViewGroup parent = (ViewGroup) mView.getParent(); parent.mRecreateDisplayList = true; parent.getDisplayList(); } private void setMatrix(ViewGroup host) { host.transformMatrixToLocal(mMatrix); ViewGroup parent = (ViewGroup) mView.getParent(); parent.transformMatrixToGlobal(mMatrix); mMatrix.postTranslate(-parent.getScrollX(), -parent.getScrollY()); } public static GhostView addGhost(View view, ViewGroup viewGroup) { if (!(view.getParent() instanceof ViewGroup)) { throw new IllegalArgumentException("Ghosted views must be parented by a ViewGroup"); } ViewGroupOverlay overlay = viewGroup.getOverlay(); ViewOverlay.OverlayViewGroup overlayViewGroup = overlay.mOverlayViewGroup; GhostView ghostView = view.mGhostView; if (ghostView != null) { ViewGroup oldParent = (ViewGroup) ghostView.getParent(); if (oldParent != overlayViewGroup) { oldParent.removeView(ghostView); ghostView = null; } } if (ghostView == null) { ghostView = new GhostView(view, (ViewGroup) overlayViewGroup.mHostView); overlay.add(ghostView); } return ghostView; } public static void removeGhost(View view) { GhostView ghostView = view.mGhostView; if (ghostView != null) { ViewGroup parent = (ViewGroup) ghostView.getParent(); parent.removeView(ghostView); } } public static GhostView getGhost(View view) { return view.mGhostView; } }
core/java/android/view/View.java +15 −3 Original line number Diff line number Diff line Loading @@ -17,9 +17,7 @@ package android.view; import android.animation.AnimatorInflater; import android.animation.RevealAnimator; import android.animation.StateListAnimator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; Loading Loading @@ -3519,6 +3517,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private int[] mTempNestedScrollConsumed; /** * An overlay is going to draw this View instead of being drawn as part of this * View's parent. mGhostView is the View in the Overlay that must be invalidated * when this view is invalidated. */ GhostView mGhostView; /** * Simple constructor to use when creating a view from code. * Loading Loading @@ -10284,6 +10289,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @hide */ @ViewDebug.ExportedProperty(category = "drawing") public float getTransitionAlpha() { return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; } Loading Loading @@ -11371,6 +11377,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback, void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate) { if (mGhostView != null) { mGhostView.invalidate(invalidateCache); return; } if (skipInvalidate()) { return; } Loading Loading @@ -11408,7 +11419,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } // Damage the entire IsolatedZVolume recieving this view's shadow. // Damage the entire IsolatedZVolume receiving this view's shadow. if (isHardwareAccelerated() && getZ() != 0) { damageShadowReceiver(); } Loading Loading @@ -19397,6 +19408,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @return The name used of the View to be used to identify Views in Transitions or null * if no name has been given. */ @ViewDebug.ExportedProperty public String getTransitionName() { return mTransitionName; }