Loading core/java/android/widget/Magnifier.java +109 −89 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import android.os.Message; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.DisplayListCanvas; import android.view.LayoutInflater; import android.view.PixelCopy; import android.view.RenderNode; import android.view.Surface; Loading Loading @@ -71,8 +70,6 @@ public final class Magnifier { private final int[] mViewCoordinatesInSurface; // The window containing the magnifier. private InternalPopupWindow mWindow; // The center coordinates of the window containing the magnifier. private final Point mWindowCoords = new Point(); // The width of the window containing the magnifier. private final int mWindowWidth; // The height of the window containing the magnifier. Loading @@ -87,8 +84,18 @@ public final class Magnifier { private final float mWindowElevation; // The corner radius of the window containing the magnifier. private final float mWindowCornerRadius; // The center coordinates of the content that is to be magnified. // The parent surface for the magnifier surface. private SurfaceInfo mParentSurface; // The surface where the content will be copied from. private SurfaceInfo mContentCopySurface; // The center coordinates of the window containing the magnifier. private final Point mWindowCoords = new Point(); // The center coordinates of the content to be magnified, // which can potentially contain a region outside the magnified view. private final Point mCenterZoomCoords = new Point(); // The center coordinates of the content to be magnified, // clamped inside the visible region of the magnified view. private final Point mClampedCenterZoomCoords = new Point(); // Variables holding previous states, used for detecting redundant calls and invalidation. private final Point mPrevStartCoordsInSurface = new Point( NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE); Loading @@ -108,8 +115,6 @@ public final class Magnifier { public Magnifier(@NonNull View view) { mView = Preconditions.checkNotNull(view); final Context context = mView.getContext(); final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null); content.findViewById(R.id.magnifier_inner).setClipToOutline(true); mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width); mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height); mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation); Loading Loading @@ -155,31 +160,17 @@ public final class Magnifier { xPosInView = Math.max(0, Math.min(xPosInView, mView.getWidth())); yPosInView = Math.max(0, Math.min(yPosInView, mView.getHeight())); configureCoordinates(xPosInView, yPosInView); // Clamp the startX location to avoid magnifying content which does not belong // to the magnified view. This will not take into account overlapping views. final Rect viewVisibleRegion = new Rect(); mView.getGlobalVisibleRect(viewVisibleRegion); if (mView.getViewRootImpl() != null) { // Clamping coordinates relative to the surface, not to the window. final Rect surfaceInsets = mView.getViewRootImpl().mWindowAttributes.surfaceInsets; viewVisibleRegion.offset(surfaceInsets.left, surfaceInsets.top); } if (mView instanceof SurfaceView) { // If we copy content from a SurfaceView, clamp coordinates relative to it. viewVisibleRegion.offset(-mViewCoordinatesInSurface[0], -mViewCoordinatesInSurface[1]); } final int startX = Math.max(viewVisibleRegion.left, Math.min( mCenterZoomCoords.x - mBitmapWidth / 2, viewVisibleRegion.right - mBitmapWidth)); final int startY = mCenterZoomCoords.y - mBitmapHeight / 2; obtainSurfaces(); obtainContentCoordinates(xPosInView, yPosInView); obtainWindowCoordinates(); final int startX = mClampedCenterZoomCoords.x - mBitmapWidth / 2; final int startY = mClampedCenterZoomCoords.y - mBitmapHeight / 2; if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) { if (mWindow == null) { synchronized (mLock) { mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(), getValidParentSurfaceForMagnifier(), mParentSurface.mSurface, mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius, Handler.getMain() /* draw the magnifier on the UI thread */, mLock, mCallback); Loading Loading @@ -213,6 +204,7 @@ public final class Magnifier { */ public void update() { if (mWindow != null) { obtainSurfaces(); // Update the content shown in the magnifier. performPixelCopy(mPrevStartCoordsInSurface.x, mPrevStartCoordsInSurface.y, false /* update window position */); Loading Loading @@ -257,26 +249,53 @@ public final class Magnifier { mWindow.mLastDrawContentPositionY - surfaceInsets.top); } @Nullable private Surface getValidParentSurfaceForMagnifier() { /** * Retrieves the surfaces used by the magnifier: * - a parent surface for the magnifier surface. This will usually be the main app window. * - a surface where the magnified content will be copied from. This will be the main app * window unless the magnified view is a SurfaceView, in which case its backing surface * will be used. */ private void obtainSurfaces() { // Get the main window surface. SurfaceInfo validMainWindowSurface = SurfaceInfo.NULL; if (mView.getViewRootImpl() != null) { final Surface mainWindowSurface = mView.getViewRootImpl().mSurface; final ViewRootImpl viewRootImpl = mView.getViewRootImpl(); final Surface mainWindowSurface = viewRootImpl.mSurface; if (mainWindowSurface != null && mainWindowSurface.isValid()) { return mainWindowSurface; final Rect surfaceInsets = viewRootImpl.mWindowAttributes.surfaceInsets; final int surfaceWidth = viewRootImpl.getWidth() + surfaceInsets.left + surfaceInsets.right; final int surfaceHeight = viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; validMainWindowSurface = new SurfaceInfo(mainWindowSurface, surfaceWidth, surfaceHeight, true); } } // Get the surface backing the magnified view, if it is a SurfaceView. SurfaceInfo validSurfaceViewSurface = SurfaceInfo.NULL; if (mView instanceof SurfaceView) { final Surface surfaceViewSurface = ((SurfaceView) mView).getHolder().getSurface(); final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder(); final Surface surfaceViewSurface = surfaceHolder.getSurface(); if (surfaceViewSurface != null && surfaceViewSurface.isValid()) { return surfaceViewSurface; final Rect surfaceFrame = surfaceHolder.getSurfaceFrame(); validSurfaceViewSurface = new SurfaceInfo(surfaceViewSurface, surfaceFrame.right, surfaceFrame.bottom, false); } } return null; // Choose the parent surface for the magnifier and the source surface for the content. mParentSurface = validMainWindowSurface != SurfaceInfo.NULL ? validMainWindowSurface : validSurfaceViewSurface; mContentCopySurface = mView instanceof SurfaceView ? validSurfaceViewSurface : validMainWindowSurface; } private void configureCoordinates(final float xPosInView, final float yPosInView) { // Compute the coordinates of the center of the content going to be displayed in the // magnifier. These are relative to the surface the content is copied from. /** * Computes the coordinates of the center of the content going to be displayed in the * magnifier. These are relative to the surface the content is copied from. */ private void obtainContentCoordinates(final float xPosInView, final float yPosInView) { final float posX; final float posY; mView.getLocationInSurface(mViewCoordinatesInSurface); Loading @@ -291,78 +310,59 @@ public final class Magnifier { mCenterZoomCoords.x = Math.round(posX); mCenterZoomCoords.y = Math.round(posY); // Clamp the x location to avoid magnifying content which does not belong // to the magnified view. This will not take into account overlapping views. final Rect viewVisibleRegion = new Rect(); mView.getGlobalVisibleRect(viewVisibleRegion); if (mView.getViewRootImpl() != null) { // Clamping coordinates relative to the surface, not to the window. final Rect surfaceInsets = mView.getViewRootImpl().mWindowAttributes.surfaceInsets; viewVisibleRegion.offset(surfaceInsets.left, surfaceInsets.top); } if (mView instanceof SurfaceView) { // If we copy content from a SurfaceView, clamp coordinates relative to it. viewVisibleRegion.offset(-mViewCoordinatesInSurface[0], -mViewCoordinatesInSurface[1]); } mClampedCenterZoomCoords.x = Math.max(viewVisibleRegion.left + mBitmapWidth / 2, Math.min( mCenterZoomCoords.x, viewVisibleRegion.right - mBitmapWidth / 2)); mClampedCenterZoomCoords.y = mCenterZoomCoords.y; } private void obtainWindowCoordinates() { // Compute the position of the magnifier window. Again, this has to be relative to the // surface of the magnified view, as this surface is the parent of the magnifier surface. final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize( R.dimen.magnifier_offset); mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2; mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset; if (mView instanceof SurfaceView && mView.getViewRootImpl() != null) { // TODO: deduplicate against the first part of #getValidParentSurfaceForMagnifier() final Surface mainWindowSurface = mView.getViewRootImpl().mSurface; if (mainWindowSurface != null && mainWindowSurface.isValid()) { if (mParentSurface != mContentCopySurface) { mWindowCoords.x += mViewCoordinatesInSurface[0]; mWindowCoords.y += mViewCoordinatesInSurface[1]; } } } private void performPixelCopy(final int startXInSurface, final int startYInSurface, final boolean updateWindowPosition) { // Get the view surface where the content will be copied from. final Surface surface; final int surfaceWidth; final int surfaceHeight; if (mView instanceof SurfaceView) { final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder(); surface = surfaceHolder.getSurface(); surfaceWidth = surfaceHolder.getSurfaceFrame().right; surfaceHeight = surfaceHolder.getSurfaceFrame().bottom; } else if (mView.getViewRootImpl() != null) { final ViewRootImpl viewRootImpl = mView.getViewRootImpl(); surface = viewRootImpl.mSurface; final Rect surfaceInsets = viewRootImpl.mWindowAttributes.surfaceInsets; surfaceWidth = viewRootImpl.getWidth() + surfaceInsets.left + surfaceInsets.right; surfaceHeight = viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; } else { surface = null; surfaceWidth = NONEXISTENT_PREVIOUS_CONFIG_VALUE; surfaceHeight = NONEXISTENT_PREVIOUS_CONFIG_VALUE; } if (surface == null || !surface.isValid()) { if (mContentCopySurface.mSurface == null || !mContentCopySurface.mSurface.isValid()) { return; } // Clamp copy coordinates inside the surface to avoid displaying distorted content. final int clampedStartXInSurface = Math.max(0, Math.min(startXInSurface, surfaceWidth - mBitmapWidth)); Math.min(startXInSurface, mContentCopySurface.mWidth - mBitmapWidth)); final int clampedStartYInSurface = Math.max(0, Math.min(startYInSurface, surfaceHeight - mBitmapHeight)); Math.min(startYInSurface, mContentCopySurface.mHeight - mBitmapHeight)); // Clamp window coordinates inside the parent surface, to avoid displaying // the magnifier out of screen or overlapping with system insets. Rect windowBounds = null; if (mView.getViewRootImpl() != null) { // TODO: deduplicate against the first part of #getValidParentSurfaceForMagnifier() // TODO: deduplicate against the first part of the current method final ViewRootImpl viewRootImpl = mView.getViewRootImpl(); final Surface parentSurface = viewRootImpl.mSurface; final Rect surfaceInsets = viewRootImpl.mWindowAttributes.surfaceInsets; final int parentWidth = viewRootImpl.getWidth() + surfaceInsets.left + surfaceInsets.right; final int parentHeight = viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; if (parentSurface != null && parentSurface.isValid()) { final Rect windowBounds; if (mParentSurface.mIsMainWindowSurface) { final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets(); windowBounds = new Rect(systemInsets.left, systemInsets.top, parentWidth - systemInsets.right, parentHeight - systemInsets.bottom); } } if (windowBounds == null && mView instanceof SurfaceView) { windowBounds = ((SurfaceView) mView).getHolder().getSurfaceFrame(); mParentSurface.mWidth - systemInsets.right, mParentSurface.mHeight - systemInsets.bottom); } else { windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight); } final int windowCoordsX = Math.max(windowBounds.left, Math.min(windowBounds.right - mWindowWidth, mWindowCoords.x)); final int windowCoordsY = Math.max(windowBounds.top, Loading @@ -376,7 +376,7 @@ public final class Magnifier { final InternalPopupWindow currentWindowInstance = mWindow; final Bitmap bitmap = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888); PixelCopy.request(surface, mPixelCopyRequestRect, bitmap, PixelCopy.request(mContentCopySurface.mSurface, mPixelCopyRequestRect, bitmap, result -> { synchronized (mLock) { if (mWindow != currentWindowInstance) { Loading @@ -395,6 +395,26 @@ public final class Magnifier { mPrevStartCoordsInSurface.y = startYInSurface; } /** * Contains a surface and metadata corresponding to it. */ private static class SurfaceInfo { public static final SurfaceInfo NULL = new SurfaceInfo(null, 0, 0, false); private Surface mSurface; private int mWidth; private int mHeight; private boolean mIsMainWindowSurface; SurfaceInfo(final Surface surface, final int width, final int height, final boolean isMainWindowSurface) { mSurface = surface; mWidth = width; mHeight = height; mIsMainWindowSurface = isMainWindowSurface; } } /** * Magnifier's own implementation of PopupWindow-similar floating window. * This exists to ensure frame-synchronization between window position updates and window Loading core/res/res/layout/magnifier.xmldeleted 100644 → 0 +0 −35 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2017 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 --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/magnifier_inner" android:layout_width="@android:dimen/magnifier_width" android:layout_height="@android:dimen/magnifier_height" android:elevation="@android:dimen/magnifier_elevation" android:background="?android:attr/floatingToolbarPopupBackgroundDrawable" android:scaleType="fitXY"> <ImageView android:id="@+id/magnifier_image" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> </LinearLayout> core/res/res/values/symbols.xml +0 −3 Original line number Diff line number Diff line Loading @@ -2587,9 +2587,6 @@ <java-symbol type="attr" name="floatingToolbarDividerColor" /> <!-- Magnifier --> <java-symbol type="id" name="magnifier_image" /> <java-symbol type="id" name="magnifier_inner" /> <java-symbol type="layout" name="magnifier" /> <java-symbol type="dimen" name="magnifier_width" /> <java-symbol type="dimen" name="magnifier_height" /> <java-symbol type="dimen" name="magnifier_elevation" /> Loading Loading
core/java/android/widget/Magnifier.java +109 −89 Original line number Diff line number Diff line Loading @@ -38,7 +38,6 @@ import android.os.Message; import android.view.ContextThemeWrapper; import android.view.Display; import android.view.DisplayListCanvas; import android.view.LayoutInflater; import android.view.PixelCopy; import android.view.RenderNode; import android.view.Surface; Loading Loading @@ -71,8 +70,6 @@ public final class Magnifier { private final int[] mViewCoordinatesInSurface; // The window containing the magnifier. private InternalPopupWindow mWindow; // The center coordinates of the window containing the magnifier. private final Point mWindowCoords = new Point(); // The width of the window containing the magnifier. private final int mWindowWidth; // The height of the window containing the magnifier. Loading @@ -87,8 +84,18 @@ public final class Magnifier { private final float mWindowElevation; // The corner radius of the window containing the magnifier. private final float mWindowCornerRadius; // The center coordinates of the content that is to be magnified. // The parent surface for the magnifier surface. private SurfaceInfo mParentSurface; // The surface where the content will be copied from. private SurfaceInfo mContentCopySurface; // The center coordinates of the window containing the magnifier. private final Point mWindowCoords = new Point(); // The center coordinates of the content to be magnified, // which can potentially contain a region outside the magnified view. private final Point mCenterZoomCoords = new Point(); // The center coordinates of the content to be magnified, // clamped inside the visible region of the magnified view. private final Point mClampedCenterZoomCoords = new Point(); // Variables holding previous states, used for detecting redundant calls and invalidation. private final Point mPrevStartCoordsInSurface = new Point( NONEXISTENT_PREVIOUS_CONFIG_VALUE, NONEXISTENT_PREVIOUS_CONFIG_VALUE); Loading @@ -108,8 +115,6 @@ public final class Magnifier { public Magnifier(@NonNull View view) { mView = Preconditions.checkNotNull(view); final Context context = mView.getContext(); final View content = LayoutInflater.from(context).inflate(R.layout.magnifier, null); content.findViewById(R.id.magnifier_inner).setClipToOutline(true); mWindowWidth = context.getResources().getDimensionPixelSize(R.dimen.magnifier_width); mWindowHeight = context.getResources().getDimensionPixelSize(R.dimen.magnifier_height); mWindowElevation = context.getResources().getDimension(R.dimen.magnifier_elevation); Loading Loading @@ -155,31 +160,17 @@ public final class Magnifier { xPosInView = Math.max(0, Math.min(xPosInView, mView.getWidth())); yPosInView = Math.max(0, Math.min(yPosInView, mView.getHeight())); configureCoordinates(xPosInView, yPosInView); // Clamp the startX location to avoid magnifying content which does not belong // to the magnified view. This will not take into account overlapping views. final Rect viewVisibleRegion = new Rect(); mView.getGlobalVisibleRect(viewVisibleRegion); if (mView.getViewRootImpl() != null) { // Clamping coordinates relative to the surface, not to the window. final Rect surfaceInsets = mView.getViewRootImpl().mWindowAttributes.surfaceInsets; viewVisibleRegion.offset(surfaceInsets.left, surfaceInsets.top); } if (mView instanceof SurfaceView) { // If we copy content from a SurfaceView, clamp coordinates relative to it. viewVisibleRegion.offset(-mViewCoordinatesInSurface[0], -mViewCoordinatesInSurface[1]); } final int startX = Math.max(viewVisibleRegion.left, Math.min( mCenterZoomCoords.x - mBitmapWidth / 2, viewVisibleRegion.right - mBitmapWidth)); final int startY = mCenterZoomCoords.y - mBitmapHeight / 2; obtainSurfaces(); obtainContentCoordinates(xPosInView, yPosInView); obtainWindowCoordinates(); final int startX = mClampedCenterZoomCoords.x - mBitmapWidth / 2; final int startY = mClampedCenterZoomCoords.y - mBitmapHeight / 2; if (xPosInView != mPrevPosInView.x || yPosInView != mPrevPosInView.y) { if (mWindow == null) { synchronized (mLock) { mWindow = new InternalPopupWindow(mView.getContext(), mView.getDisplay(), getValidParentSurfaceForMagnifier(), mParentSurface.mSurface, mWindowWidth, mWindowHeight, mWindowElevation, mWindowCornerRadius, Handler.getMain() /* draw the magnifier on the UI thread */, mLock, mCallback); Loading Loading @@ -213,6 +204,7 @@ public final class Magnifier { */ public void update() { if (mWindow != null) { obtainSurfaces(); // Update the content shown in the magnifier. performPixelCopy(mPrevStartCoordsInSurface.x, mPrevStartCoordsInSurface.y, false /* update window position */); Loading Loading @@ -257,26 +249,53 @@ public final class Magnifier { mWindow.mLastDrawContentPositionY - surfaceInsets.top); } @Nullable private Surface getValidParentSurfaceForMagnifier() { /** * Retrieves the surfaces used by the magnifier: * - a parent surface for the magnifier surface. This will usually be the main app window. * - a surface where the magnified content will be copied from. This will be the main app * window unless the magnified view is a SurfaceView, in which case its backing surface * will be used. */ private void obtainSurfaces() { // Get the main window surface. SurfaceInfo validMainWindowSurface = SurfaceInfo.NULL; if (mView.getViewRootImpl() != null) { final Surface mainWindowSurface = mView.getViewRootImpl().mSurface; final ViewRootImpl viewRootImpl = mView.getViewRootImpl(); final Surface mainWindowSurface = viewRootImpl.mSurface; if (mainWindowSurface != null && mainWindowSurface.isValid()) { return mainWindowSurface; final Rect surfaceInsets = viewRootImpl.mWindowAttributes.surfaceInsets; final int surfaceWidth = viewRootImpl.getWidth() + surfaceInsets.left + surfaceInsets.right; final int surfaceHeight = viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; validMainWindowSurface = new SurfaceInfo(mainWindowSurface, surfaceWidth, surfaceHeight, true); } } // Get the surface backing the magnified view, if it is a SurfaceView. SurfaceInfo validSurfaceViewSurface = SurfaceInfo.NULL; if (mView instanceof SurfaceView) { final Surface surfaceViewSurface = ((SurfaceView) mView).getHolder().getSurface(); final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder(); final Surface surfaceViewSurface = surfaceHolder.getSurface(); if (surfaceViewSurface != null && surfaceViewSurface.isValid()) { return surfaceViewSurface; final Rect surfaceFrame = surfaceHolder.getSurfaceFrame(); validSurfaceViewSurface = new SurfaceInfo(surfaceViewSurface, surfaceFrame.right, surfaceFrame.bottom, false); } } return null; // Choose the parent surface for the magnifier and the source surface for the content. mParentSurface = validMainWindowSurface != SurfaceInfo.NULL ? validMainWindowSurface : validSurfaceViewSurface; mContentCopySurface = mView instanceof SurfaceView ? validSurfaceViewSurface : validMainWindowSurface; } private void configureCoordinates(final float xPosInView, final float yPosInView) { // Compute the coordinates of the center of the content going to be displayed in the // magnifier. These are relative to the surface the content is copied from. /** * Computes the coordinates of the center of the content going to be displayed in the * magnifier. These are relative to the surface the content is copied from. */ private void obtainContentCoordinates(final float xPosInView, final float yPosInView) { final float posX; final float posY; mView.getLocationInSurface(mViewCoordinatesInSurface); Loading @@ -291,78 +310,59 @@ public final class Magnifier { mCenterZoomCoords.x = Math.round(posX); mCenterZoomCoords.y = Math.round(posY); // Clamp the x location to avoid magnifying content which does not belong // to the magnified view. This will not take into account overlapping views. final Rect viewVisibleRegion = new Rect(); mView.getGlobalVisibleRect(viewVisibleRegion); if (mView.getViewRootImpl() != null) { // Clamping coordinates relative to the surface, not to the window. final Rect surfaceInsets = mView.getViewRootImpl().mWindowAttributes.surfaceInsets; viewVisibleRegion.offset(surfaceInsets.left, surfaceInsets.top); } if (mView instanceof SurfaceView) { // If we copy content from a SurfaceView, clamp coordinates relative to it. viewVisibleRegion.offset(-mViewCoordinatesInSurface[0], -mViewCoordinatesInSurface[1]); } mClampedCenterZoomCoords.x = Math.max(viewVisibleRegion.left + mBitmapWidth / 2, Math.min( mCenterZoomCoords.x, viewVisibleRegion.right - mBitmapWidth / 2)); mClampedCenterZoomCoords.y = mCenterZoomCoords.y; } private void obtainWindowCoordinates() { // Compute the position of the magnifier window. Again, this has to be relative to the // surface of the magnified view, as this surface is the parent of the magnifier surface. final int verticalOffset = mView.getContext().getResources().getDimensionPixelSize( R.dimen.magnifier_offset); mWindowCoords.x = mCenterZoomCoords.x - mWindowWidth / 2; mWindowCoords.y = mCenterZoomCoords.y - mWindowHeight / 2 - verticalOffset; if (mView instanceof SurfaceView && mView.getViewRootImpl() != null) { // TODO: deduplicate against the first part of #getValidParentSurfaceForMagnifier() final Surface mainWindowSurface = mView.getViewRootImpl().mSurface; if (mainWindowSurface != null && mainWindowSurface.isValid()) { if (mParentSurface != mContentCopySurface) { mWindowCoords.x += mViewCoordinatesInSurface[0]; mWindowCoords.y += mViewCoordinatesInSurface[1]; } } } private void performPixelCopy(final int startXInSurface, final int startYInSurface, final boolean updateWindowPosition) { // Get the view surface where the content will be copied from. final Surface surface; final int surfaceWidth; final int surfaceHeight; if (mView instanceof SurfaceView) { final SurfaceHolder surfaceHolder = ((SurfaceView) mView).getHolder(); surface = surfaceHolder.getSurface(); surfaceWidth = surfaceHolder.getSurfaceFrame().right; surfaceHeight = surfaceHolder.getSurfaceFrame().bottom; } else if (mView.getViewRootImpl() != null) { final ViewRootImpl viewRootImpl = mView.getViewRootImpl(); surface = viewRootImpl.mSurface; final Rect surfaceInsets = viewRootImpl.mWindowAttributes.surfaceInsets; surfaceWidth = viewRootImpl.getWidth() + surfaceInsets.left + surfaceInsets.right; surfaceHeight = viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; } else { surface = null; surfaceWidth = NONEXISTENT_PREVIOUS_CONFIG_VALUE; surfaceHeight = NONEXISTENT_PREVIOUS_CONFIG_VALUE; } if (surface == null || !surface.isValid()) { if (mContentCopySurface.mSurface == null || !mContentCopySurface.mSurface.isValid()) { return; } // Clamp copy coordinates inside the surface to avoid displaying distorted content. final int clampedStartXInSurface = Math.max(0, Math.min(startXInSurface, surfaceWidth - mBitmapWidth)); Math.min(startXInSurface, mContentCopySurface.mWidth - mBitmapWidth)); final int clampedStartYInSurface = Math.max(0, Math.min(startYInSurface, surfaceHeight - mBitmapHeight)); Math.min(startYInSurface, mContentCopySurface.mHeight - mBitmapHeight)); // Clamp window coordinates inside the parent surface, to avoid displaying // the magnifier out of screen or overlapping with system insets. Rect windowBounds = null; if (mView.getViewRootImpl() != null) { // TODO: deduplicate against the first part of #getValidParentSurfaceForMagnifier() // TODO: deduplicate against the first part of the current method final ViewRootImpl viewRootImpl = mView.getViewRootImpl(); final Surface parentSurface = viewRootImpl.mSurface; final Rect surfaceInsets = viewRootImpl.mWindowAttributes.surfaceInsets; final int parentWidth = viewRootImpl.getWidth() + surfaceInsets.left + surfaceInsets.right; final int parentHeight = viewRootImpl.getHeight() + surfaceInsets.top + surfaceInsets.bottom; if (parentSurface != null && parentSurface.isValid()) { final Rect windowBounds; if (mParentSurface.mIsMainWindowSurface) { final Rect systemInsets = mView.getRootWindowInsets().getSystemWindowInsets(); windowBounds = new Rect(systemInsets.left, systemInsets.top, parentWidth - systemInsets.right, parentHeight - systemInsets.bottom); } } if (windowBounds == null && mView instanceof SurfaceView) { windowBounds = ((SurfaceView) mView).getHolder().getSurfaceFrame(); mParentSurface.mWidth - systemInsets.right, mParentSurface.mHeight - systemInsets.bottom); } else { windowBounds = new Rect(0, 0, mParentSurface.mWidth, mParentSurface.mHeight); } final int windowCoordsX = Math.max(windowBounds.left, Math.min(windowBounds.right - mWindowWidth, mWindowCoords.x)); final int windowCoordsY = Math.max(windowBounds.top, Loading @@ -376,7 +376,7 @@ public final class Magnifier { final InternalPopupWindow currentWindowInstance = mWindow; final Bitmap bitmap = Bitmap.createBitmap(mBitmapWidth, mBitmapHeight, Bitmap.Config.ARGB_8888); PixelCopy.request(surface, mPixelCopyRequestRect, bitmap, PixelCopy.request(mContentCopySurface.mSurface, mPixelCopyRequestRect, bitmap, result -> { synchronized (mLock) { if (mWindow != currentWindowInstance) { Loading @@ -395,6 +395,26 @@ public final class Magnifier { mPrevStartCoordsInSurface.y = startYInSurface; } /** * Contains a surface and metadata corresponding to it. */ private static class SurfaceInfo { public static final SurfaceInfo NULL = new SurfaceInfo(null, 0, 0, false); private Surface mSurface; private int mWidth; private int mHeight; private boolean mIsMainWindowSurface; SurfaceInfo(final Surface surface, final int width, final int height, final boolean isMainWindowSurface) { mSurface = surface; mWidth = width; mHeight = height; mIsMainWindowSurface = isMainWindowSurface; } } /** * Magnifier's own implementation of PopupWindow-similar floating window. * This exists to ensure frame-synchronization between window position updates and window Loading
core/res/res/layout/magnifier.xmldeleted 100644 → 0 +0 −35 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <!-- ~ Copyright (C) 2017 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 --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/magnifier_inner" android:layout_width="@android:dimen/magnifier_width" android:layout_height="@android:dimen/magnifier_height" android:elevation="@android:dimen/magnifier_elevation" android:background="?android:attr/floatingToolbarPopupBackgroundDrawable" android:scaleType="fitXY"> <ImageView android:id="@+id/magnifier_image" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> </LinearLayout>
core/res/res/values/symbols.xml +0 −3 Original line number Diff line number Diff line Loading @@ -2587,9 +2587,6 @@ <java-symbol type="attr" name="floatingToolbarDividerColor" /> <!-- Magnifier --> <java-symbol type="id" name="magnifier_image" /> <java-symbol type="id" name="magnifier_inner" /> <java-symbol type="layout" name="magnifier" /> <java-symbol type="dimen" name="magnifier_width" /> <java-symbol type="dimen" name="magnifier_height" /> <java-symbol type="dimen" name="magnifier_elevation" /> Loading