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

Commit a006b706 authored by Omar Abdelmonem's avatar Omar Abdelmonem Committed by Android (Google) Code Review
Browse files

Merge "Add touchpad selection dropdown menu" into main

parents 8660d59e 3c9b6a96
Loading
Loading
Loading
Loading
+18 −21
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@ import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.util.Slog;
import android.util.TypedValue;
import android.view.Gravity;
@@ -42,6 +41,7 @@ import com.android.server.input.TouchpadHardwareProperties;
import com.android.server.input.TouchpadHardwareState;

import java.util.Objects;
import java.util.function.Consumer;

public class TouchpadDebugView extends LinearLayout {
    private static final float MAX_SCREEN_WIDTH_PROPORTION = 0.4f;
@@ -54,7 +54,6 @@ public class TouchpadDebugView extends LinearLayout {
    private static final int ROUNDED_CORNER_RADIUS_DP = 24;
    private static final int BUTTON_PRESSED_BACKGROUND_COLOR = Color.rgb(118, 151, 99);
    private static final int BUTTON_RELEASED_BACKGROUND_COLOR = Color.rgb(84, 85, 169);

    /**
     * Input device ID for the touchpad that this debug view is displaying.
     */
@@ -76,24 +75,24 @@ public class TouchpadDebugView extends LinearLayout {
    private int mWindowLocationBeforeDragX;
    private int mWindowLocationBeforeDragY;
    private int mLatestGestureType = 0;
    private TouchpadSelectionView mTouchpadSelectionView;
    private TouchpadVisualizationView mTouchpadVisualizationView;
    private TextView mGestureInfoView;
    private TextView mNameView;

    @NonNull
    private TouchpadHardwareState mLastTouchpadState =
            new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
                    new TouchpadFingerState[0]);
    private TouchpadVisualizationView mTouchpadVisualizationView;
    private final TouchpadHardwareProperties mTouchpadHardwareProperties;

    public TouchpadDebugView(Context context, int touchpadId,
                             TouchpadHardwareProperties touchpadHardwareProperties) {
                             TouchpadHardwareProperties touchpadHardwareProperties,
                             Consumer<Integer> touchpadSwitchHandler) {
        super(context);
        mTouchpadId = touchpadId;
        mWindowManager =
                Objects.requireNonNull(getContext().getSystemService(WindowManager.class));
        mTouchpadHardwareProperties = touchpadHardwareProperties;
        init(context, touchpadId);
        init(context, touchpadId, touchpadSwitchHandler);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

        mWindowLayoutParams = new WindowManager.LayoutParams();
@@ -115,7 +114,8 @@ public class TouchpadDebugView extends LinearLayout {
        mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
    }

    private void init(Context context, int touchpadId) {
    private void init(Context context, int touchpadId,
                      Consumer<Integer> touchpadSwitchHandler) {
        updateScreenDimensions();
        setOrientation(VERTICAL);
        setLayoutParams(new LayoutParams(
@@ -123,18 +123,14 @@ public class TouchpadDebugView extends LinearLayout {
                LayoutParams.WRAP_CONTENT));
        setBackgroundColor(Color.TRANSPARENT);

        mNameView = new TextView(context);
        mNameView.setBackgroundColor(BUTTON_RELEASED_BACKGROUND_COLOR);
        mNameView.setTextSize(TEXT_SIZE_SP);
        mNameView.setText(Objects.requireNonNull(Objects.requireNonNull(
                        mContext.getSystemService(InputManager.class))
                .getInputDevice(touchpadId)).getName());
        mNameView.setGravity(Gravity.CENTER);
        mNameView.setTextColor(Color.WHITE);
        mTouchpadSelectionView = new TouchpadSelectionView(context,
                touchpadId, touchpadSwitchHandler);
        mTouchpadSelectionView.setBackgroundColor(BUTTON_RELEASED_BACKGROUND_COLOR);
        mTouchpadSelectionView.setGravity(Gravity.CENTER);
        int paddingInDP = (int) TypedValue.applyDimension(COMPLEX_UNIT_DIP, TEXT_PADDING_DP,
                getResources().getDisplayMetrics());
        mNameView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP);
        mNameView.setLayoutParams(
        mTouchpadSelectionView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP);
        mTouchpadSelectionView.setLayoutParams(
                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));

        mTouchpadVisualizationView = new TouchpadVisualizationView(context,
@@ -147,10 +143,11 @@ public class TouchpadDebugView extends LinearLayout {
        mGestureInfoView.setPadding(paddingInDP, paddingInDP, paddingInDP, paddingInDP);
        mGestureInfoView.setLayoutParams(
                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        //TODO(b/369061237): Handle longer text

        updateTheme(getResources().getConfiguration().uiMode);

        addView(mNameView);
        addView(mTouchpadSelectionView);
        addView(mTouchpadVisualizationView);
        addView(mGestureInfoView);

@@ -359,12 +356,12 @@ public class TouchpadDebugView extends LinearLayout {

    private void onTouchpadButtonPress() {
        Slog.d(TAG, "You clicked me!");
        mNameView.setBackgroundColor(BUTTON_PRESSED_BACKGROUND_COLOR);
        mTouchpadSelectionView.setBackgroundColor(BUTTON_PRESSED_BACKGROUND_COLOR);
    }

    private void onTouchpadButtonRelease() {
        Slog.d(TAG, "You released the click");
        mNameView.setBackgroundColor(BUTTON_RELEASED_BACKGROUND_COLOR);
        mTouchpadSelectionView.setBackgroundColor(BUTTON_RELEASED_BACKGROUND_COLOR);
    }

    /**
+12 −4
Original line number Diff line number Diff line
@@ -46,7 +46,7 @@ public class TouchpadDebugViewController implements InputManager.InputDeviceList

    public TouchpadDebugViewController(Context context, Looper looper,
                                       InputManagerService inputManagerService) {
        //TODO(b/363979581): Handle multi-display scenarios
        //TODO(b/369059937): Handle multi-display scenarios
        mContext = context;
        mHandler = new Handler(looper);
        mInputManagerService = inputManagerService;
@@ -77,6 +77,14 @@ public class TouchpadDebugViewController implements InputManager.InputDeviceList
        }
    }

    /**
     * Switch to showing the touchpad with the given device ID
     */
    public void switchVisualisationToTouchpadId(int newDeviceId) {
        if (mTouchpadDebugView != null) hideDebugView(mTouchpadDebugView.getTouchpadId());
        showDebugView(newDeviceId);
    }

    @Override
    public void onInputDeviceChanged(int deviceId) {
    }
@@ -117,7 +125,7 @@ public class TouchpadDebugViewController implements InputManager.InputDeviceList
                        touchpadId);

        mTouchpadDebugView = new TouchpadDebugView(mContext, touchpadId,
                touchpadHardwareProperties);
                touchpadHardwareProperties, this::switchVisualisationToTouchpadId);
        final WindowManager.LayoutParams mWindowLayoutParams =
                mTouchpadDebugView.getWindowLayoutParams();

+111 −0
Original line number Diff line number Diff line
/*
 * Copyright 2024 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.input.debug;

import android.content.Context;
import android.graphics.Color;
import android.hardware.input.InputManager;
import android.view.Gravity;
import android.view.InputDevice;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
import android.widget.TextView;

import java.util.Objects;
import java.util.function.Consumer;

public class TouchpadSelectionView extends LinearLayout {
    private static final float TEXT_SIZE_SP = 16.0f;

    int mCurrentTouchpadId;

    public TouchpadSelectionView(Context context, int touchpadId,
                                 Consumer<Integer> touchpadSwitchHandler) {
        super(context);
        mCurrentTouchpadId = touchpadId;
        init(context, touchpadSwitchHandler);
    }

    private void init(Context context, Consumer<Integer> touchpadSwitchHandler) {
        setOrientation(HORIZONTAL);
        setLayoutParams(new LayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT));
        setBackgroundColor(Color.TRANSPARENT);

        TextView nameView = new TextView(context);
        nameView.setTextSize(TEXT_SIZE_SP);
        nameView.setText(getTouchpadName(mCurrentTouchpadId));
        nameView.setGravity(Gravity.LEFT);
        nameView.setTextColor(Color.WHITE);

        LayoutParams textParams = new LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        textParams.rightMargin = 16;
        nameView.setLayoutParams(textParams);

        ImageButton arrowButton = new ImageButton(context);
        arrowButton.setImageDrawable(context.getDrawable(android.R.drawable.arrow_down_float));
        arrowButton.setForegroundGravity(Gravity.RIGHT);
        arrowButton.setBackgroundColor(Color.TRANSPARENT);
        arrowButton.setLayoutParams(new LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT));

        arrowButton.setOnClickListener(v -> showPopupMenu(v, context, touchpadSwitchHandler));

        addView(nameView);
        addView(arrowButton);
    }

    private void showPopupMenu(View anchorView, Context context,
                               Consumer<Integer> touchpadSwitchHandler) {
        int i = 0;
        PopupMenu popupMenu = new PopupMenu(context, anchorView);

        final InputManager inputManager = Objects.requireNonNull(
                mContext.getSystemService(InputManager.class));
        for (int deviceId : inputManager.getInputDeviceIds()) {
            InputDevice inputDevice = inputManager.getInputDevice(deviceId);
            if (Objects.requireNonNull(inputDevice).supportsSource(
                    InputDevice.SOURCE_TOUCHPAD | InputDevice.SOURCE_MOUSE)) {
                popupMenu.getMenu().add(0, deviceId, i, getTouchpadName(deviceId));
                i++;
            }
        }

        popupMenu.setOnMenuItemClickListener(item -> {
            if (item.getItemId() == mCurrentTouchpadId) {
                return false;
            }

            touchpadSwitchHandler.accept(item.getItemId());
            return true;
        });

        popupMenu.show();
    }

    private String getTouchpadName(int touchpadId) {
        return Objects.requireNonNull(Objects.requireNonNull(
                        mContext.getSystemService(InputManager.class))
                .getInputDevice(touchpadId)).getName();
    }
}
+13 −5
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.function.Consumer;

/**
 * Build/Install/Run:
 * atest TouchpadDebugViewTest
@@ -99,10 +101,12 @@ public class TouchpadDebugViewTest {

        when(mInputManager.getInputDevice(TOUCHPAD_DEVICE_ID)).thenReturn(inputDevice);

        Consumer<Integer> touchpadSwitchHandler = id -> {};

        mTouchpadDebugView = new TouchpadDebugView(mTestableContext, TOUCHPAD_DEVICE_ID,
                new TouchpadHardwareProperties.Builder(0f, 0f, 500f,
                        500f, 45f, 47f, -4f, 5f, (short) 10, true,
                        true).build());
                        true).build(), touchpadSwitchHandler);

        mTouchpadDebugView.measure(
                View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
@@ -321,26 +325,30 @@ public class TouchpadDebugViewTest {
                new TouchpadHardwareState(0, 1 /* buttonsDown */, 0, 0,
                        new TouchpadFingerState[0]), TOUCHPAD_DEVICE_ID);

        assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.rgb(118, 151, 99));
        assertEquals(((ColorDrawable) child.getBackground()).getColor(),
                Color.parseColor("#769763"));

        mTouchpadDebugView.updateHardwareState(
                new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
                        new TouchpadFingerState[0]), TOUCHPAD_DEVICE_ID);

        assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.rgb(84, 85, 169));
        assertEquals(((ColorDrawable) child.getBackground()).getColor(),
                Color.parseColor("#5455A9"));

        mTouchpadDebugView.updateHardwareState(
                new TouchpadHardwareState(0, 1 /* buttonsDown */, 0, 0,
                        new TouchpadFingerState[0]), TOUCHPAD_DEVICE_ID);

        assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.rgb(118, 151, 99));
        assertEquals(((ColorDrawable) child.getBackground()).getColor(),
                Color.parseColor("#769763"));

        // Color should not change because hardware state of a different touchpad
        mTouchpadDebugView.updateHardwareState(
                new TouchpadHardwareState(0, 0 /* buttonsDown */, 0, 0,
                        new TouchpadFingerState[0]), TOUCHPAD_DEVICE_ID + 1);

        assertEquals(((ColorDrawable) child.getBackground()).getColor(), Color.rgb(118, 151, 99));
        assertEquals(((ColorDrawable) child.getBackground()).getColor(),
                Color.parseColor("#769763"));
    }

    @Test