Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e9490612 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Introduce @hide ParcelableHandwritingGesture

This is a follow up CL to our previous CL [1], which introduced
HandwritingGesture and several subclasses.

One of the challenge is that we only wanted to make child classes
Parcelable, while keeping the abstract base class HandwritingGesture
non-Parcelable.  Although InputConnection has only one method

  InputConnection#performHandwritingGesture(
          HandwritingGesture, ResultReceiver),

in the IPC layer IRemoteInputConnection needed to define methods for
each subclass, e.g.

 * performHandwritingSelectGesture(in InputConnectionCommandHeader,
       in SelectGesture, ...)
 * performHandwritingInsertGesture(in InputConnectionCommandHeader,
       in InsertGesture, ...)
 * performHandwritingDeleteGesture(in InputConnectionCommandHeader,
       in DeleteGesture, ...)

because their abstract class HandwritingGesture is not Parcelable.

To avoid such method definitions (and lots of type-based dispatching /
merging logic), this CL introduces

  ParcelableHandwritingGesture

as a generic Parcelable container of HandwritingGesture subclasses.
You can freely use ParcelableHandwritingGesture in AIDL method
definitions as follows.

  performHandwritingGesture(in InputConnectionCommandHeader,
        in ParcelableHandwritingGesture, ...)

In the Java side, you can easily wrap objects as follows.

  var parcelableGesture = ParcelableHandwritingGesture.of(gesture);
  var unparceledGesture = parcelableGesture.get();

Note that this CL is still an internal cleanup. There must be no
developer observable behavior change.

 [1]: I53bcb62e03ac1c371feb60d1385c88c921754092
      3e3ff1a3

Bug: 234882948
Bug: 239783077
Test: presubmit
Test: atest FrameworksCoreTests:ParcelableHandwritingGestureTest
Change-Id: I158026087653f6772a78cc2394e678ae9741fb00
parent a99bb97e
Loading
Loading
Loading
Loading
+6 −43
Original line number Diff line number Diff line
@@ -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(
+3 −1
Original line number Diff line number Diff line
@@ -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
+19 −0
Original line number Diff line number Diff line
/*
 * 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;
+109 −0
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+3 −56
Original line number Diff line number Diff line
@@ -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 */)
Loading