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

Commit 61edd42c authored by Ming-Shin Lu's avatar Ming-Shin Lu Committed by Android (Google) Code Review
Browse files

Merge changes I6adbf430,I6e137a6e,I9e15358a,I2aea907b,I12d99c15, ...

* changes:
  Migrate IMMS#shouldRestoreImeVisibility to ImeVisibilityStateComputer
  Migrate applyImeVsibility to ImeVisibilityApplier
  Migrate computeImeDisplayIdForTarget to ImeVisibilityStateComputer
  Migrate to IME visibility settings
  Introduce ImeVisibilityApplier
  Introduce ImeVisibilityStateComputer
parents 2f078882 279f7a58
Loading
Loading
Loading
Loading
+155 −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 com.android.server.inputmethod;

import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;

import static com.android.server.EventLogTags.IMF_HIDE_IME;
import static com.android.server.EventLogTags.IMF_SHOW_IME;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_HIDE_IME;
import static com.android.server.inputmethod.ImeVisibilityStateComputer.STATE_SHOW_IME;

import android.annotation.Nullable;
import android.os.Binder;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.util.EventLog;
import android.util.Slog;
import android.view.inputmethod.ImeTracker;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.inputmethod.InputMethodDebug;
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.server.LocalServices;
import com.android.server.wm.WindowManagerInternal;

import java.util.Objects;

/**
 * The default implementation of {@link ImeVisibilityApplier} used in
 * {@link InputMethodManagerService}.
 */
final class DefaultImeVisibilityApplier implements ImeVisibilityApplier {

    private static final String TAG = "DefaultImeVisibilityApplier";

    private static final boolean DEBUG = InputMethodManagerService.DEBUG;

    private InputMethodManagerService mService;

    private final WindowManagerInternal mWindowManagerInternal;


    DefaultImeVisibilityApplier(InputMethodManagerService service) {
        mService = service;
        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
    }

    @GuardedBy("ImfLock.class")
    @Override
    public void performShowIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
            int showFlags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
        final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
        if (curMethod != null) {
            // create a placeholder token for IMS so that IMS cannot inject windows into client app.
            final IBinder showInputToken = new Binder();
            mService.setRequestImeTokenToWindow(windowToken, showInputToken);
            if (DEBUG) {
                Slog.v(TAG, "Calling " + curMethod + ".showSoftInput(" + showInputToken
                        + ", " + showFlags + ", " + resultReceiver + ") for reason: "
                        + InputMethodDebug.softInputDisplayReasonToString(reason));
            }
            // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
            if (curMethod.showSoftInput(showInputToken, statsToken, showFlags, resultReceiver)) {
                if (DEBUG_IME_VISIBILITY) {
                    EventLog.writeEvent(IMF_SHOW_IME, statsToken.getTag(),
                            Objects.toString(mService.mCurFocusedWindow),
                            InputMethodDebug.softInputDisplayReasonToString(reason),
                            InputMethodDebug.softInputModeToString(
                                    mService.mCurFocusedWindowSoftInputMode));
                }
                mService.onShowHideSoftInputRequested(true /* show */, windowToken, reason,
                        statsToken);
            }
        }
    }

    @GuardedBy("ImfLock.class")
    @Override
    public void performHideIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {
        final IInputMethodInvoker curMethod = mService.getCurMethodLocked();
        if (curMethod != null) {
            final Binder hideInputToken = new Binder();
            mService.setRequestImeTokenToWindow(windowToken, hideInputToken);
            // The IME will report its visible state again after the following message finally
            // delivered to the IME process as an IPC.  Hence the inconsistency between
            // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in
            // the final state.
            if (DEBUG) {
                Slog.v(TAG, "Calling " + curMethod + ".hideSoftInput(0, " + hideInputToken
                        + ", " + resultReceiver + ") for reason: "
                        + InputMethodDebug.softInputDisplayReasonToString(reason));
            }
            // TODO(b/192412909): Check if we can always call onShowHideSoftInputRequested() or not.
            if (curMethod.hideSoftInput(hideInputToken, statsToken, 0, resultReceiver)) {
                if (DEBUG_IME_VISIBILITY) {
                    EventLog.writeEvent(IMF_HIDE_IME, statsToken.getTag(),
                            Objects.toString(mService.mCurFocusedWindow),
                            InputMethodDebug.softInputDisplayReasonToString(reason),
                            InputMethodDebug.softInputModeToString(
                                    mService.mCurFocusedWindowSoftInputMode));
                }
                mService.onShowHideSoftInputRequested(false /* show */, windowToken, reason,
                        statsToken);
            }
        }
    }

    @GuardedBy("ImfLock.class")
    @Override
    public void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
            @ImeVisibilityStateComputer.VisibilityState int state) {
        switch (state) {
            case STATE_SHOW_IME:
                ImeTracker.get().onProgress(statsToken,
                        ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
                // Send to window manager to show IME after IME layout finishes.
                mWindowManagerInternal.showImePostLayout(windowToken, statsToken);
                break;
            case STATE_HIDE_IME:
                if (mService.mCurFocusedWindowClient != null) {
                    ImeTracker.get().onProgress(statsToken,
                            ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
                    // IMMS only knows of focused window, not the actual IME target.
                    // e.g. it isn't aware of any window that has both
                    // NOT_FOCUSABLE, ALT_FOCUSABLE_IM flags set and can the IME target.
                    // Send it to window manager to hide IME from IME target window.
                    // TODO(b/139861270): send to mCurClient.client once IMMS is aware of
                    // actual IME target.
                    mWindowManagerInternal.hideIme(windowToken,
                            mService.mCurFocusedWindowClient.mSelfReportedDisplayId, statsToken);
                } else {
                    ImeTracker.get().onFailed(statsToken,
                            ImeTracker.PHASE_SERVER_APPLY_IME_VISIBILITY);
                }
                break;
            default:
                throw new IllegalArgumentException("Invalid IME visibility state: " + state);
        }
    }
}
+79 −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 com.android.server.inputmethod;

import android.annotation.Nullable;
import android.os.IBinder;
import android.os.ResultReceiver;
import android.view.inputmethod.ImeTracker;

import com.android.internal.inputmethod.SoftInputShowHideReason;

/**
 * Interface for IME visibility operations like show/hide and update Z-ordering relative to the IME
 * targeted window.
 */
interface ImeVisibilityApplier {
    /**
     * Performs showing IME on top of the given window.
     *
     * @param windowToken    The token of a window that currently has focus.
     * @param statsToken     A token that tracks the progress of an IME request.
     * @param showFlags      Provides additional operating flags to show IME.
     * @param resultReceiver If non-null, this will be called back to the caller when
     *                       it has processed request to tell what it has done.
     * @param reason         The reason for requesting to show IME.
     */
    default void performShowIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
            int showFlags, ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}

    /**
     * Performs hiding IME to the given window
     *
     * @param windowToken    The token of a window that currently has focus.
     * @param statsToken     A token that tracks the progress of an IME request.
     * @param resultReceiver If non-null, this will be called back to the caller when
     *                       it has processed request to tell what it has done.
     * @param reason         The reason for requesting to hide IME.
     */
    default void performHideIme(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
            ResultReceiver resultReceiver, @SoftInputShowHideReason int reason) {}

    /**
     * Applies the IME visibility from {@link android.inputmethodservice.InputMethodService} with
     * according to the given visibility state.
     *
     * @param windowToken The token of a window for applying the IME visibility
     * @param statsToken  A token that tracks the progress of an IME request.
     * @param state       The new IME visibility state for the applier to handle
     */
    default void applyImeVisibility(IBinder windowToken, @Nullable ImeTracker.Token statsToken,
            @ImeVisibilityStateComputer.VisibilityState int state) {}

    /**
     * Updates the IME Z-ordering relative to the given window.
     *
     * This used to adjust the IME relative layer of the window during
     * {@link InputMethodManagerService} is in switching IME clients.
     *
     * @param windowToken The token of a window to update the Z-ordering relative to the IME.
     */
    default void updateImeLayeringByTarget(IBinder windowToken) {
        // TODO: add a method in WindowManagerInternal to call DC#updateImeInputAndControlTarget
        //  here to end up updating IME layering after IMMS#attachNewInputLocked called.
    }
}
+424 −0

File added.

Preview size limit exceeded, changes collapsed.

+65 −192

File changed.

Preview size limit exceeded, changes collapsed.