Loading core/java/android/widget/Editor.java +38 −6 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; import android.view.ActionMode.Callback; import android.view.ContextMenu; Loading Loading @@ -394,6 +395,19 @@ public class Editor { // Specifies whether the new magnifier (with fish-eye effect) is enabled. private final boolean mNewMagnifierEnabled; // Line height range in DP for the new magnifier. static private final int MIN_LINE_HEIGHT_FOR_MAGNIFIER = 20; static private final int MAX_LINE_HEIGHT_FOR_MAGNIFIER = 32; // Line height range in pixels for the new magnifier. // - If the line height is bigger than the max, magnifier should be dismissed. // - If the line height is smaller than the min, magnifier should apply a bigger zoom factor // to make sure the text can be seen clearly. private int mMinLineHeightForMagnifier; private int mMaxLineHeightForMagnifier; // The zoom factor initially configured. // The actual zoom value may changes based on this initial zoom value. private float mInitialZoom = 1f; Editor(TextView textView) { mTextView = textView; // Synchronize the filter list, which places the undo input filter at the end. Loading Loading @@ -440,8 +454,6 @@ public class Editor { private Magnifier.Builder createBuilderWithInlineMagnifierDefaults() { final Magnifier.Builder params = new Magnifier.Builder(mTextView); // TODO: supports changing the height/width dynamically because the text height can be // dynamically changed. float zoom = AppGlobals.getFloatCoreSetting( WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, 1.5f); float aspectRatio = AppGlobals.getFloatCoreSetting( Loading @@ -454,13 +466,20 @@ public class Editor { aspectRatio = 5.5f; } mInitialZoom = zoom; mMinLineHeightForMagnifier = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, MIN_LINE_HEIGHT_FOR_MAGNIFIER, mTextView.getContext().getResources().getDisplayMetrics()); mMaxLineHeightForMagnifier = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, MAX_LINE_HEIGHT_FOR_MAGNIFIER, mTextView.getContext().getResources().getDisplayMetrics()); final Layout layout = mTextView.getLayout(); final int line = layout.getLineForOffset(mTextView.getSelectionStart()); final int sourceHeight = layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line); // Slightly increase the height to avoid tooLargeTextForMagnifier() returns true. int height = (int)(sourceHeight * zoom) + 2; int width = (int)(aspectRatio * height); final int height = (int)(sourceHeight * zoom); final int width = (int)(aspectRatio * Math.max(sourceHeight, mMinLineHeightForMagnifier)); params.setFishEyeStyle() .setSize(width, height) Loading Loading @@ -4902,6 +4921,12 @@ public class Editor { } private boolean tooLargeTextForMagnifier() { if (mNewMagnifierEnabled) { Layout layout = mTextView.getLayout(); final int line = layout.getLineForOffset(getCurrentCursorOffset()); return layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line) >= mMaxLineHeightForMagnifier; } final float magnifierContentHeight = Math.round( mMagnifierAnimator.mMagnifier.getHeight() / mMagnifierAnimator.mMagnifier.getZoom()); Loading Loading @@ -5111,6 +5136,13 @@ public class Editor { int lineRight = (int) layout.getLineRight(line); lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight); final int lineHeight = layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line); float zoom = mInitialZoom; if (lineHeight < mMinLineHeightForMagnifier) { zoom = zoom * mMinLineHeightForMagnifier / lineHeight; } mMagnifierAnimator.mMagnifier.updateSourceFactors(lineHeight, zoom); mMagnifierAnimator.mMagnifier.show(showPosInView.x, showPosInView.y); } else { mMagnifierAnimator.show(showPosInView.x, showPosInView.y); Loading core/java/android/widget/Magnifier.java +75 −8 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ public final class Magnifier { // The width of the window containing the magnifier. private final int mWindowWidth; // The height of the window containing the magnifier. private final int mWindowHeight; private int mWindowHeight; // The zoom applied to the view region copied to the magnifier view. private float mZoom; // The width of the content that will be copied to the magnifier. Loading Loading @@ -484,6 +484,21 @@ public final class Magnifier { mDirtyState = true; } /** * Updates the factors of source which may impact the magnifier's size. * This can be called while the magnifier is showing and moving. * @param sourceHeight the new source height. * @param zoom the new zoom factor. */ void updateSourceFactors(final int sourceHeight, final float zoom) { mZoom = zoom; mSourceHeight = sourceHeight; mWindowHeight = (int) (sourceHeight * zoom); if (mWindow != null) { mWindow.updateContentFactors(mWindowHeight, zoom); } } /** * Returns the zoom to be applied to the magnified view region copied to the magnifier. * If the zoom is x and the magnifier window size is (width, height), the original size Loading Loading @@ -904,7 +919,7 @@ public final class Magnifier { private final Display mDisplay; // The size of the content of the magnifier. private final int mContentWidth; private final int mContentHeight; private int mContentHeight; // The insets of the content inside the allocated surface. private final int mOffsetX; private final int mOffsetY; Loading Loading @@ -947,7 +962,7 @@ public final class Magnifier { // The current content of the magnifier. It is mBitmap + mOverlay, only used for testing. private Bitmap mCurrentContent; private final float mZoom; private float mZoom; // The width of the ramp region in pixels on the left & right sides of the fish-eye effect. private final int mRamp; // Whether is in the new magnifier style. Loading Loading @@ -1009,11 +1024,11 @@ public final class Magnifier { final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(width, height); try { canvas.insertReorderBarrier(); canvas.enableZ(); canvas.drawRenderNode(mBitmapRenderNode); canvas.insertInorderBarrier(); canvas.disableZ(); canvas.drawRenderNode(mOverlayRenderNode); canvas.insertInorderBarrier(); canvas.disableZ(); } finally { mRenderer.getRootNode().endRecording(); } Loading @@ -1034,15 +1049,66 @@ public final class Magnifier { } } /** * Updates the factors of content which may resize the window. * @param contentHeight the new height of content. * @param zoom the new zoom factor. */ private void updateContentFactors(final int contentHeight, final float zoom) { if (mContentHeight == contentHeight && mZoom == zoom) { return; } if (mContentHeight < contentHeight) { // Grows the surface height as necessary. new SurfaceControl.Transaction().setBufferSize( mSurfaceControl, mContentWidth, contentHeight).apply(); mSurface.copyFrom(mSurfaceControl); mRenderer.setSurface(mSurface); final Outline outline = new Outline(); outline.setRoundRect(0, 0, mContentWidth, contentHeight, 0); outline.setAlpha(1.0f); mBitmapRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY, mOffsetX + mContentWidth, mOffsetY + contentHeight); mBitmapRenderNode.setOutline(outline); mOverlayRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY, mOffsetX + mContentWidth, mOffsetY + contentHeight); mOverlayRenderNode.setOutline(outline); final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(mContentWidth, contentHeight); try { canvas.enableZ(); canvas.drawRenderNode(mBitmapRenderNode); canvas.disableZ(); canvas.drawRenderNode(mOverlayRenderNode); canvas.disableZ(); } finally { mRenderer.getRootNode().endRecording(); } } mContentHeight = contentHeight; mZoom = zoom; fillMeshMatrix(); } private void createMeshMatrixForFishEyeEffect() { mMeshWidth = 1; mMeshHeight = 6; mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; fillMeshMatrix(); } private void fillMeshMatrix() { mMeshWidth = 1; mMeshHeight = 6; final float w = mContentWidth; final float h = mContentHeight; final float h0 = h / mZoom; final float dh = h - h0; mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; for (int i = 0; i < 2 * (mMeshWidth + 1) * (mMeshHeight + 1); i += 2) { // Calculates X value. final int colIndex = i % (2 * (mMeshWidth + 1)) / 2; Loading Loading @@ -1197,6 +1263,7 @@ public final class Magnifier { if (mBitmap != null) { mBitmap.recycle(); } mOverlay.setCallback(null); } private void doDraw() { Loading Loading
core/java/android/widget/Editor.java +38 −6 Original line number Diff line number Diff line Loading @@ -83,6 +83,7 @@ import android.util.ArraySet; import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseArray; import android.util.TypedValue; import android.view.ActionMode; import android.view.ActionMode.Callback; import android.view.ContextMenu; Loading Loading @@ -394,6 +395,19 @@ public class Editor { // Specifies whether the new magnifier (with fish-eye effect) is enabled. private final boolean mNewMagnifierEnabled; // Line height range in DP for the new magnifier. static private final int MIN_LINE_HEIGHT_FOR_MAGNIFIER = 20; static private final int MAX_LINE_HEIGHT_FOR_MAGNIFIER = 32; // Line height range in pixels for the new magnifier. // - If the line height is bigger than the max, magnifier should be dismissed. // - If the line height is smaller than the min, magnifier should apply a bigger zoom factor // to make sure the text can be seen clearly. private int mMinLineHeightForMagnifier; private int mMaxLineHeightForMagnifier; // The zoom factor initially configured. // The actual zoom value may changes based on this initial zoom value. private float mInitialZoom = 1f; Editor(TextView textView) { mTextView = textView; // Synchronize the filter list, which places the undo input filter at the end. Loading Loading @@ -440,8 +454,6 @@ public class Editor { private Magnifier.Builder createBuilderWithInlineMagnifierDefaults() { final Magnifier.Builder params = new Magnifier.Builder(mTextView); // TODO: supports changing the height/width dynamically because the text height can be // dynamically changed. float zoom = AppGlobals.getFloatCoreSetting( WidgetFlags.KEY_MAGNIFIER_ZOOM_FACTOR, 1.5f); float aspectRatio = AppGlobals.getFloatCoreSetting( Loading @@ -454,13 +466,20 @@ public class Editor { aspectRatio = 5.5f; } mInitialZoom = zoom; mMinLineHeightForMagnifier = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, MIN_LINE_HEIGHT_FOR_MAGNIFIER, mTextView.getContext().getResources().getDisplayMetrics()); mMaxLineHeightForMagnifier = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, MAX_LINE_HEIGHT_FOR_MAGNIFIER, mTextView.getContext().getResources().getDisplayMetrics()); final Layout layout = mTextView.getLayout(); final int line = layout.getLineForOffset(mTextView.getSelectionStart()); final int sourceHeight = layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line); // Slightly increase the height to avoid tooLargeTextForMagnifier() returns true. int height = (int)(sourceHeight * zoom) + 2; int width = (int)(aspectRatio * height); final int height = (int)(sourceHeight * zoom); final int width = (int)(aspectRatio * Math.max(sourceHeight, mMinLineHeightForMagnifier)); params.setFishEyeStyle() .setSize(width, height) Loading Loading @@ -4902,6 +4921,12 @@ public class Editor { } private boolean tooLargeTextForMagnifier() { if (mNewMagnifierEnabled) { Layout layout = mTextView.getLayout(); final int line = layout.getLineForOffset(getCurrentCursorOffset()); return layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line) >= mMaxLineHeightForMagnifier; } final float magnifierContentHeight = Math.round( mMagnifierAnimator.mMagnifier.getHeight() / mMagnifierAnimator.mMagnifier.getZoom()); Loading Loading @@ -5111,6 +5136,13 @@ public class Editor { int lineRight = (int) layout.getLineRight(line); lineRight += mTextView.getTotalPaddingLeft() - mTextView.getScrollX(); mMagnifierAnimator.mMagnifier.setSourceHorizontalBounds(lineLeft, lineRight); final int lineHeight = layout.getLineBottomWithoutSpacing(line) - layout.getLineTop(line); float zoom = mInitialZoom; if (lineHeight < mMinLineHeightForMagnifier) { zoom = zoom * mMinLineHeightForMagnifier / lineHeight; } mMagnifierAnimator.mMagnifier.updateSourceFactors(lineHeight, zoom); mMagnifierAnimator.mMagnifier.show(showPosInView.x, showPosInView.y); } else { mMagnifierAnimator.show(showPosInView.x, showPosInView.y); Loading
core/java/android/widget/Magnifier.java +75 −8 Original line number Diff line number Diff line Loading @@ -89,7 +89,7 @@ public final class Magnifier { // The width of the window containing the magnifier. private final int mWindowWidth; // The height of the window containing the magnifier. private final int mWindowHeight; private int mWindowHeight; // The zoom applied to the view region copied to the magnifier view. private float mZoom; // The width of the content that will be copied to the magnifier. Loading Loading @@ -484,6 +484,21 @@ public final class Magnifier { mDirtyState = true; } /** * Updates the factors of source which may impact the magnifier's size. * This can be called while the magnifier is showing and moving. * @param sourceHeight the new source height. * @param zoom the new zoom factor. */ void updateSourceFactors(final int sourceHeight, final float zoom) { mZoom = zoom; mSourceHeight = sourceHeight; mWindowHeight = (int) (sourceHeight * zoom); if (mWindow != null) { mWindow.updateContentFactors(mWindowHeight, zoom); } } /** * Returns the zoom to be applied to the magnified view region copied to the magnifier. * If the zoom is x and the magnifier window size is (width, height), the original size Loading Loading @@ -904,7 +919,7 @@ public final class Magnifier { private final Display mDisplay; // The size of the content of the magnifier. private final int mContentWidth; private final int mContentHeight; private int mContentHeight; // The insets of the content inside the allocated surface. private final int mOffsetX; private final int mOffsetY; Loading Loading @@ -947,7 +962,7 @@ public final class Magnifier { // The current content of the magnifier. It is mBitmap + mOverlay, only used for testing. private Bitmap mCurrentContent; private final float mZoom; private float mZoom; // The width of the ramp region in pixels on the left & right sides of the fish-eye effect. private final int mRamp; // Whether is in the new magnifier style. Loading Loading @@ -1009,11 +1024,11 @@ public final class Magnifier { final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(width, height); try { canvas.insertReorderBarrier(); canvas.enableZ(); canvas.drawRenderNode(mBitmapRenderNode); canvas.insertInorderBarrier(); canvas.disableZ(); canvas.drawRenderNode(mOverlayRenderNode); canvas.insertInorderBarrier(); canvas.disableZ(); } finally { mRenderer.getRootNode().endRecording(); } Loading @@ -1034,15 +1049,66 @@ public final class Magnifier { } } /** * Updates the factors of content which may resize the window. * @param contentHeight the new height of content. * @param zoom the new zoom factor. */ private void updateContentFactors(final int contentHeight, final float zoom) { if (mContentHeight == contentHeight && mZoom == zoom) { return; } if (mContentHeight < contentHeight) { // Grows the surface height as necessary. new SurfaceControl.Transaction().setBufferSize( mSurfaceControl, mContentWidth, contentHeight).apply(); mSurface.copyFrom(mSurfaceControl); mRenderer.setSurface(mSurface); final Outline outline = new Outline(); outline.setRoundRect(0, 0, mContentWidth, contentHeight, 0); outline.setAlpha(1.0f); mBitmapRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY, mOffsetX + mContentWidth, mOffsetY + contentHeight); mBitmapRenderNode.setOutline(outline); mOverlayRenderNode.setLeftTopRightBottom(mOffsetX, mOffsetY, mOffsetX + mContentWidth, mOffsetY + contentHeight); mOverlayRenderNode.setOutline(outline); final RecordingCanvas canvas = mRenderer.getRootNode().beginRecording(mContentWidth, contentHeight); try { canvas.enableZ(); canvas.drawRenderNode(mBitmapRenderNode); canvas.disableZ(); canvas.drawRenderNode(mOverlayRenderNode); canvas.disableZ(); } finally { mRenderer.getRootNode().endRecording(); } } mContentHeight = contentHeight; mZoom = zoom; fillMeshMatrix(); } private void createMeshMatrixForFishEyeEffect() { mMeshWidth = 1; mMeshHeight = 6; mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; fillMeshMatrix(); } private void fillMeshMatrix() { mMeshWidth = 1; mMeshHeight = 6; final float w = mContentWidth; final float h = mContentHeight; final float h0 = h / mZoom; final float dh = h - h0; mMeshLeft = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; mMeshRight = new float[2 * (mMeshWidth + 1) * (mMeshHeight + 1)]; for (int i = 0; i < 2 * (mMeshWidth + 1) * (mMeshHeight + 1); i += 2) { // Calculates X value. final int colIndex = i % (2 * (mMeshWidth + 1)) / 2; Loading Loading @@ -1197,6 +1263,7 @@ public final class Magnifier { if (mBitmap != null) { mBitmap.recycle(); } mOverlay.setCallback(null); } private void doDraw() { Loading