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

Commit eb851853 authored by Andrei Litvin's avatar Andrei Litvin Committed by Android (Google) Code Review
Browse files

Merge "Add support for GamePad api in ITvRemoteServiceInput."

parents 9da27b56 9b9f556a
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
# Copyright (C) 2020 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.

type FULL

key BUTTON_A {
    base:                               fallback DPAD_CENTER
}

key BUTTON_B {
    base:                               fallback BACK
}

key BUTTON_X {
    base:                               fallback DPAD_CENTER
}

key BUTTON_Y {
    base:                               fallback BACK
}

key BUTTON_THUMBL {
    base:                               fallback DPAD_CENTER
}

key BUTTON_THUMBR {
    base:                               fallback DPAD_CENTER
}

key BUTTON_SELECT {
    base:                               fallback MENU
}

key BUTTON_MODE {
    base:                               fallback MENU
}
+71 −0
Original line number Diff line number Diff line
# Copyright (C) 2020 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.

#
# Keyboard map for the android virtual remote running as a gamepad
#

key 0x130 BUTTON_A
key 0x131 BUTTON_B
key 0x133 BUTTON_X
key 0x134 BUTTON_Y

key 0x136 BUTTON_L2
key 0x137 BUTTON_R2
key 0x138 BUTTON_L1
key 0x139 BUTTON_R1

key 0x13a BUTTON_SELECT
key 0x13b BUTTON_START
key 0x13c BUTTON_MODE

key 0x13d BUTTON_THUMBL
key 0x13e BUTTON_THUMBR

key 103 DPAD_UP
key 108 DPAD_DOWN
key 105 DPAD_LEFT
key 106 DPAD_RIGHT

# Generic usage buttons
key 0x2c0 BUTTON_1
key 0x2c1 BUTTON_2
key 0x2c2 BUTTON_3
key 0x2c3 BUTTON_4
key 0x2c4 BUTTON_5
key 0x2c5 BUTTON_6
key 0x2c6 BUTTON_7
key 0x2c7 BUTTON_8
key 0x2c8 BUTTON_9
key 0x2c9 BUTTON_10
key 0x2ca BUTTON_11
key 0x2cb BUTTON_12
key 0x2cc BUTTON_13
key 0x2cd BUTTON_14
key 0x2ce BUTTON_15
key 0x2cf BUTTON_16

# assistant buttons
key 0x246 VOICE_ASSIST
key 0x247 ASSIST

axis 0x00 X
axis 0x01 Y
axis 0x02 Z
axis 0x05 RZ
axis 0x09 RTRIGGER
axis 0x0a LTRIGGER
axis 0x10 HAT_X
axis 0x11 HAT_Y
+7 −1
Original line number Diff line number Diff line
@@ -39,4 +39,10 @@ oneway interface ITvRemoteServiceInput {
    void sendPointerUp(IBinder token, int pointerId);
    @UnsupportedAppUsage
    void sendPointerSync(IBinder token);

    // API specific to gamepads. Close gamepads with closeInputBridge
    void openGamepadBridge(IBinder token, String name);
    void sendGamepadKeyDown(IBinder token, int keyCode);
    void sendGamepadKeyUp(IBinder token, int keyCode);
    void sendGamepadAxisValue(IBinder token, int axis, float value);
}
+14 −10
Original line number Diff line number Diff line
@@ -3,18 +3,22 @@ package com.android.media.tv.remoteprovider {

  public abstract class TvRemoteProvider {
    ctor public TvRemoteProvider(android.content.Context);
    method public void clearInputBridge(android.os.IBinder) throws java.lang.RuntimeException;
    method public void closeInputBridge(android.os.IBinder) throws java.lang.RuntimeException;
    method public void clearInputBridge(@NonNull android.os.IBinder) throws java.lang.RuntimeException;
    method public void closeInputBridge(@NonNull android.os.IBinder) throws java.lang.RuntimeException;
    method public android.os.IBinder getBinder();
    method public final android.content.Context getContext();
    method public void onInputBridgeConnected(android.os.IBinder);
    method public void openRemoteInputBridge(android.os.IBinder, String, int, int, int) throws java.lang.RuntimeException;
    method public void sendKeyDown(android.os.IBinder, int) throws java.lang.RuntimeException;
    method public void sendKeyUp(android.os.IBinder, int) throws java.lang.RuntimeException;
    method public void sendPointerDown(android.os.IBinder, int, int, int) throws java.lang.RuntimeException;
    method public void sendPointerSync(android.os.IBinder) throws java.lang.RuntimeException;
    method public void sendPointerUp(android.os.IBinder, int) throws java.lang.RuntimeException;
    method public void sendTimestamp(android.os.IBinder, long) throws java.lang.RuntimeException;
    method public void onInputBridgeConnected(@NonNull android.os.IBinder);
    method public void openGamepadBridge(@NonNull android.os.IBinder, @NonNull String) throws java.lang.RuntimeException;
    method public void openRemoteInputBridge(@NonNull android.os.IBinder, @NonNull String, int, int, int) throws java.lang.RuntimeException;
    method public void sendGamepadAxisValue(@NonNull android.os.IBinder, int, @FloatRange(from=-1.0F, to=1.0f) float) throws java.lang.RuntimeException;
    method public void sendGamepadKeyDown(@NonNull android.os.IBinder, int) throws java.lang.RuntimeException;
    method public void sendGamepadKeyUp(@NonNull android.os.IBinder, int) throws java.lang.RuntimeException;
    method public void sendKeyDown(@NonNull android.os.IBinder, int) throws java.lang.RuntimeException;
    method public void sendKeyUp(@NonNull android.os.IBinder, int) throws java.lang.RuntimeException;
    method public void sendPointerDown(@NonNull android.os.IBinder, int, int, int) throws java.lang.RuntimeException;
    method public void sendPointerSync(@NonNull android.os.IBinder) throws java.lang.RuntimeException;
    method public void sendPointerUp(@NonNull android.os.IBinder, int) throws java.lang.RuntimeException;
    method public void sendTimestamp(@NonNull android.os.IBinder, long) throws java.lang.RuntimeException;
    field public static final String SERVICE_INTERFACE = "com.android.media.tv.remoteprovider.TvRemoteProvider";
  }

+156 −17
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.media.tv.remoteprovider;

import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.content.Context;
import android.media.tv.ITvRemoteProvider;
import android.media.tv.ITvRemoteServiceInput;
@@ -24,6 +26,7 @@ import android.os.RemoteException;
import android.util.Log;

import java.util.LinkedList;
import java.util.Objects;

/**
 * Base class for emote providers implemented in unbundled service.
@@ -93,7 +96,7 @@ public abstract class TvRemoteProvider {
     *
     * @param token Identifier for the connection. Null, if failed.
     */
    public void onInputBridgeConnected(IBinder token) {
    public void onInputBridgeConnected(@NonNull IBinder token) {
    }

    /**
@@ -124,27 +127,73 @@ public abstract class TvRemoteProvider {
     * @param maxPointers Maximum supported pointers
     * @throws RuntimeException
     */
    public void openRemoteInputBridge(IBinder token, String name, int width, int height,
                                      int maxPointers) throws RuntimeException {
    public void openRemoteInputBridge(
            @NonNull IBinder token, @NonNull String name, int width, int height, int maxPointers)
            throws RuntimeException {
        final IBinder finalToken = Objects.requireNonNull(token);
        final String finalName = Objects.requireNonNull(name);

        synchronized (mOpenBridgeRunnables) {
            if (mRemoteServiceInput == null) {
                Log.d(TAG, "Delaying openRemoteInputBridge() for " + name);
                Log.d(TAG, "Delaying openRemoteInputBridge() for " + finalName);

                mOpenBridgeRunnables.add(() -> {
                    try {
                        mRemoteServiceInput.openInputBridge(
                                token, name, width, height, maxPointers);
                        Log.d(TAG, "Delayed openRemoteInputBridge() for " + name + ": success");
                                finalToken, finalName, width, height, maxPointers);
                        Log.d(TAG, "Delayed openRemoteInputBridge() for " + finalName
                                + ": success");
                    } catch (RemoteException re) {
                        Log.e(TAG, "Delayed openRemoteInputBridge() for " + name + ": failure", re);
                        Log.e(TAG, "Delayed openRemoteInputBridge() for " + finalName
                                + ": failure", re);
                    }
                });
                return;
            }
        }
        try {
            mRemoteServiceInput.openInputBridge(token, name, width, height, maxPointers);
            Log.d(TAG, "openRemoteInputBridge() for " + name + ": success");
            mRemoteServiceInput.openInputBridge(finalToken, finalName, width, height, maxPointers);
            Log.d(TAG, "openRemoteInputBridge() for " + finalName + ": success");
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Opens an input bridge as a gamepad device.
     * Clients should pass in a token that can be used to match this request with a token that
     * will be returned by {@link TvRemoteProvider#onInputBridgeConnected(IBinder token)}
     * <p>
     * The token should be used for subsequent calls.
     * </p>
     *
     * @param token       Identifier for this connection
     * @param name        Device name
     * @throws RuntimeException
     */
    public void openGamepadBridge(@NonNull IBinder token, @NonNull  String name)
            throws RuntimeException {
        final IBinder finalToken = Objects.requireNonNull(token);
        final String finalName = Objects.requireNonNull(name);
        synchronized (mOpenBridgeRunnables) {
            if (mRemoteServiceInput == null) {
                Log.d(TAG, "Delaying openGamepadBridge() for " + finalName);

                mOpenBridgeRunnables.add(() -> {
                    try {
                        mRemoteServiceInput.openGamepadBridge(finalToken, finalName);
                        Log.d(TAG, "Delayed openGamepadBridge() for " + finalName + ": success");
                    } catch (RemoteException re) {
                        Log.e(TAG, "Delayed openGamepadBridge() for " + finalName + ": failure",
                                re);
                    }
                });
                return;
            }
        }
        try {
            mRemoteServiceInput.openGamepadBridge(token, finalName);
            Log.d(TAG, "openGamepadBridge() for " + finalName + ": success");
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
@@ -156,7 +205,8 @@ public abstract class TvRemoteProvider {
     * @param token identifier for this connection
     * @throws RuntimeException
     */
    public void closeInputBridge(IBinder token) throws RuntimeException {
    public void closeInputBridge(@NonNull IBinder token) throws RuntimeException {
        Objects.requireNonNull(token);
        try {
            mRemoteServiceInput.closeInputBridge(token);
        } catch (RemoteException re) {
@@ -172,7 +222,8 @@ public abstract class TvRemoteProvider {
     * @param token identifier for this connection
     * @throws RuntimeException
     */
    public void clearInputBridge(IBinder token) throws RuntimeException {
    public void clearInputBridge(@NonNull IBinder token) throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) Log.d(TAG, "clearInputBridge() token " + token);
        try {
            mRemoteServiceInput.clearInputBridge(token);
@@ -189,7 +240,8 @@ public abstract class TvRemoteProvider {
     *                  {@link android.os.SystemClock#uptimeMillis} time base
     * @throws RuntimeException
     */
    public void sendTimestamp(IBinder token, long timestamp) throws RuntimeException {
    public void sendTimestamp(@NonNull IBinder token, long timestamp) throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) Log.d(TAG, "sendTimestamp() token: " + token +
                ", timestamp: " + timestamp);
        try {
@@ -206,7 +258,8 @@ public abstract class TvRemoteProvider {
     * @param keyCode Key code to be sent
     * @throws RuntimeException
     */
    public void sendKeyUp(IBinder token, int keyCode) throws RuntimeException {
    public void sendKeyUp(@NonNull IBinder token, int keyCode) throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) Log.d(TAG, "sendKeyUp() token: " + token + ", keyCode: " + keyCode);
        try {
            mRemoteServiceInput.sendKeyUp(token, keyCode);
@@ -222,7 +275,8 @@ public abstract class TvRemoteProvider {
     * @param keyCode Key code to be sent
     * @throws RuntimeException
     */
    public void sendKeyDown(IBinder token, int keyCode) throws RuntimeException {
    public void sendKeyDown(@NonNull IBinder token, int keyCode) throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) Log.d(TAG, "sendKeyDown() token: " + token +
                ", keyCode: " + keyCode);
        try {
@@ -240,7 +294,8 @@ public abstract class TvRemoteProvider {
     *                  to {@link MotionEvent#getPointerCount()} -1
     * @throws RuntimeException
     */
    public void sendPointerUp(IBinder token, int pointerId) throws RuntimeException {
    public void sendPointerUp(@NonNull IBinder token, int pointerId) throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) Log.d(TAG, "sendPointerUp() token: " + token +
                ", pointerId: " + pointerId);
        try {
@@ -260,8 +315,9 @@ public abstract class TvRemoteProvider {
     * @param y         Y co-ordinates in display pixels
     * @throws RuntimeException
     */
    public void sendPointerDown(IBinder token, int pointerId, int x, int y)
    public void sendPointerDown(@NonNull IBinder token, int pointerId, int x, int y)
            throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) Log.d(TAG, "sendPointerDown() token: " + token +
                ", pointerId: " + pointerId);
        try {
@@ -277,7 +333,8 @@ public abstract class TvRemoteProvider {
     * @param token identifier for the device
     * @throws RuntimeException
     */
    public void sendPointerSync(IBinder token) throws RuntimeException {
    public void sendPointerSync(@NonNull IBinder token) throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) Log.d(TAG, "sendPointerSync() token: " + token);
        try {
            mRemoteServiceInput.sendPointerSync(token);
@@ -286,6 +343,88 @@ public abstract class TvRemoteProvider {
        }
    }

    /**
     * Send a notification that a gamepad key was pressed.
     *
     * Supported buttons are:
     * <ul>
     *   <li> Right-side buttons: BUTTON_A, BUTTON_B, BUTTON_X, BUTTON_Y
     *   <li> Digital Triggers and bumpers: BUTTON_L1, BUTTON_R1, BUTTON_L2, BUTTON_R2
     *   <li> Thumb buttons: BUTTON_THUMBL, BUTTON_THUMBR
     *   <li> DPad buttons: DPAD_UP, DPAD_DOWN, DPAD_LEFT, DPAD_RIGHT
     *   <li> Gamepad buttons: BUTTON_SELECT, BUTTON_START, BUTTON_MODE
     *   <li> Generic buttons: BUTTON_1, BUTTON_2, ...., BUTTON16
     *   <li> Assistant: ASSIST, VOICE_ASSIST
     * </ul>
     *
     * @param token   identifier for the device
     * @param keyCode the gamepad key that was pressed (like BUTTON_A)
     */
    public void sendGamepadKeyDown(@NonNull IBinder token, int keyCode) throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) {
            Log.d(TAG, "sendGamepadKeyDown() token: " + token);
        }

        try {
            mRemoteServiceInput.sendGamepadKeyDown(token, keyCode);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Send a notification that a gamepad key was released.
     *
     * @see sendGamepadKeyDown for supported key codes.
     *
     * @param token identifier for the device
     * @param keyCode the gamepad key that was pressed
     */
    public void sendGamepadKeyUp(@NonNull IBinder token, int keyCode) throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) {
            Log.d(TAG, "sendGamepadKeyUp() token: " + token);
        }

        try {
            mRemoteServiceInput.sendGamepadKeyUp(token, keyCode);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    /**
     * Send a gamepad axis value.
     *
     * Supported axes:
     *  <li> Left Joystick: AXIS_X, AXIS_Y
     *  <li> Right Joystick: AXIS_Z, AXIS_RZ
     *  <li> Triggers: AXIS_LTRIGGER, AXIS_RTRIGGER
     *  <li> DPad: AXIS_HAT_X, AXIS_HAT_Y
     *
     * For non-trigger axes, the range of acceptable values is [-1, 1]. The trigger axes support
     * values [0, 1].
     *
     * @param token identifier for the device
     * @param axis  MotionEvent axis
     * @param value the value to send
     */
    public void sendGamepadAxisValue(
            @NonNull IBinder token, int axis, @FloatRange(from = -1.0f, to = 1.0f) float value)
            throws RuntimeException {
        Objects.requireNonNull(token);
        if (DEBUG_KEYS) {
            Log.d(TAG, "sendGamepadAxisValue() token: " + token);
        }

        try {
            mRemoteServiceInput.sendGamepadAxisValue(token, axis, value);
        } catch (RemoteException re) {
            throw re.rethrowFromSystemServer();
        }
    }

    private final class ProviderStub extends ITvRemoteProvider.Stub {
        @Override
        public void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
Loading