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

Commit c4a9755d authored by Cosmin Băieș's avatar Cosmin Băieș Committed by Android (Google) Code Review
Browse files

Merge changes from topic "ime-switch-long-click" into main

* changes:
  Add IME switch button long click support
  Order IMEs and subtype by IME name and ID only
  Introduce IME subtype switching auto mode
parents 9aca3ea5 61e1f831
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.inputmethod.Flags;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.window.WindowProviderService;
@@ -186,6 +187,10 @@ public abstract class AbstractInputMethodService extends WindowProviderService
            if (callback != null) {
                callback.finishedEvent(seq, handled);
            }
            if (Flags.imeSwitcherRevamp() && !handled && event.getAction() == KeyEvent.ACTION_DOWN
                    && event.getUnicodeChar() > 0 && mInputMethodServiceInternal != null) {
                mInputMethodServiceInternal.notifyUserActionIfNecessary();
            }
        }

        /**
+11 −0
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ import android.os.ResultReceiver;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.InputType;
import android.text.Layout;
@@ -4340,6 +4341,16 @@ public class InputMethodService extends AbstractInputMethodService {
        return mNavigationBarController.isShown();
    }

    /**
     * Called when the IME switch button was clicked from the client. This will show the input
     * method picker dialog.
     *
     * @hide
     */
    final void onImeSwitchButtonClickFromClient() {
        mPrivOps.onImeSwitchButtonClickFromClient(getDisplayId(), UserHandle.myUserId());
    }

    /**
     * Used to inject custom {@link InputMethodServiceInternal}.
     *
+15 −1
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.view.WindowInsets;
import android.view.WindowInsetsController.Appearance;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;

import com.android.internal.inputmethod.InputMethodNavButtonFlags;
@@ -145,7 +146,8 @@ final class NavigationBarController {
        return mImpl.toDebugString();
    }

    private static final class Impl implements Callback, Window.DecorCallback {
    private static final class Impl implements Callback, Window.DecorCallback,
            NavigationBarView.ButtonClickListener {
        private static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700;

        // Copied from com.android.systemui.animation.Interpolators#LEGACY_DECELERATE
@@ -241,6 +243,7 @@ final class NavigationBarController {
                                    ? StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN
                                    : 0);
                    navigationBarView.setNavigationIconHints(hints);
                    navigationBarView.prepareNavButtons(this);
                }
            } else {
                mNavigationBarFrame.setLayoutParams(new FrameLayout.LayoutParams(
@@ -592,6 +595,17 @@ final class NavigationBarController {
            return drawLegacyNavigationBarBackground;
        }

        @Override
        public void onImeSwitchButtonClick(View v) {
            mService.onImeSwitchButtonClickFromClient();
        }

        @Override
        public boolean onImeSwitchButtonLongClick(View v) {
            v.getContext().getSystemService(InputMethodManager.class).showInputMethodPicker();
            return true;
        }

        /**
         * Returns the height of the IME caption bar if this should be shown, or {@code 0} instead.
         */
+35 −2
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.inputmethod.Flags;
import android.view.inputmethod.InputConnection;
import android.widget.ImageView;

@@ -58,12 +59,30 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
    private int mTouchDownY;
    private AudioManager mAudioManager;
    private boolean mGestureAborted;
    /**
     * Whether the long click action has been invoked. The short click action is invoked on the up
     * event while a long click is invoked as soon as the long press duration is reached, so a long
     * click could be performed before the short click is checked, in which case the short click's
     * action should not be invoked.
     *
     * @see View#mHasPerformedLongPress
     */
    private boolean mLongClicked;
    private OnClickListener mOnClickListener;
    private final KeyButtonRipple mRipple;
    private final Paint mOvalBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    private float mDarkIntensity;
    private boolean mHasOvalBg = false;

    /** Runnable for checking whether the long click action should be performed. */
    private final Runnable mCheckLongPress = new Runnable() {
        public void run() {
            if (isPressed() && performLongClick()) {
                mLongClicked = true;
            }
        }
    };

    public KeyButtonView(Context context, AttributeSet attrs) {
        super(context, attrs);

@@ -159,6 +178,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mDownTime = SystemClock.uptimeMillis();
                mLongClicked = false;
                setPressed(true);

                // Use raw X and Y to detect gestures in case a parent changes the x and y values
@@ -173,6 +193,10 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
                if (!showSwipeUI) {
                    playSoundEffect(SoundEffectConstants.CLICK);
                }
                if (Flags.imeSwitcherRevamp() && isLongClickable()) {
                    removeCallbacks(mCheckLongPress);
                    postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
                }
                break;
            case MotionEvent.ACTION_MOVE:
                x = (int) ev.getRawX();
@@ -183,6 +207,9 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
                    // When quick step is enabled, prevent animating the ripple triggered by
                    // setPressed and decide to run it on touch up
                    setPressed(false);
                    if (isLongClickable()) {
                        removeCallbacks(mCheckLongPress);
                    }
                }
                break;
            case MotionEvent.ACTION_CANCEL:
@@ -190,9 +217,12 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
                if (mCode != KEYCODE_UNKNOWN) {
                    sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);
                }
                if (isLongClickable()) {
                    removeCallbacks(mCheckLongPress);
                }
                break;
            case MotionEvent.ACTION_UP:
                final boolean doIt = isPressed();
                final boolean doIt = isPressed() && !mLongClicked;
                setPressed(false);
                final boolean doHapticFeedback = (SystemClock.uptimeMillis() - mDownTime) > 150;
                if (showSwipeUI) {
@@ -201,7 +231,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
                        performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
                        playSoundEffect(SoundEffectConstants.CLICK);
                    }
                } else if (doHapticFeedback) {
                } else if (doHapticFeedback && !mLongClicked) {
                    // Always send a release ourselves because it doesn't seem to be sent elsewhere
                    // and it feels weird to sometimes get a release haptic and other times not.
                    performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY_RELEASE);
@@ -221,6 +251,9 @@ public class KeyButtonView extends ImageView implements ButtonInterface {
                        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                    }
                }
                if (isLongClickable()) {
                    removeCallbacks(mCheckLongPress);
                }
                break;
        }

+42 −4
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.DrawableRes;
import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.app.StatusBarManager;
import android.content.Context;
import android.content.res.Configuration;
@@ -39,6 +40,7 @@ import android.view.Surface;
import android.view.View;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import android.view.inputmethod.Flags;
import android.view.inputmethod.InputMethodManager;
import android.widget.FrameLayout;

@@ -79,6 +81,28 @@ public final class NavigationBarView extends FrameLayout {

    private NavigationBarInflaterView mNavigationInflaterView;

    /**
     * Interface definition for callbacks to be invoked when navigation bar buttons are clicked.
     */
    public interface ButtonClickListener {

        /**
         * Called when the IME switch button is clicked.
         *
         * @param v The view that was clicked.
         */
        void onImeSwitchButtonClick(View v);

        /**
         * Called when the IME switch button has been clicked and held.
         *
         * @param v The view that was clicked and held.
         *
         * @return true if the callback consumed the long click, false otherwise.
         */
        boolean onImeSwitchButtonLongClick(View v);
    }

    public NavigationBarView(Context context, AttributeSet attrs) {
        super(context, attrs);

@@ -98,14 +122,28 @@ public final class NavigationBarView extends FrameLayout {
                new ButtonDispatcher(com.android.internal.R.id.input_method_nav_home_handle));

        mDeadZone = new android.inputmethodservice.navigationbar.DeadZone(this);
    }

    /**
     * Prepares the navigation bar buttons to be used and sets the on click listeners.
     *
     * @param listener The listener used to handle the clicks on the navigation bar buttons.
     */
    public void prepareNavButtons(@NonNull ButtonClickListener listener) {
        getBackButton().setLongClickable(false);

        if (Flags.imeSwitcherRevamp()) {
            final var imeSwitchButton = getImeSwitchButton();
            imeSwitchButton.setLongClickable(true);
            imeSwitchButton.setOnClickListener(listener::onImeSwitchButtonClick);
            imeSwitchButton.setOnLongClickListener(listener::onImeSwitchButtonLongClick);
        } else {
            final ButtonDispatcher imeSwitchButton = getImeSwitchButton();
            imeSwitchButton.setLongClickable(false);
            imeSwitchButton.setOnClickListener(view -> view.getContext()
                    .getSystemService(InputMethodManager.class).showInputMethodPicker());
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
Loading