Reland CursorAnchorInfo#createForAdditionalParentMatrix()

This logically relands the CL [1], which added an @hide method
CursorAnchorInfo#createForAdditionalParentMatrix().
The corresponding change was once removed in [2].
This is a preparation to reland a change that supports
InputMethodManager#reportActivityView() again.

[1] Ic7f9057623ffc61ec7a6121735dc39adecf4649d
[2] I0a05453eeed863db5bfe4b965ab4bcbad67f2783

Bug: 224424149
Test: CursorAnchorInfoTest
Change-Id: I0a411453c7c26795d28e913a96be8eb8fa3684d7
This commit is contained in:
Hiroki Sato
2022-03-24 15:17:55 +09:00
parent ba57fccde4
commit 62af809a65
2 changed files with 146 additions and 21 deletions

View File

@@ -415,7 +415,7 @@ public final class CursorAnchorInfo implements Parcelable {
"required when positional parameters are specified.");
}
}
return new CursorAnchorInfo(this);
return CursorAnchorInfo.create(this);
}
/**
@@ -440,31 +440,93 @@ public final class CursorAnchorInfo implements Parcelable {
}
}
private CursorAnchorInfo(final Builder builder) {
mSelectionStart = builder.mSelectionStart;
mSelectionEnd = builder.mSelectionEnd;
mComposingTextStart = builder.mComposingTextStart;
mComposingText = builder.mComposingText;
mInsertionMarkerFlags = builder.mInsertionMarkerFlags;
mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal;
mInsertionMarkerTop = builder.mInsertionMarkerTop;
mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline;
mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
mCharacterBoundsArray = builder.mCharacterBoundsArrayBuilder != null
? builder.mCharacterBoundsArrayBuilder.build() : null;
mEditorBoundsInfo = builder.mEditorBoundsInfo;
mMatrixValues = new float[9];
private static CursorAnchorInfo create(Builder builder) {
final SparseRectFArray characterBoundsArray =
builder.mCharacterBoundsArrayBuilder != null
? builder.mCharacterBoundsArrayBuilder.build()
: null;
final float[] matrixValues = new float[9];
if (builder.mMatrixInitialized) {
System.arraycopy(builder.mMatrixValues, 0, mMatrixValues, 0, 9);
System.arraycopy(builder.mMatrixValues, 0, matrixValues, 0, 9);
} else {
Matrix.IDENTITY_MATRIX.getValues(mMatrixValues);
Matrix.IDENTITY_MATRIX.getValues(matrixValues);
}
return new CursorAnchorInfo(builder.mSelectionStart, builder.mSelectionEnd,
builder.mComposingTextStart, builder.mComposingText, builder.mInsertionMarkerFlags,
builder.mInsertionMarkerHorizontal, builder.mInsertionMarkerTop,
builder.mInsertionMarkerBaseline, builder.mInsertionMarkerBottom,
characterBoundsArray, builder.mEditorBoundsInfo, matrixValues);
}
private CursorAnchorInfo(int selectionStart, int selectionEnd, int composingTextStart,
@Nullable CharSequence composingText, int insertionMarkerFlags,
float insertionMarkerHorizontal, float insertionMarkerTop,
float insertionMarkerBaseline, float insertionMarkerBottom,
@Nullable SparseRectFArray characterBoundsArray,
@Nullable EditorBoundsInfo editorBoundsInfo,
@NonNull float[] matrixValues) {
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
mComposingTextStart = composingTextStart;
mComposingText = composingText;
mInsertionMarkerFlags = insertionMarkerFlags;
mInsertionMarkerHorizontal = insertionMarkerHorizontal;
mInsertionMarkerTop = insertionMarkerTop;
mInsertionMarkerBaseline = insertionMarkerBaseline;
mInsertionMarkerBottom = insertionMarkerBottom;
mCharacterBoundsArray = characterBoundsArray;
mEditorBoundsInfo = editorBoundsInfo;
mMatrixValues = matrixValues;
// To keep hash function simple, we only use some complex objects for hash.
int hash = Objects.hashCode(mComposingText);
hash *= 31;
hash += Arrays.hashCode(mMatrixValues);
mHashCode = hash;
int hashCode = Objects.hashCode(mComposingText);
hashCode *= 31;
hashCode += Arrays.hashCode(mMatrixValues);
mHashCode = hashCode;
}
/**
* Creates a new instance of {@link CursorAnchorInfo} by applying {@code parentMatrix} to
* the coordinate transformation matrix.
*
* @param original {@link CursorAnchorInfo} to be cloned from.
* @param parentMatrix {@link Matrix} to be applied to {@code original.getMatrix()}
* @return A new instance of {@link CursorAnchorInfo} whose {@link CursorAnchorInfo#getMatrix()}
* returns {@code parentMatrix * original.getMatrix()}.
* @hide
*/
public static CursorAnchorInfo createForAdditionalParentMatrix(CursorAnchorInfo original,
@NonNull Matrix parentMatrix) {
return new CursorAnchorInfo(original.mSelectionStart, original.mSelectionEnd,
original.mComposingTextStart, original.mComposingText,
original.mInsertionMarkerFlags, original.mInsertionMarkerHorizontal,
original.mInsertionMarkerTop, original.mInsertionMarkerBaseline,
original.mInsertionMarkerBottom, original.mCharacterBoundsArray,
original.mEditorBoundsInfo, computeMatrixValues(parentMatrix, original));
}
/**
* Returns a float array that represents {@link Matrix} elements for
* {@code parentMatrix * info.getMatrix()}.
*
* @param parentMatrix {@link Matrix} to be multiplied.
* @param info {@link CursorAnchorInfo} to provide {@link Matrix} to be multiplied.
* @return {@code parentMatrix * info.getMatrix()}.
*/
private static float[] computeMatrixValues(@NonNull Matrix parentMatrix,
@NonNull CursorAnchorInfo info) {
if (parentMatrix.isIdentity()) {
return info.mMatrixValues;
}
final Matrix newMatrix = new Matrix();
newMatrix.setValues(info.mMatrixValues);
newMatrix.postConcat(parentMatrix);
final float[] matrixValues = new float[9];
newMatrix.getValues(matrixValues);
return matrixValues;
}
/**

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2022 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.inputmethod;
import static org.junit.Assert.assertEquals;
import android.graphics.Matrix;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class CursorAnchorInfoTest {
@Test
public void testCreateForAdditionalParentMatrix() {
final Matrix originalMatrix = new Matrix();
originalMatrix.setTranslate(10.0f, 20.0f);
final CursorAnchorInfo.Builder builder = new CursorAnchorInfo.Builder();
builder.setMatrix(originalMatrix);
final CursorAnchorInfo originalInstance = builder.build();
assertEquals(originalMatrix, originalInstance.getMatrix());
final Matrix additionalParentMatrix = new Matrix();
additionalParentMatrix.setTranslate(1.0f, 2.0f);
final Matrix newMatrix = new Matrix(originalMatrix);
newMatrix.postConcat(additionalParentMatrix);
builder.reset();
builder.setMatrix(newMatrix);
// An instance created by the standard Builder class.
final CursorAnchorInfo newInstanceByBuilder = builder.build();
// An instance created by an @hide method.
final CursorAnchorInfo newInstanceByMethod =
CursorAnchorInfo.createForAdditionalParentMatrix(
originalInstance, additionalParentMatrix);
assertEquals(newMatrix, newInstanceByBuilder.getMatrix());
assertEquals(newMatrix, newInstanceByMethod.getMatrix());
assertEquals(newInstanceByBuilder.hashCode(), newInstanceByMethod.hashCode());
}
}