Merge "Introduce @hide ParcelableHandwritingGesture"

This commit is contained in:
Yohei Yukawa
2022-10-31 23:20:30 +00:00
committed by Android (Google) Code Review
7 changed files with 284 additions and 127 deletions

View File

@@ -26,18 +26,12 @@ import android.os.ResultReceiver;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.DeleteGesture;
import android.view.inputmethod.DeleteRangeGesture;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.HandwritingGesture;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InsertGesture;
import android.view.inputmethod.JoinOrSplitGesture;
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
import android.view.inputmethod.ParcelableHandwritingGesture;
import android.view.inputmethod.SurroundingText;
import android.view.inputmethod.TextAttribute;
@@ -637,50 +631,19 @@ final class IRemoteInputConnectionInvoker {
}
/**
* Invokes one of {@link IRemoteInputConnection#performHandwritingSelectGesture},
* {@link IRemoteInputConnection#performHandwritingSelectRangeGesture},
* {@link IRemoteInputConnection#performHandwritingDeleteGesture},
* {@link IRemoteInputConnection#performHandwritingDeleteRangeGesture},
* {@link IRemoteInputConnection#performHandwritingInsertGesture},
* {@link IRemoteInputConnection#performHandwritingRemoveSpaceGesture},
* {@link IRemoteInputConnection#performHandwritingJoinOrSplitGesture}.
* Invokes {@link IRemoteInputConnection#performHandwritingGesture(
* InputConnectionCommandHeader, ParcelableHandwritingGesture, ResultReceiver)}.
*/
@AnyThread
public void performHandwritingGesture(
@NonNull HandwritingGesture gesture, @Nullable @CallbackExecutor Executor executor,
@Nullable IntConsumer consumer) {
public void performHandwritingGesture(@NonNull ParcelableHandwritingGesture gesture,
@Nullable @CallbackExecutor Executor executor, @Nullable IntConsumer consumer) {
ResultReceiver resultReceiver = null;
if (consumer != null) {
Objects.requireNonNull(executor);
resultReceiver = new IntResultReceiver(executor, consumer);
}
try {
if (gesture instanceof SelectGesture) {
mConnection.performHandwritingSelectGesture(
createHeader(), (SelectGesture) gesture, resultReceiver);
} else if (gesture instanceof SelectRangeGesture) {
mConnection.performHandwritingSelectRangeGesture(
createHeader(), (SelectRangeGesture) gesture, resultReceiver);
} else if (gesture instanceof InsertGesture) {
mConnection.performHandwritingInsertGesture(
createHeader(), (InsertGesture) gesture, resultReceiver);
} else if (gesture instanceof DeleteGesture) {
mConnection.performHandwritingDeleteGesture(
createHeader(), (DeleteGesture) gesture, resultReceiver);
} else if (gesture instanceof DeleteRangeGesture) {
mConnection.performHandwritingDeleteRangeGesture(
createHeader(), (DeleteRangeGesture) gesture, resultReceiver);
} else if (gesture instanceof RemoveSpaceGesture) {
mConnection.performHandwritingRemoveSpaceGesture(
createHeader(), (RemoveSpaceGesture) gesture, resultReceiver);
} else if (gesture instanceof JoinOrSplitGesture) {
mConnection.performHandwritingJoinOrSplitGesture(
createHeader(), (JoinOrSplitGesture) gesture, resultReceiver);
} else if (consumer != null && executor != null) {
executor.execute(()
-> consumer.accept(InputConnection.HANDWRITING_GESTURE_RESULT_UNSUPPORTED));
}
mConnection.performHandwritingGesture(createHeader(), gesture, resultReceiver);
} catch (RemoteException e) {
if (consumer != null && executor != null) {
executor.execute(() -> consumer.accept(

View File

@@ -32,6 +32,7 @@ import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.HandwritingGesture;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.ParcelableHandwritingGesture;
import android.view.inputmethod.SurroundingText;
import android.view.inputmethod.TextAttribute;
@@ -418,7 +419,8 @@ final class RemoteInputConnection implements InputConnection {
public void performHandwritingGesture(
@NonNull HandwritingGesture gesture, @Nullable @CallbackExecutor Executor executor,
@Nullable IntConsumer consumer) {
mInvoker.performHandwritingGesture(gesture, executor, consumer);
mInvoker.performHandwritingGesture(ParcelableHandwritingGesture.of(gesture), executor,
consumer);
}
@AnyThread

View File

@@ -0,0 +1,19 @@
/*
* 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;
parcelable ParcelableHandwritingGesture;

View File

@@ -0,0 +1,109 @@
/*
* 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 android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* A generic container of parcelable {@link HandwritingGesture}.
*
* @hide
*/
public final class ParcelableHandwritingGesture implements Parcelable {
@NonNull
private final HandwritingGesture mGesture;
@NonNull
private final Parcelable mGestureAsParcelable;
private ParcelableHandwritingGesture(@NonNull HandwritingGesture gesture) {
mGesture = gesture;
// For fail-fast.
mGestureAsParcelable = (Parcelable) gesture;
}
/**
* Creates {@link ParcelableHandwritingGesture} from {@link HandwritingGesture}, which also
* implements {@link Parcelable}.
*
* @param gesture {@link HandwritingGesture} object to be stored.
* @return {@link ParcelableHandwritingGesture} to be stored in {@link Parcel}.
*/
@NonNull
public static ParcelableHandwritingGesture of(@NonNull HandwritingGesture gesture) {
return new ParcelableHandwritingGesture(Objects.requireNonNull(gesture));
}
/**
* @return {@link HandwritingGesture} object stored in this container.
*/
@NonNull
public HandwritingGesture get() {
return mGesture;
}
private static HandwritingGesture createFromParcelInternal(
@HandwritingGesture.GestureType int gestureType, @NonNull Parcel parcel) {
switch (gestureType) {
case HandwritingGesture.GESTURE_TYPE_NONE:
throw new UnsupportedOperationException("GESTURE_TYPE_NONE is not supported");
case HandwritingGesture.GESTURE_TYPE_SELECT:
return SelectGesture.CREATOR.createFromParcel(parcel);
case HandwritingGesture.GESTURE_TYPE_SELECT_RANGE:
return SelectRangeGesture.CREATOR.createFromParcel(parcel);
case HandwritingGesture.GESTURE_TYPE_INSERT:
return InsertGesture.CREATOR.createFromParcel(parcel);
case HandwritingGesture.GESTURE_TYPE_DELETE:
return DeleteGesture.CREATOR.createFromParcel(parcel);
case HandwritingGesture.GESTURE_TYPE_DELETE_RANGE:
return DeleteRangeGesture.CREATOR.createFromParcel(parcel);
case HandwritingGesture.GESTURE_TYPE_JOIN_OR_SPLIT:
return JoinOrSplitGesture.CREATOR.createFromParcel(parcel);
case HandwritingGesture.GESTURE_TYPE_REMOVE_SPACE:
return RemoveSpaceGesture.CREATOR.createFromParcel(parcel);
default:
throw new UnsupportedOperationException("Unknown type=" + gestureType);
}
}
public static final Creator<ParcelableHandwritingGesture> CREATOR = new Parcelable.Creator<>() {
@Override
public ParcelableHandwritingGesture createFromParcel(Parcel in) {
final int gestureType = in.readInt();
return new ParcelableHandwritingGesture(createFromParcelInternal(gestureType, in));
}
@Override
public ParcelableHandwritingGesture[] newArray(int size) {
return new ParcelableHandwritingGesture[size];
}
};
@Override
public int describeContents() {
return mGestureAsParcelable.describeContents();
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mGesture.getGestureType());
mGestureAsParcelable.writeToParcel(dest, flags);
}
}

View File

@@ -982,62 +982,9 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
@Dispatching(cancellable = true)
@Override
public void performHandwritingSelectGesture(
InputConnectionCommandHeader header, SelectGesture gesture,
public void performHandwritingGesture(
InputConnectionCommandHeader header, ParcelableHandwritingGesture gestureContainer,
ResultReceiver resultReceiver) {
performHandwritingGestureInternal(header, gesture, resultReceiver);
}
@Dispatching(cancellable = true)
@Override
public void performHandwritingSelectRangeGesture(
InputConnectionCommandHeader header, SelectRangeGesture gesture,
ResultReceiver resultReceiver) {
performHandwritingGestureInternal(header, gesture, resultReceiver);
}
@Dispatching(cancellable = true)
@Override
public void performHandwritingInsertGesture(
InputConnectionCommandHeader header, InsertGesture gesture,
ResultReceiver resultReceiver) {
performHandwritingGestureInternal(header, gesture, resultReceiver);
}
@Dispatching(cancellable = true)
@Override
public void performHandwritingDeleteGesture(
InputConnectionCommandHeader header, DeleteGesture gesture,
ResultReceiver resultReceiver) {
performHandwritingGestureInternal(header, gesture, resultReceiver);
}
@Dispatching(cancellable = true)
@Override
public void performHandwritingDeleteRangeGesture(
InputConnectionCommandHeader header, DeleteRangeGesture gesture,
ResultReceiver resultReceiver) {
performHandwritingGestureInternal(header, gesture, resultReceiver);
}
@Dispatching(cancellable = true)
@Override
public void performHandwritingRemoveSpaceGesture(
InputConnectionCommandHeader header, RemoveSpaceGesture gesture,
ResultReceiver resultReceiver) {
performHandwritingGestureInternal(header, gesture, resultReceiver);
}
@Dispatching(cancellable = true)
@Override
public void performHandwritingJoinOrSplitGesture(
InputConnectionCommandHeader header, JoinOrSplitGesture gesture,
ResultReceiver resultReceiver) {
performHandwritingGestureInternal(header, gesture, resultReceiver);
}
private <T extends HandwritingGesture> void performHandwritingGestureInternal(
InputConnectionCommandHeader header, T gesture, ResultReceiver resultReceiver) {
dispatchWithTracing("performHandwritingGesture", () -> {
if (header.mSessionId != mCurrentSessionId.get()) {
if (resultReceiver != null) {
@@ -1059,7 +1006,7 @@ final class RemoteInputConnectionImpl extends IRemoteInputConnection.Stub {
// TODO(210039666): implement Cleaner to return HANDWRITING_GESTURE_RESULT_UNKNOWN if
// editor doesn't return any type.
ic.performHandwritingGesture(
gesture,
gestureContainer.get(),
resultReceiver != null ? Runnable::run : null,
resultReceiver != null
? (resultCode) -> resultReceiver.send(resultCode, null /* resultData */)

View File

@@ -21,15 +21,9 @@ import android.os.ResultReceiver;
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.DeleteGesture;
import android.view.inputmethod.DeleteRangeGesture;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputContentInfo;
import android.view.inputmethod.InsertGesture;
import android.view.inputmethod.JoinOrSplitGesture;
import android.view.inputmethod.RemoveSpaceGesture;
import android.view.inputmethod.SelectGesture;
import android.view.inputmethod.SelectRangeGesture;
import android.view.inputmethod.ParcelableHandwritingGesture;
import android.view.inputmethod.TextAttribute;
import com.android.internal.infra.AndroidFuture;
@@ -94,26 +88,8 @@ import com.android.internal.inputmethod.InputConnectionCommandHeader;
void performPrivateCommand(in InputConnectionCommandHeader header, String action,
in Bundle data);
void performHandwritingSelectGesture(in InputConnectionCommandHeader header,
in SelectGesture gesture, in ResultReceiver resultReceiver);
void performHandwritingSelectRangeGesture(in InputConnectionCommandHeader header,
in SelectRangeGesture gesture, in ResultReceiver resultReceiver);
void performHandwritingInsertGesture(in InputConnectionCommandHeader header,
in InsertGesture gesture, in ResultReceiver resultReceiver);
void performHandwritingDeleteGesture(in InputConnectionCommandHeader header,
in DeleteGesture gesture, in ResultReceiver resultReceiver);
void performHandwritingDeleteRangeGesture(in InputConnectionCommandHeader header,
in DeleteRangeGesture gesture, in ResultReceiver resultReceiver);
void performHandwritingRemoveSpaceGesture(in InputConnectionCommandHeader header,
in RemoveSpaceGesture gesture, in ResultReceiver resultReceiver);
void performHandwritingJoinOrSplitGesture(in InputConnectionCommandHeader header,
in JoinOrSplitGesture gesture, in ResultReceiver resultReceiver);
void performHandwritingGesture(in InputConnectionCommandHeader header,
in ParcelableHandwritingGesture gesture, in ResultReceiver resultReceiver);
void setComposingRegion(in InputConnectionCommandHeader header, int start, int end);

View File

@@ -0,0 +1,141 @@
/*
* 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 static org.junit.Assert.assertThrows;
import android.annotation.NonNull;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
@SmallTest
@Presubmit
@RunWith(AndroidJUnit4.class)
public class ParcelableHandwritingGestureTest {
@Test
public void testCreationFailWithNullPointerException() {
assertThrows(NullPointerException.class, () -> ParcelableHandwritingGesture.of(null));
}
@Test
public void testInvalidTypeHeader() {
Parcel parcel = null;
try {
parcel = Parcel.obtain();
// GESTURE_TYPE_NONE is not a supported header.
parcel.writeInt(HandwritingGesture.GESTURE_TYPE_NONE);
final Parcel initializedParcel = parcel;
assertThrows(UnsupportedOperationException.class,
() -> ParcelableHandwritingGesture.CREATOR.createFromParcel(initializedParcel));
} finally {
if (parcel != null) {
parcel.recycle();
}
}
}
@Test
public void testSelectGesture() {
verifyEqualityAfterUnparcel(new SelectGesture.Builder()
.setGranularity(HandwritingGesture.GRANULARITY_WORD)
.setSelectionArea(new RectF(1, 2, 3, 4))
.setFallbackText("")
.build());
}
@Test
public void testSelectRangeGesture() {
verifyEqualityAfterUnparcel(new SelectRangeGesture.Builder()
.setGranularity(HandwritingGesture.GRANULARITY_WORD)
.setSelectionStartArea(new RectF(1, 2, 3, 4))
.setSelectionEndArea(new RectF(5, 6, 7, 8))
.setFallbackText("")
.build());
}
@Test
public void testInsertGestureGesture() {
verifyEqualityAfterUnparcel(new InsertGesture.Builder()
.setTextToInsert("text")
.setInsertionPoint(new PointF(1, 1)).setFallbackText("")
.build());
}
@Test
public void testDeleteGestureGesture() {
verifyEqualityAfterUnparcel(new DeleteGesture.Builder()
.setGranularity(HandwritingGesture.GRANULARITY_WORD)
.setDeletionArea(new RectF(1, 2, 3, 4))
.setFallbackText("")
.build());
}
@Test
public void testDeleteRangeGestureGesture() {
verifyEqualityAfterUnparcel(new DeleteRangeGesture.Builder()
.setGranularity(HandwritingGesture.GRANULARITY_WORD)
.setDeletionStartArea(new RectF(1, 2, 3, 4))
.setDeletionEndArea(new RectF(5, 6, 7, 8))
.setFallbackText("")
.build());
}
@Test
public void testRemoveSpaceGestureGesture() {
verifyEqualityAfterUnparcel(new RemoveSpaceGesture.Builder()
.setPoints(new PointF(1f, 2f), new PointF(3f, 4f))
.setFallbackText("")
.build());
}
@Test
public void testJoinOrSplitGestureGesture() {
verifyEqualityAfterUnparcel(new JoinOrSplitGesture.Builder()
.setJoinOrSplitPoint(new PointF(1f, 2f))
.setFallbackText("")
.build());
}
static void verifyEqualityAfterUnparcel(@NonNull HandwritingGesture gesture) {
assertEquals(gesture, cloneViaParcel(ParcelableHandwritingGesture.of(gesture)).get());
}
private static ParcelableHandwritingGesture cloneViaParcel(
@NonNull ParcelableHandwritingGesture original) {
Parcel parcel = null;
try {
parcel = Parcel.obtain();
original.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
return ParcelableHandwritingGesture.CREATOR.createFromParcel(parcel);
} finally {
if (parcel != null) {
parcel.recycle();
}
}
}
}