Marking CarInputManager methods with SystemApi
Test: atest CarServiceUnitTest
Bug: 159623196
Change-Id: I27e07b691167853000632db3c42324b8c855979c
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 4406895..65d68d6 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -21,6 +21,7 @@
field public static final String CAR_DEVICE_POLICY_SERVICE = "car_device_policy_service";
field public static final String CAR_DRIVING_STATE_SERVICE = "drivingstate";
field public static final String CAR_EXTRA_CLUSTER_ACTIVITY_STATE = "android.car.cluster.ClusterActivityState";
+ field public static final String CAR_INPUT_SERVICE = "android.car.input";
field public static final String CAR_MEDIA_SERVICE = "car_media";
field public static final String CAR_USER_SERVICE = "car_user_service";
field public static final String CAR_WATCHDOG_SERVICE = "car_watchdog";
@@ -38,6 +39,7 @@
field public static final String PERMISSION_CAR_DYNAMICS_STATE = "android.car.permission.CAR_DYNAMICS_STATE";
field public static final String PERMISSION_CAR_ENGINE_DETAILED = "android.car.permission.CAR_ENGINE_DETAILED";
field public static final String PERMISSION_CAR_INSTRUMENT_CLUSTER_CONTROL = "android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL";
+ field public static final String PERMISSION_CAR_MONITOR_INPUT = "android.car.permission.CAR_MONITOR_INPUT";
field public static final String PERMISSION_CAR_POWER = "android.car.permission.CAR_POWER";
field public static final String PERMISSION_CAR_PROJECTION = "android.car.permission.CAR_PROJECTION";
field public static final String PERMISSION_CAR_PROJECTION_STATUS = "android.car.permission.ACCESS_CAR_PROJECTION_STATUS";
@@ -831,6 +833,58 @@
field @Deprecated public final int mTargetDisplay;
}
+ public final class CarInputManager {
+ method @RequiresPermission(android.Manifest.permission.INJECT_EVENTS) public void injectKeyEvent(@NonNull android.view.KeyEvent, int);
+ method public void releaseInputEventCapture(int);
+ method @RequiresPermission(android.car.Car.PERMISSION_CAR_MONITOR_INPUT) public int requestInputEventCapture(@NonNull android.car.input.CarInputManager.CarInputCaptureCallback, int, @NonNull int[], int);
+ field public static final int CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT = 1; // 0x1
+ field public static final int INPUT_CAPTURE_RESPONSE_DELAYED = 2; // 0x2
+ field public static final int INPUT_CAPTURE_RESPONSE_FAILED = 1; // 0x1
+ field public static final int INPUT_CAPTURE_RESPONSE_SUCCEEDED = 0; // 0x0
+ field public static final int INPUT_TYPE_CUSTOM_INPUT_EVENT = 200; // 0xc8
+ field public static final int INPUT_TYPE_ROTARY_NAVIGATION = 10; // 0xa
+ }
+
+ public static interface CarInputManager.CarInputCaptureCallback {
+ method public default void onCaptureStateChanged(int, @NonNull int[]);
+ method public default void onCustomInputEvents(int, @NonNull java.util.List<android.car.input.CustomInputEvent>);
+ method public default void onKeyEvents(int, @NonNull java.util.List<android.view.KeyEvent>);
+ method public default void onRotaryEvents(int, @NonNull java.util.List<android.car.input.RotaryEvent>);
+ }
+
+ public final class CustomInputEvent implements android.os.Parcelable {
+ ctor public CustomInputEvent(int, int, int);
+ method public int describeContents();
+ method public int getInputCode();
+ method public int getRepeatCounter();
+ method public int getTargetDisplayType();
+ method @NonNull public static String inputCodeToString(int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.input.CustomInputEvent> CREATOR;
+ field public static final int INPUT_CODE_F1 = 1001; // 0x3e9
+ field public static final int INPUT_CODE_F10 = 1010; // 0x3f2
+ field public static final int INPUT_CODE_F2 = 1002; // 0x3ea
+ field public static final int INPUT_CODE_F3 = 1003; // 0x3eb
+ field public static final int INPUT_CODE_F4 = 1004; // 0x3ec
+ field public static final int INPUT_CODE_F5 = 1005; // 0x3ed
+ field public static final int INPUT_CODE_F6 = 1006; // 0x3ee
+ field public static final int INPUT_CODE_F7 = 1007; // 0x3ef
+ field public static final int INPUT_CODE_F8 = 1008; // 0x3f0
+ field public static final int INPUT_CODE_F9 = 1009; // 0x3f1
+ }
+
+ public final class RotaryEvent implements android.os.Parcelable {
+ ctor public RotaryEvent(int, boolean, @NonNull long[]);
+ method public int describeContents();
+ method public int getInputType();
+ method public int getNumberOfClicks();
+ method public long getUptimeMillisForClick(int);
+ method @NonNull public long[] getUptimeMillisForClicks();
+ method public boolean isClockwise();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.car.input.RotaryEvent> CREATOR;
+ }
+
}
package android.car.media {
diff --git a/car-lib/api/system-lint-baseline.txt b/car-lib/api/system-lint-baseline.txt
index 0f151f2..b36f2ce 100644
--- a/car-lib/api/system-lint-baseline.txt
+++ b/car-lib/api/system-lint-baseline.txt
@@ -41,6 +41,8 @@
Callbacks must be abstract class instead of interface to enable extension in future API levels: CarCabinEventCallback
CallbackInterface: android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback:
Callbacks must be abstract class instead of interface to enable extension in future API levels: CarHvacEventCallback
+CallbackInterface: android.car.input.CarInputManager.CarInputCaptureCallback:
+ Callbacks must be abstract class instead of interface to enable extension in future API levels: CarInputCaptureCallback
CallbackInterface: android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback:
Callbacks must be abstract class instead of interface to enable extension in future API levels: CarTrustAgentBleCallback
CallbackInterface: android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentEnrollmentCallback:
@@ -77,6 +79,9 @@
Registration methods should have overload that accepts delivery Executor: `registerCallback`
ExecutorRegistration: android.car.hardware.hvac.CarHvacManager#registerCallback(android.car.hardware.hvac.CarHvacManager.CarHvacEventCallback):
Registration methods should have overload that accepts delivery Executor: `registerCallback`
+ExecutorRegistration: android.car.input.CarInputManager#requestInputEventCapture(android.car.input.CarInputManager.CarInputCaptureCallback, int, int[], int):
+ Registration methods should have overload that accepts delivery Executor: `requestInputEventCapture`
+
ExecutorRegistration: android.car.storagemonitoring.CarStorageMonitoringManager#registerListener(android.car.storagemonitoring.CarStorageMonitoringManager.IoStatsListener):
Registration methods should have overload that accepts delivery Executor: `registerListener`
ExecutorRegistration: android.car.trust.CarTrustAgentEnrollmentManager#setBleCallback(android.car.trust.CarTrustAgentEnrollmentManager.CarTrustAgentBleCallback):
@@ -144,6 +149,12 @@
InternalField: android.car.input.CarInputHandlingService.InputFilter#mTargetDisplay:
Internal field mTargetDisplay must not be exposed
+ListenerLast: android.car.input.CarInputManager#requestInputEventCapture(android.car.input.CarInputManager.CarInputCaptureCallback, int, int[], int) parameter #1:
+ Listeners should always be at end of argument list (method `requestInputEventCapture`)
+ListenerLast: android.car.input.CarInputManager#requestInputEventCapture(android.car.input.CarInputManager.CarInputCaptureCallback, int, int[], int) parameter #2:
+ Listeners should always be at end of argument list (method `requestInputEventCapture`)
+ListenerLast: android.car.input.CarInputManager#requestInputEventCapture(android.car.input.CarInputManager.CarInputCaptureCallback, int, int[], int) parameter #3:
+ Listeners should always be at end of argument list (method `requestInputEventCapture`)
MinMaxConstant: android.car.diagnostic.IntegerSensorIndex#MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR:
If min/max could change in future, make them dynamic methods: android.car.diagnostic.IntegerSensorIndex#MAX_AIR_FLOW_RATE_FROM_MASS_AIR_FLOW_SENSOR
diff --git a/car-lib/src/android/car/Car.java b/car-lib/src/android/car/Car.java
index 4468c95..5d9f128 100644
--- a/car-lib/src/android/car/Car.java
+++ b/car-lib/src/android/car/Car.java
@@ -336,6 +336,8 @@
/**
* @hide
*/
+ @MandatoryFeature
+ @SystemApi
public static final String CAR_INPUT_SERVICE = "android.car.input";
/**
@@ -711,10 +713,18 @@
public static final String PERMISSION_USE_CAR_WATCHDOG =
"android.car.permission.USE_CAR_WATCHDOG";
+ /**
+ * Permission necessary to monitor Car input events.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String PERMISSION_CAR_MONITOR_INPUT =
+ "android.car.permission.CAR_MONITOR_INPUT";
+
/** Type of car connection: platform runs directly in car. */
public static final int CONNECTION_TYPE_EMBEDDED = 5;
-
/** @hide */
@IntDef({CONNECTION_TYPE_EMBEDDED})
@Retention(RetentionPolicy.SOURCE)
diff --git a/car-lib/src/android/car/input/CarInputManager.java b/car-lib/src/android/car/input/CarInputManager.java
index 84f582f..777d925 100644
--- a/car-lib/src/android/car/input/CarInputManager.java
+++ b/car-lib/src/android/car/input/CarInputManager.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.car.Car;
import android.car.CarManagerBase;
import android.car.CarOccupantZoneManager;
@@ -44,6 +45,7 @@
*
* @hide
*/
+@SystemApi
public final class CarInputManager extends CarManagerBase {
private static final String TAG = CarInputManager.class.getSimpleName();
@@ -55,8 +57,7 @@
* <p>
* Events (key, rotary and custom input events) are associated with display types.
* Display types are defined in {@link android.car.CarOccupantZoneManager}. This manager only
- * accepts the driver display types. Currently it accepts driver's displays only (
- * ({@link CarOccupantZoneManager#DISPLAY_TYPE_MAIN} and
+ * accepts the driver display types ({@link CarOccupantZoneManager#DISPLAY_TYPE_MAIN} and
* {@link CarOccupantZoneManager#DISPLAY_TYPE_INSTRUMENT_CLUSTER}).
*/
public interface CarInputCaptureCallback {
@@ -113,12 +114,12 @@
public static final int CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY = 0x2;
/** @hide */
- @IntDef(flag = true, prefix = { "CAPTURE_REQ_FLAGS_" }, value = {
+ @IntDef(flag = true, prefix = {"CAPTURE_REQ_FLAGS_"}, value = {
CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT,
CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY,
})
@Retention(RetentionPolicy.SOURCE)
- @interface CaptureRequestFlags {}
+ public @interface CaptureRequestFlags {}
/**
* This is special type to cover all INPUT_TYPE_*. This is used for clients using
@@ -148,16 +149,22 @@
* {@link KeyEvent#KEYCODE_DPAD_RIGHT}, {@link KeyEvent#KEYCODE_DPAD_CENTER},
* {@link KeyEvent#KEYCODE_DPAD_DOWN_LEFT}, {@link KeyEvent#KEYCODE_DPAD_DOWN_RIGHT},
* {@link KeyEvent#KEYCODE_DPAD_UP_LEFT}, {@link KeyEvent#KEYCODE_DPAD_UP_RIGHT}
+ *
+ * @hide
*/
public static final int INPUT_TYPE_DPAD_KEYS = 100;
/**
* This is for all {@code KeyEvent#KEYCODE_NAVIGATE_*} keys.
+ *
+ * @hide
*/
public static final int INPUT_TYPE_NAVIGATE_KEYS = 101;
/**
* This is for all {@code KeyEvent#KEYCODE_SYSTEM_NAVIGATE_*} keys.
+ *
+ * @hide
*/
public static final int INPUT_TYPE_SYSTEM_NAVIGATE_KEYS = 102;
@@ -244,11 +251,22 @@
* until the client receives a {@link CarInputCaptureCallback#onCaptureStateChanged(int, int[])}
* call with valid input types.
*
- * <p> The targetDisplayType parameter must represent a driver display type (
- * {@link CarOccupantZoneManager#DISPLAY_TYPE_MAIN} or
+ * <p> The targetDisplayType parameter must only contain driver display types (which are
+ * {@link CarOccupantZoneManager#DISPLAY_TYPE_MAIN} and
* {@link CarOccupantZoneManager#DISPLAY_TYPE_INSTRUMENT_CLUSTER}.
+ *
+ * <p>Callbacks are grouped and stacked per display and input types. Only the most recently
+ * registered callback will receive the incoming events for the associated display and input
+ * types.
+ *
+ * @throws SecurityException is caller doesn't have android.car.permission.CAR_MONITOR_INPUT
+ * permission granted
+ * @throws IllegalArgumentException if targetDisplayType parameter correspond to a non supported
+ * display type
+ * @throws IllegalArgumentException if inputTypes parameter contains invalid or non supported
+ * values
*/
- @RequiresPermission(android.Manifest.permission.MONITOR_INPUT)
+ @RequiresPermission(Car.PERMISSION_CAR_MONITOR_INPUT)
@InputCaptureResponseEnum
public int requestInputEventCapture(@NonNull CarInputCaptureCallback callback,
@DisplayTypeEnum int targetDisplayType,
@@ -289,12 +307,12 @@
* The event parameter display id will be overridden accordingly to the display type also passed
* as parameter.
*
- * @param event the event to inject
- * @param targetDisplayType the display type associated with the event
+ * @param event the key event to inject
+ * @param targetDisplayType the display type associated with the key event
* @throws RemoteException in case of failure when invoking car input service
*/
@RequiresPermission(android.Manifest.permission.INJECT_EVENTS)
- public void injectKeyEvent(KeyEvent event, @DisplayTypeEnum int targetDisplayType) {
+ public void injectKeyEvent(@NonNull KeyEvent event, @DisplayTypeEnum int targetDisplayType) {
try {
mService.injectKeyEvent(event, targetDisplayType);
} catch (RemoteException e) {
@@ -302,6 +320,7 @@
}
}
+ /** @hide */
@Override
protected void onCarDisconnected() {
synchronized (mLock) {
diff --git a/car-lib/src/android/car/input/CustomInputEvent.java b/car-lib/src/android/car/input/CustomInputEvent.java
index 129d8fa..fd5412c 100644
--- a/car-lib/src/android/car/input/CustomInputEvent.java
+++ b/car-lib/src/android/car/input/CustomInputEvent.java
@@ -17,6 +17,7 @@
package android.car.input;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,6 +35,7 @@
// input.
// TODO(b/12219669): Check with INPUT_CODE_Fn constants should move to
// android/car/Constants/CommonConstants.java. If keeping these constants, than add unit tests.
+@SystemApi
@DataClass(
genEqualsHashCode = true,
genAidl = true)
@@ -72,7 +74,7 @@
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
-
+ /** @hide */
@android.annotation.IntDef(prefix = "INPUT_CODE_", value = {
INPUT_CODE_F1,
INPUT_CODE_F2,
@@ -91,6 +93,7 @@
}
@DataClass.Generated.Member
+ @NonNull
public static String inputCodeToString(@InputCode int value) {
switch (value) {
case INPUT_CODE_F1:
@@ -314,3 +317,4 @@
//@formatter:on
// End of generated code
}
+
diff --git a/car-lib/src/android/car/input/RotaryEvent.java b/car-lib/src/android/car/input/RotaryEvent.java
index a43e1e2..565f039 100644
--- a/car-lib/src/android/car/input/RotaryEvent.java
+++ b/car-lib/src/android/car/input/RotaryEvent.java
@@ -16,6 +16,7 @@
package android.car.input;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -31,6 +32,7 @@
*
* @hide
*/
+@SystemApi
@DataClass(
genEqualsHashCode = true,
genAidl = true)
diff --git a/service/AndroidManifest.xml b/service/AndroidManifest.xml
index 1fe8c0c..e9755a5 100644
--- a/service/AndroidManifest.xml
+++ b/service/AndroidManifest.xml
@@ -780,6 +780,13 @@
android:label="@string/car_permission_label_set_car_vendor_category_10"
android:description="@string/car_permission_desc_set_car_vendor_category_10"/>
+ <!-- Allows an application to receive Car input events.
+ <p>Protection level: signature
+ -->
+ <permission android:name="android.car.permission.CAR_MONITOR_INPUT"
+ android:protectionLevel="signature"
+ android:label="@string/car_permission_label_monitor_input"
+ android:description="@string/car_permission_desc_monitor_input"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.DEVICE_POWER"/>
diff --git a/service/res/values/strings.xml b/service/res/values/strings.xml
index 0b1c265..1d92934 100644
--- a/service/res/values/strings.xml
+++ b/service/res/values/strings.xml
@@ -465,6 +465,11 @@
<!-- Permission text: apps control vendor properties in category 10 [CHAR LIMIT=NONE] -->
<string name="car_permission_desc_set_car_vendor_category_10" translatable="false">Control vendor specific properties in category 10.</string>
+ <!-- Permission text: apps can receive car input events [CHAR LIMIT=NONE] -->
+ <string name="car_permission_label_monitor_input" translatable="false">receive car input events</string>
+ <!-- Permission text: apps can receive car input events [CHAR LIMIT=NONE] -->
+ <string name="car_permission_desc_monitor_input" translatable="false">Receive car input events</string>
+
<!-- Permission text: enable or disable car's features [CHAR LIMIT=NONE] -->
<string name="car_permission_label_control_car_features">Enable or disable car\u2019s features</string>
<!-- Permission text: enable or disable car's features [CHAR LIMIT=NONE] -->
diff --git a/service/src/com/android/car/InputCaptureClientController.java b/service/src/com/android/car/InputCaptureClientController.java
index e33b0a5..ed55b24 100644
--- a/service/src/com/android/car/InputCaptureClientController.java
+++ b/service/src/com/android/car/InputCaptureClientController.java
@@ -21,6 +21,7 @@
import static java.util.Map.entry;
import android.annotation.NonNull;
+import android.car.Car;
import android.car.CarOccupantZoneManager;
import android.car.input.CarInputManager;
import android.car.input.CustomInputEvent;
@@ -239,7 +240,7 @@
public int requestInputEventCapture(ICarInputCallback callback,
@DisplayTypeEnum int targetDisplayType,
int[] inputTypes, int requestFlags) {
- ICarImpl.assertPermission(mContext, android.Manifest.permission.MONITOR_INPUT);
+ ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_MONITOR_INPUT);
Preconditions.checkArgument(SUPPORTED_DISPLAY_TYPES.contains(targetDisplayType),
"Display not supported yet:" + targetDisplayType);
diff --git a/tests/SampleCustomInputService/AndroidManifest.xml b/tests/SampleCustomInputService/AndroidManifest.xml
index d012ff4..596b0d6 100644
--- a/tests/SampleCustomInputService/AndroidManifest.xml
+++ b/tests/SampleCustomInputService/AndroidManifest.xml
@@ -25,7 +25,9 @@
<!-- The following permissions are required in order to communicate against Car Input API -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
- <uses-permission android:name="android.permission.MONITOR_INPUT"/>
+ <!-- This permission is required to register against CarInputManager in order to receive
+ custom input events. -->
+ <uses-permission android:name="android.car.permission.CAR_MONITOR_INPUT"/>
<!-- This permission is required to adjust car audio volume -->
<uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
diff --git a/tests/carservice_test/AndroidManifest.xml b/tests/carservice_test/AndroidManifest.xml
index 198292b..6040c5b 100644
--- a/tests/carservice_test/AndroidManifest.xml
+++ b/tests/carservice_test/AndroidManifest.xml
@@ -28,6 +28,7 @@
<uses-permission android:name="android.car.permission.CONTROL_APP_BLOCKING"/>
<uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME"/>
<uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_SETTINGS"/>
+ <uses-permission android:name="android.car.permission.CAR_MONITOR_INPUT"/>
<uses-permission android:name="android.car.permission.STORAGE_MONITORING"/>
<uses-permission android:name="android.car.permission.READ_CAR_OCCUPANT_AWARENESS_STATE"/>