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

Commit d20f669a authored by Taran Singh's avatar Taran Singh Committed by Automerger Merge Worker
Browse files

Merge "Use CancellationSignalBeamer in InsertMode, preview" into udc-dev am: 9647ee7e

parents e2e00307 9647ee7e
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -3601,6 +3601,11 @@ package android.view.displayhash {

package android.view.inputmethod {

  public abstract class CancellableHandwritingGesture extends android.view.inputmethod.HandwritingGesture {
    ctor public CancellableHandwritingGesture();
    method public void setCancellationSignal(@NonNull android.os.CancellationSignal);
  }

  public abstract class HandwritingGesture {
    method @NonNull public static android.view.inputmethod.HandwritingGesture fromByteArray(@NonNull byte[]);
    method public final int getGestureType();
+51 −10
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.annotation.Nullable;
import android.graphics.RectF;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.CancellationSignalBeamer;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.view.KeyEvent;
@@ -59,6 +61,7 @@ final class IRemoteInputConnectionInvoker {
    @NonNull
    private final IRemoteInputConnection mConnection;
    private final int mSessionId;
    private CancellationSignalBeamer.Sender mBeamer;

    private IRemoteInputConnectionInvoker(@NonNull IRemoteInputConnection inputConnection,
            int sessionId) {
@@ -681,7 +684,7 @@ final class IRemoteInputConnectionInvoker {
     * InputConnectionCommandHeader, ParcelableHandwritingGesture, ResultReceiver)}.
     */
    @AnyThread
    public void performHandwritingGesture(@NonNull ParcelableHandwritingGesture gesture,
    public void performHandwritingGesture(@NonNull HandwritingGesture gesture,
            @Nullable @CallbackExecutor Executor executor, @Nullable IntConsumer consumer) {
        ResultReceiver resultReceiver = null;
        if (consumer != null) {
@@ -689,7 +692,11 @@ final class IRemoteInputConnectionInvoker {
            resultReceiver = new IntResultReceiver(executor, consumer);
        }
        try {
            mConnection.performHandwritingGesture(createHeader(), gesture, resultReceiver);
            try (var ignored = getCancellationSignalBeamer().beamScopeIfNeeded(gesture)) {
                mConnection.performHandwritingGesture(createHeader(),
                        ParcelableHandwritingGesture.of(gesture),
                        resultReceiver);
            }
        } catch (RemoteException e) {
            if (consumer != null && executor != null) {
                executor.execute(() -> consumer.accept(
@@ -700,25 +707,59 @@ final class IRemoteInputConnectionInvoker {

    /**
     * Invokes one of {@link IRemoteInputConnection#previewHandwritingGesture(
     * InputConnectionCommandHeader, ParcelableHandwritingGesture, CancellationSignal)}
     * InputConnectionCommandHeader, HandwritingGesture, IBinder)}
     */
    @AnyThread
    public boolean previewHandwritingGesture(
            @NonNull ParcelableHandwritingGesture gesture,
            @NonNull HandwritingGesture gesture,
            @Nullable CancellationSignal cancellationSignal) {
        if (cancellationSignal != null && cancellationSignal.isCanceled()) {
            return false; // cancelled.
        }

        // TODO(b/254727073): Implement CancellationSignal
        try {
            mConnection.previewHandwritingGesture(createHeader(), gesture, null);
            try (var csToken = beam(cancellationSignal)) {
                mConnection.previewHandwritingGesture(createHeader(),
                        ParcelableHandwritingGesture.of(gesture),
                        csToken);
            }
            return true;
        } catch (RemoteException e) {
            return false;
        }
    }

    @Nullable
    CancellationSignalBeamer.Sender.CloseableToken beam(CancellationSignal cs) {
        if (cs == null) {
            return null;
        }
        return getCancellationSignalBeamer().beam(cs);
    }

    private CancellationSignalBeamer.Sender getCancellationSignalBeamer() {
        if (mBeamer != null) {
            return mBeamer;
        }
        mBeamer = new CancellationSignalBeamer.Sender() {
            @Override
            public void onCancel(IBinder token) {
                try {
                    mConnection.cancelCancellationSignal(token);
                } catch (RemoteException e) {
                    // Remote process likely died, ignore.
                }
            }

            @Override
            public void onForget(IBinder token) {
                try {
                    mConnection.forgetCancellationSignal(token);
                } catch (RemoteException e) {
                    // Remote process likely died, ignore.
                }
            }
        };

        return mBeamer;
    }

    /**
     * Invokes {@link IRemoteInputConnection#requestCursorUpdates(InputConnectionCommandHeader, int,
     * int, AndroidFuture)}.
+6 −5
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ 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.PreviewableHandwritingGesture;
import android.view.inputmethod.SurroundingText;
import android.view.inputmethod.TextAttribute;
@@ -424,16 +423,18 @@ final class RemoteInputConnection implements InputConnection {
    public void performHandwritingGesture(
            @NonNull HandwritingGesture gesture, @Nullable @CallbackExecutor Executor executor,
            @Nullable IntConsumer consumer) {
        mInvoker.performHandwritingGesture(ParcelableHandwritingGesture.of(gesture), executor,
                consumer);
        mInvoker.performHandwritingGesture(gesture, executor, consumer);
    }

    @AnyThread
    public boolean previewHandwritingGesture(
            @NonNull PreviewableHandwritingGesture gesture,
            @Nullable CancellationSignal cancellationSignal) {
        return mInvoker.previewHandwritingGesture(ParcelableHandwritingGesture.of(gesture),
                cancellationSignal);
        if (cancellationSignal != null && cancellationSignal.isCanceled()) {
            return false; // cancelled.
        }

        return mInvoker.previewHandwritingGesture(gesture, cancellationSignal);
    }

    @AnyThread
+61 −5
Original line number Diff line number Diff line
@@ -19,9 +19,13 @@ package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.system.SystemCleaner;
import android.util.Pair;
import android.view.inputmethod.CancellableHandwritingGesture;
import android.view.inputmethod.HandwritingGesture;

import java.lang.ref.Cleaner;
import java.lang.ref.Reference;
import java.util.ArrayList;
import java.util.HashMap;

/**
@@ -143,6 +147,58 @@ public class CancellationSignalBeamer {
         */
        public abstract void onForget(IBinder token);

        private static final ThreadLocal<Pair<Sender, ArrayList<CloseableToken>>> sScope =
                new ThreadLocal<>();

        /**
         * Beams a {@link CancellationSignal} through an existing Binder interface.
         * @param gesture {@link HandwritingGesture} that supports
         *  {@link CancellableHandwritingGesture cancellation} requesting cancellation token.
         * @return {@link IBinder} token. MUST be {@link MustClose#close}d <em>after</em>
         *  the binder call transporting it to the remote process, best with
         *  try-with-resources. {@code null} if {@code cs} was {@code null} or if
         *  {@link HandwritingGesture} isn't {@link CancellableHandwritingGesture cancellable}.
         */
        public MustClose beamScopeIfNeeded(HandwritingGesture gesture) {
            if (!(gesture instanceof CancellableHandwritingGesture)) {
                return null;
            }
            sScope.set(Pair.create(this, new ArrayList<>()));
            return () -> {
                var tokens = sScope.get().second;
                sScope.remove();
                for (int i = tokens.size() - 1; i >= 0; i--) {
                    if (tokens.get(i) != null) {
                        tokens.get(i).close();
                    }
                }
            };
        }

        /**
         * An {@link AutoCloseable} interface with {@link AutoCloseable#close()} callback.
         */
        public interface MustClose extends AutoCloseable {
            @Override
            void close();
        }

        /**
         * Beams a {@link CancellationSignal} token from existing scope created by previous call to
         * {@link #beamScopeIfNeeded()}
         * @param cs {@link CancellationSignal} for which token should be returned.
         * @return {@link IBinder} token.
         */
        public static IBinder beamFromScope(CancellationSignal cs) {
            var state = sScope.get();
            if (state != null) {
                var token = state.first.beam(cs);
                state.second.add(token);
                return token;
            }
            return null;
        }

        private static class Token extends Binder implements CloseableToken, Runnable {

            private final Sender mSender;
@@ -200,7 +256,7 @@ public class CancellationSignalBeamer {
         *
         * MUST be closed <em>after</em> it is sent over binder, ideally through try-with-resources.
         */
        public interface CloseableToken extends IBinder, AutoCloseable {
        public interface CloseableToken extends IBinder, MustClose {
            @Override
            void close(); // No throws
        }
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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.annotation.TestApi;
import android.os.CancellationSignal;
import android.os.CancellationSignalBeamer;
import android.os.IBinder;

/**
 * A {@link HandwritingGesture} that can be {@link CancellationSignal#cancel() cancelled}.
 * @hide
 */
@TestApi
public abstract class CancellableHandwritingGesture extends HandwritingGesture {
    CancellationSignal mCancellationSignal;

    IBinder mCancellationSignalToken;

    /**
     * Set {@link CancellationSignal} for testing only.
     * @hide
     */
    @TestApi
    public void setCancellationSignal(@NonNull CancellationSignal cancellationSignal) {
        mCancellationSignal = cancellationSignal;
    }

    CancellationSignal getCancellationSignal() {
        return mCancellationSignal;
    }

    void unbeamCancellationSignal(CancellationSignalBeamer.Receiver receiver) {
        mCancellationSignal = receiver.unbeam(mCancellationSignalToken);
        mCancellationSignalToken = null;
    }

}
Loading