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

Commit 0ebfd8be authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

VDM IME 2/n: setInputMethodComponent API

New VirtualDeviceParams.Builder#setInputMethodComponent API that
for now only updates a map in IMMS.

The custom VD IME cannot be changed during the device lifetime.

Bug: 287269288
Test: CTS
Change-Id: Iad2401d19482030fca072bdec48935c9b574d465
parent ddcfc905
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3247,6 +3247,7 @@ package android.companion.virtual {
    method @Deprecated public int getDefaultNavigationPolicy();
    method public int getDevicePolicy(int);
    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @Nullable public android.content.ComponentName getHomeComponent();
    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") @Nullable public android.content.ComponentName getInputMethodComponent();
    method public int getLockState();
    method @Nullable public String getName();
    method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
@@ -3280,6 +3281,7 @@ package android.companion.virtual {
    method @Deprecated @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDevicePolicy(int, int);
    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_home") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setHomeComponent(@Nullable android.content.ComponentName);
    method @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setInputMethodComponent(@Nullable android.content.ComponentName);
    method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
+50 −3
Original line number Diff line number Diff line
@@ -258,6 +258,7 @@ public final class VirtualDeviceParams implements Parcelable {
    // Mapping of @PolicyType to @DevicePolicy
    @NonNull private final SparseIntArray mDevicePolicies;
    @Nullable private final ComponentName mHomeComponent;
    @Nullable private final ComponentName mInputMethodComponent;
    @NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs;
    @Nullable private final IVirtualSensorCallback mVirtualSensorCallback;
    private final int mAudioPlaybackSessionId;
@@ -273,6 +274,7 @@ public final class VirtualDeviceParams implements Parcelable {
            @Nullable String name,
            @NonNull SparseIntArray devicePolicies,
            @Nullable ComponentName homeComponent,
            @Nullable ComponentName inputMethodComponent,
            @NonNull List<VirtualSensorConfig> virtualSensorConfigs,
            @Nullable IVirtualSensorCallback virtualSensorCallback,
            int audioPlaybackSessionId,
@@ -289,6 +291,7 @@ public final class VirtualDeviceParams implements Parcelable {
        mName = name;
        mDevicePolicies = Objects.requireNonNull(devicePolicies);
        mHomeComponent = homeComponent;
        mInputMethodComponent = inputMethodComponent;
        mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
        mVirtualSensorCallback = virtualSensorCallback;
        mAudioPlaybackSessionId = audioPlaybackSessionId;
@@ -312,6 +315,7 @@ public final class VirtualDeviceParams implements Parcelable {
        mAudioPlaybackSessionId = parcel.readInt();
        mAudioRecordingSessionId = parcel.readInt();
        mHomeComponent = parcel.readTypedObject(ComponentName.CREATOR);
        mInputMethodComponent = parcel.readTypedObject(ComponentName.CREATOR);
    }

    /**
@@ -335,6 +339,18 @@ public final class VirtualDeviceParams implements Parcelable {
        return mHomeComponent;
    }

    /**
     * Returns the custom component used as input method on all displays owned by this virtual
     * device.
     *
     * @see Builder#setInputMethodComponent
     */
    @FlaggedApi(Flags.FLAG_VDM_CUSTOM_IME)
    @Nullable
    public ComponentName getInputMethodComponent() {
        return mInputMethodComponent;
    }

    /**
     * Returns the user handles with matching managed accounts on the remote device to which
     * this virtual device is streaming.
@@ -532,6 +548,7 @@ public final class VirtualDeviceParams implements Parcelable {
        dest.writeInt(mAudioPlaybackSessionId);
        dest.writeInt(mAudioRecordingSessionId);
        dest.writeTypedObject(mHomeComponent, flags);
        dest.writeTypedObject(mInputMethodComponent, flags);
    }

    @Override
@@ -563,6 +580,8 @@ public final class VirtualDeviceParams implements Parcelable {
                && Objects.equals(mActivityPolicyExemptions, that.mActivityPolicyExemptions)
                && mDefaultActivityPolicy == that.mDefaultActivityPolicy
                && Objects.equals(mName, that.mName)
                && Objects.equals(mHomeComponent, that.mHomeComponent)
                && Objects.equals(mInputMethodComponent, that.mInputMethodComponent)
                && mAudioPlaybackSessionId == that.mAudioPlaybackSessionId
                && mAudioRecordingSessionId == that.mAudioRecordingSessionId;
    }
@@ -572,7 +591,8 @@ public final class VirtualDeviceParams implements Parcelable {
        int hashCode = Objects.hash(
                mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExemptions,
                mDefaultNavigationPolicy, mActivityPolicyExemptions, mDefaultActivityPolicy, mName,
                mDevicePolicies, mHomeComponent, mAudioPlaybackSessionId, mAudioRecordingSessionId);
                mDevicePolicies, mHomeComponent, mInputMethodComponent, mAudioPlaybackSessionId,
                mAudioRecordingSessionId);
        for (int i = 0; i < mDevicePolicies.size(); i++) {
            hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
            hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
@@ -593,6 +613,7 @@ public final class VirtualDeviceParams implements Parcelable {
                + " mName=" + mName
                + " mDevicePolicies=" + mDevicePolicies
                + " mHomeComponent=" + mHomeComponent
                + " mInputMethodComponent=" + mInputMethodComponent
                + " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
                + " mAudioRecordingSessionId=" + mAudioRecordingSessionId
                + ")";
@@ -612,6 +633,8 @@ public final class VirtualDeviceParams implements Parcelable {
        pw.println(prefix + "mActivityPolicyExemptions=" + mActivityPolicyExemptions);
        pw.println(prefix + "mDevicePolicies=" + mDevicePolicies);
        pw.println(prefix + "mVirtualSensorConfigs=" + mVirtualSensorConfigs);
        pw.println(prefix + "mHomeComponent=" + mHomeComponent);
        pw.println(prefix + "mInputMethodComponent=" + mInputMethodComponent);
        pw.println(prefix + "mAudioPlaybackSessionId=" + mAudioPlaybackSessionId);
        pw.println(prefix + "mAudioRecordingSessionId=" + mAudioRecordingSessionId);
    }
@@ -644,16 +667,17 @@ public final class VirtualDeviceParams implements Parcelable {
        private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
        private boolean mDefaultActivityPolicyConfigured = false;
        @Nullable private String mName;
        @NonNull private SparseIntArray mDevicePolicies = new SparseIntArray();
        @NonNull private final SparseIntArray mDevicePolicies = new SparseIntArray();
        private int mAudioPlaybackSessionId = AUDIO_SESSION_ID_GENERATE;
        private int mAudioRecordingSessionId = AUDIO_SESSION_ID_GENERATE;

        @NonNull private List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
        @NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
        @Nullable private Executor mVirtualSensorCallbackExecutor;
        @Nullable private VirtualSensorCallback mVirtualSensorCallback;
        @Nullable private Executor mVirtualSensorDirectChannelCallbackExecutor;
        @Nullable private VirtualSensorDirectChannelCallback mVirtualSensorDirectChannelCallback;
        @Nullable private ComponentName mHomeComponent;
        @Nullable private ComponentName mInputMethodComponent;

        private static class VirtualSensorCallbackDelegate extends IVirtualSensorCallback.Stub {
            @NonNull
@@ -748,6 +772,28 @@ public final class VirtualDeviceParams implements Parcelable {
            return this;
        }

        /**
         * Specifies a component to be used as input method on all displays owned by this virtual
         * device.
         *
         * @param inputMethodComponent The component name to be used as input method. Must comply to
         *   all general input method requirements described in the guide to
         *   <a href="{@docRoot}guide/topics/text/creating-input-method.html">
         *   Creating an Input Method</a>. If the given component is not available for any user that
         *   may interact with the virtual device, then there will effectively be no IME on this
         *   device's displays for that user.
         *
         * @see android.inputmethodservice.InputMethodService
         * @attr ref android.R.styleable#InputMethod_isVirtualDeviceOnly
         * @attr ref android.R.styleable#InputMethod_showInInputMethodPicker
         */
        @FlaggedApi(Flags.FLAG_VDM_CUSTOM_IME)
        @NonNull
        public Builder setInputMethodComponent(@Nullable ComponentName inputMethodComponent) {
            mInputMethodComponent = inputMethodComponent;
            return this;
        }

        /**
         * Sets the user handles with matching managed accounts on the remote device to which
         * this virtual device is streaming. The caller is responsible for verifying the presence
@@ -1136,6 +1182,7 @@ public final class VirtualDeviceParams implements Parcelable {
                    mName,
                    mDevicePolicies,
                    mHomeComponent,
                    mInputMethodComponent,
                    mVirtualSensorConfigs,
                    virtualSensorCallbackDelegate,
                    mAudioPlaybackSessionId,
+3 −2
Original line number Diff line number Diff line
@@ -3855,8 +3855,9 @@
             device -->
        <attr name="isVrOnly" format="boolean"/>
        <!-- Specifies if an IME can only be used on a display created by a virtual device.
             @hide @SystemApi
             @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") -->
             @see android.companion.virtual.VirtualDeviceParams.Builder#setInputMethodComponent
             @hide @SystemApi -->
        <!-- @FlaggedApi("android.companion.virtual.flags.vdm_custom_ime") -->
        <attr name="isVirtualDeviceOnly" format="boolean"/>
        <attr name="__removed2" format="boolean" />
        <!-- Specifies whether the IME supports showing inline suggestions. -->
+15 −0
Original line number Diff line number Diff line
@@ -104,6 +104,7 @@ import com.android.server.LocalServices;
import com.android.server.companion.virtual.GenericWindowPolicyController.RunningAppsChangedListener;
import com.android.server.companion.virtual.audio.VirtualAudioController;
import com.android.server.companion.virtual.camera.VirtualCameraController;
import com.android.server.inputmethod.InputMethodManagerInternal;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -352,6 +353,14 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
            flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
        }
        mBaseVirtualDisplayFlags = flags;

        if (Flags.vdmCustomIme() && mParams.getInputMethodComponent() != null) {
            final String imeId = mParams.getInputMethodComponent().flattenToShortString();
            Slog.d(TAG, "Setting custom input method " + imeId + " as default for virtual device "
                    + deviceId);
            InputMethodManagerInternal.get().setVirtualDeviceInputMethodForAllUsers(
                    mDeviceId, imeId);
        }
    }

    @VisibleForTesting
@@ -556,6 +565,12 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
                mCameraAccessController.stopObservingIfNeeded();
            }

            // Clear any previously set custom IME components.
            if (Flags.vdmCustomIme() && mParams.getInputMethodComponent() != null) {
                InputMethodManagerInternal.get().setVirtualDeviceInputMethodForAllUsers(
                        mDeviceId, null);
            }

            mInputController.close();
            mSensorController.close();
        } finally {
+24 −0
Original line number Diff line number Diff line
@@ -119,6 +119,25 @@ public abstract class InputMethodManagerInternal {
    public abstract boolean setInputMethodEnabled(String imeId, boolean enabled,
            @UserIdInt int userId);

    /**
     * Makes the input method associated with {@code imeId} the default input method for all users
     * on displays that are owned by the virtual device with the given {@code deviceId}. If the
     * input method associated with {@code imeId} is not available, there will be no IME on the
     * relevant displays.
     *
     * <p>The caller of this method is responsible for resetting it to {@code null} after the
     * virtual device is closed.</p>
     *
     * @param deviceId the device ID on which to use the given input method as default.
     * @param imeId  the input method ID to be used as default on the given device. If {@code null},
     *               then any existing input method association with that device will be removed.
     * @throws IllegalArgumentException if a non-{@code null} input method ID is passed for a
     *                                  device ID that already has a custom input method set or if
     *                                  the device ID is not a valid virtual device.
     */
    public abstract void setVirtualDeviceInputMethodForAllUsers(
            int deviceId, @Nullable String imeId);

    /**
     * Registers a new {@link InputMethodListListener}.
     *
@@ -246,6 +265,11 @@ public abstract class InputMethodManagerInternal {
                    return false;
                }

                @Override
                public void setVirtualDeviceInputMethodForAllUsers(
                        int deviceId, @Nullable String imeId) {
                }

                @Override
                public void registerInputMethodListListener(InputMethodListListener listener) {
                }
Loading