diff options
12 files changed, 265 insertions, 12 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 88c961afb8e0..d1b9716b4cd3 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -16803,6 +16803,18 @@ package android.graphics.text { package android.hardware { + public abstract class Battery { + ctor public Battery(); + method @FloatRange(from=-1.0F, to=1.0f) public abstract float getCapacity(); + method public abstract int getStatus(); + method public abstract boolean hasBattery(); + field public static final int STATUS_CHARGING = 2; // 0x2 + field public static final int STATUS_DISCHARGING = 3; // 0x3 + field public static final int STATUS_FULL = 5; // 0x5 + field public static final int STATUS_NOT_CHARGING = 4; // 0x4 + field public static final int STATUS_UNKNOWN = 1; // 0x1 + } + @Deprecated public class Camera { method @Deprecated public final void addCallbackBuffer(byte[]); method @Deprecated public final void autoFocus(android.hardware.Camera.AutoFocusCallback); @@ -46363,6 +46375,7 @@ package android.view { public final class InputDevice implements android.os.Parcelable { method public int describeContents(); + method @NonNull public android.hardware.Battery getBattery(); method public int getControllerNumber(); method public String getDescriptor(); method public static android.view.InputDevice getDevice(int); diff --git a/core/java/android/hardware/Battery.java b/core/java/android/hardware/Battery.java new file mode 100644 index 000000000000..24c8d76a9813 --- /dev/null +++ b/core/java/android/hardware/Battery.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2021 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 android.hardware; + +import android.annotation.FloatRange; +import android.annotation.IntDef; +import android.os.BatteryManager; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * The Battery class is a representation of a single battery on a device. + */ +public abstract class Battery { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "STATUS_" }, value = { + STATUS_UNKNOWN, + STATUS_CHARGING, + STATUS_DISCHARGING, + STATUS_NOT_CHARGING, + STATUS_FULL + }) + public @interface BatteryStatus { + } + + /** Battery status is unknown. */ + public static final int STATUS_UNKNOWN = BatteryManager.BATTERY_STATUS_UNKNOWN; + /** Battery is charging. */ + public static final int STATUS_CHARGING = BatteryManager.BATTERY_STATUS_CHARGING; + /** Battery is discharging. */ + public static final int STATUS_DISCHARGING = BatteryManager.BATTERY_STATUS_DISCHARGING; + /** Battery is connected to power but not charging. */ + public static final int STATUS_NOT_CHARGING = BatteryManager.BATTERY_STATUS_NOT_CHARGING; + /** Battery is full. */ + public static final int STATUS_FULL = BatteryManager.BATTERY_STATUS_FULL; + + /** + * Check whether the hardware has a battery. + * + * @return True if the hardware has a battery, else false. + */ + public abstract boolean hasBattery(); + + /** + * Get the battery status. + * + * @return the battery status. + */ + public abstract @BatteryStatus int getStatus(); + + /** + * Get remaining battery capacity as float percentage [0.0f, 1.0f] of total capacity + * Returns -1 when battery capacity can't be read. + * + * @return the battery capacity. + */ + public abstract @FloatRange(from = -1.0f, to = 1.0f) float getCapacity(); +} diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index b39df4d2b6bf..c69c47f80d01 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -93,6 +93,10 @@ interface IInputManager { int[] getVibratorIds(int deviceId); boolean isVibrating(int deviceId); + // Input device battery query. + int getBatteryStatus(int deviceId); + int getBatteryCapacity(int deviceId); + void setPointerIconType(int typeId); void setCustomPointerIcon(in PointerIcon icon); diff --git a/core/java/android/hardware/input/InputDeviceBattery.java b/core/java/android/hardware/input/InputDeviceBattery.java new file mode 100644 index 000000000000..0fe124e2c0ce --- /dev/null +++ b/core/java/android/hardware/input/InputDeviceBattery.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2021 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 android.hardware.input; + +import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN; +import static android.os.IInputConstants.INVALID_BATTERY_CAPACITY; + +import android.hardware.Battery; + +/** + * Battery implementation for input devices. + * + * @hide + */ +public final class InputDeviceBattery extends Battery { + private static final float NULL_BATTERY_CAPACITY = -1.0f; + + private final InputManager mInputManager; + private final int mDeviceId; + private final boolean mHasBattery; + + InputDeviceBattery(InputManager inputManager, int deviceId, boolean hasBattery) { + mInputManager = inputManager; + mDeviceId = deviceId; + mHasBattery = hasBattery; + } + + @Override + public boolean hasBattery() { + return mHasBattery; + } + + @Override + public int getStatus() { + if (!mHasBattery) { + return BATTERY_STATUS_UNKNOWN; + } + return mInputManager.getBatteryStatus(mDeviceId); + } + + @Override + public float getCapacity() { + if (mHasBattery) { + int capacity = mInputManager.getBatteryCapacity(mDeviceId); + if (capacity != INVALID_BATTERY_CAPACITY) { + return (float) capacity / 100.0f; + } + } + return NULL_BATTERY_CAPACITY; + } +} diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index e63dc112233f..185c59d8ccfc 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1245,6 +1245,32 @@ public final class InputManager { } /** + * Get the battery status of the input device + * @param deviceId The input device ID + * @hide + */ + public int getBatteryStatus(int deviceId) { + try { + return mIm.getBatteryStatus(deviceId); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** + * Get the remaining battery capacity of the input device + * @param deviceId The input device ID + * @hide + */ + public int getBatteryCapacity(int deviceId) { + try { + return mIm.getBatteryCapacity(deviceId); + } catch (RemoteException ex) { + throw ex.rethrowFromSystemServer(); + } + } + + /** * Add a runtime association between the input port and the display port. This overrides any * static associations. * @param inputPort The port of the input device. @@ -1471,6 +1497,15 @@ public final class InputManager { } /** + * Gets a battery object associated with an input device, assuming it has one. + * @return The battery, never null. + * @hide + */ + public InputDeviceBattery getInputDeviceBattery(int deviceId, boolean hasBattery) { + return new InputDeviceBattery(this, deviceId, hasBattery); + } + + /** * Listens for changes in input devices. */ public interface InputDeviceListener { diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 242188991e27..bc03222f390d 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -22,6 +22,7 @@ import android.annotation.RequiresPermission; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.hardware.Battery; import android.hardware.SensorManager; import android.hardware.input.InputDeviceIdentifier; import android.hardware.input.InputManager; @@ -73,6 +74,7 @@ public final class InputDevice implements Parcelable { private final boolean mHasMicrophone; private final boolean mHasButtonUnderPad; private final boolean mHasSensor; + private final boolean mHasBattery; private final ArrayList<MotionRange> mMotionRanges = new ArrayList<MotionRange>(); @GuardedBy("mMotionRanges") @@ -84,6 +86,9 @@ public final class InputDevice implements Parcelable { @GuardedBy("mMotionRanges") private SensorManager mSensorManager; + @GuardedBy("mMotionRanges") + private Battery mBattery; + /** * A mask for input source classes. * @@ -455,7 +460,7 @@ public final class InputDevice implements Parcelable { public InputDevice(int id, int generation, int controllerNumber, String name, int vendorId, int productId, String descriptor, boolean isExternal, int sources, int keyboardType, KeyCharacterMap keyCharacterMap, boolean hasVibrator, boolean hasMicrophone, - boolean hasButtonUnderPad, boolean hasSensor) { + boolean hasButtonUnderPad, boolean hasSensor, boolean hasBattery) { mId = id; mGeneration = generation; mControllerNumber = controllerNumber; @@ -471,6 +476,7 @@ public final class InputDevice implements Parcelable { mHasMicrophone = hasMicrophone; mHasButtonUnderPad = hasButtonUnderPad; mHasSensor = hasSensor; + mHasBattery = hasBattery; mIdentifier = new InputDeviceIdentifier(descriptor, vendorId, productId); } @@ -490,6 +496,7 @@ public final class InputDevice implements Parcelable { mHasMicrophone = in.readInt() != 0; mHasButtonUnderPad = in.readInt() != 0; mHasSensor = in.readInt() != 0; + mHasBattery = in.readInt() != 0; mIdentifier = new InputDeviceIdentifier(mDescriptor, mVendorId, mProductId); int numRanges = in.readInt(); @@ -837,6 +844,22 @@ public final class InputDevice implements Parcelable { } /** + * Gets the battery object associated with the device, if there is one. + * Even if the device does not have a battery, the result is never null. + * Use {@link Battery#hasBattery} to determine whether a battery is + * present. + * + * @return The battery object associated with the device, never null. + */ + @NonNull + public Battery getBattery() { + if (mBattery == null) { + mBattery = InputManager.getInstance().getInputDeviceBattery(mId, mHasBattery); + } + return mBattery; + } + + /** * Gets the sensor manager service associated with the input device. * Even if the device does not have a sensor, the result is never null. * Use {@link SensorManager#getSensorList} to get a full list of all supported sensors. @@ -1058,6 +1081,7 @@ public final class InputDevice implements Parcelable { out.writeInt(mHasMicrophone ? 1 : 0); out.writeInt(mHasButtonUnderPad ? 1 : 0); out.writeInt(mHasSensor ? 1 : 0); + out.writeInt(mHasBattery ? 1 : 0); final int numRanges = mMotionRanges.size(); out.writeInt(numRanges); @@ -1104,6 +1128,8 @@ public final class InputDevice implements Parcelable { description.append(" Has Sensor: ").append(mHasSensor).append("\n"); + description.append(" Has battery: ").append(mHasBattery).append("\n"); + description.append(" Has mic: ").append(mHasMicrophone).append("\n"); description.append(" Sources: 0x").append(Integer.toHexString(mSources)).append(" ("); diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp index 4eaa016df6f2..9cc72437a023 100644 --- a/core/jni/android_view_InputDevice.cpp +++ b/core/jni/android_view_InputDevice.cpp @@ -70,7 +70,8 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi deviceInfo.isExternal(), deviceInfo.getSources(), deviceInfo.getKeyboardType(), kcmObj.get(), deviceInfo.hasVibrator(), hasMic, - deviceInfo.hasButtonUnderPad(), deviceInfo.hasSensor())); + deviceInfo.hasButtonUnderPad(), deviceInfo.hasSensor(), + deviceInfo.hasBattery())); const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); for (const InputDeviceInfo::MotionRange& range: ranges) { @@ -90,9 +91,10 @@ int register_android_view_InputDevice(JNIEnv* env) gInputDeviceClassInfo.clazz = FindClassOrDie(env, "android/view/InputDevice"); gInputDeviceClassInfo.clazz = MakeGlobalRefOrDie(env, gInputDeviceClassInfo.clazz); - gInputDeviceClassInfo.ctor = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>", - "(IIILjava/lang/String;IILjava/lang/" - "String;ZIILandroid/view/KeyCharacterMap;ZZZZ)V"); + gInputDeviceClassInfo.ctor = + GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "<init>", + "(IIILjava/lang/String;IILjava/lang/" + "String;ZIILandroid/view/KeyCharacterMap;ZZZZZ)V"); gInputDeviceClassInfo.addMotionRange = GetMethodIDOrDie(env, gInputDeviceClassInfo.clazz, "addMotionRange", "(IIFFFFF)V"); diff --git a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java index b319886ae466..341ee37aee39 100644 --- a/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java +++ b/core/tests/coretests/src/android/hardware/input/InputDeviceSensorManagerTest.java @@ -149,7 +149,7 @@ public class InputDeviceSensorManagerTest { 0 /* vendorId */, 0 /* productId */, "descriptor", true /* isExternal */, 0 /* sources */, 0 /* keyboardType */, null /* keyCharacterMap */, false /* hasVibrator */, false /* hasMicrophone */, false /* hasButtonUnderpad */, - true /* hasSensor */); + true /* hasSensor */, false /* hasBattery */); assertTrue(d.hasSensor()); return d; } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index f6e08fbaf379..2e4200c1f7d9 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -289,6 +289,8 @@ public class InputManagerService extends IInputManager.Stub private static native void nativeCancelVibrate(long ptr, int deviceId, int token); private static native boolean nativeIsVibrating(long ptr, int deviceId); private static native int[] nativeGetVibratorIds(long ptr, int deviceId); + private static native int nativeGetBatteryCapacity(long ptr, int deviceId); + private static native int nativeGetBatteryStatus(long ptr, int deviceId); private static native void nativeReloadKeyboardLayouts(long ptr); private static native void nativeReloadDeviceAliases(long ptr); private static native String nativeDump(long ptr); @@ -2008,6 +2010,18 @@ public class InputManagerService extends IInputManager.Stub // Binder call @Override + public int getBatteryStatus(int deviceId) { + return nativeGetBatteryStatus(mPtr, deviceId); + } + + // Binder call + @Override + public int getBatteryCapacity(int deviceId) { + return nativeGetBatteryCapacity(mPtr, deviceId); + } + + // Binder call + @Override public void setPointerIconType(int iconId) { nativeSetPointerIconType(mPtr, iconId); } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index dc15b0749bb1..5b587e9859d8 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -26,14 +26,14 @@ // Log debug messages about InputDispatcherPolicy #define DEBUG_INPUT_DISPATCHER_POLICY 0 - -#include <atomic> -#include <cinttypes> -#include <limits.h> #include <android-base/parseint.h> #include <android-base/stringprintf.h> +#include <android/os/IInputConstants.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> +#include <limits.h> +#include <atomic> +#include <cinttypes> #include <utils/Log.h> #include <utils/Looper.h> @@ -46,6 +46,7 @@ #include <input/SpriteController.h> #include <ui/Region.h> +#include <batteryservice/include/batteryservice/BatteryServiceConstants.h> #include <inputflinger/InputManager.h> #include <android_os_MessageQueue.h> @@ -1908,6 +1909,20 @@ static jintArray nativeGetVibratorIds(JNIEnv* env, jclass clazz, jlong ptr, jint return vibIdArray; } +static jint nativeGetBatteryCapacity(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId) { + NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); + + std::optional<int32_t> ret = im->getInputManager()->getReader()->getBatteryCapacity(deviceId); + return static_cast<jint>(ret.value_or(android::os::IInputConstants::INVALID_BATTERY_CAPACITY)); +} + +static jint nativeGetBatteryStatus(JNIEnv* env, jclass /* clazz */, jlong ptr, jint deviceId) { + NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); + + std::optional<int32_t> ret = im->getInputManager()->getReader()->getBatteryStatus(deviceId); + return static_cast<jint>(ret.value_or(BATTERY_STATUS_UNKNOWN)); +} + static void nativeReloadKeyboardLayouts(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); @@ -2163,6 +2178,8 @@ static const JNINativeMethod gInputManagerMethods[] = { {"nativeCancelVibrate", "(JII)V", (void*)nativeCancelVibrate}, {"nativeIsVibrating", "(JI)Z", (void*)nativeIsVibrating}, {"nativeGetVibratorIds", "(JI)[I", (void*)nativeGetVibratorIds}, + {"nativeGetBatteryCapacity", "(JI)I", (void*)nativeGetBatteryCapacity}, + {"nativeGetBatteryStatus", "(JI)I", (void*)nativeGetBatteryStatus}, {"nativeReloadKeyboardLayouts", "(J)V", (void*)nativeReloadKeyboardLayouts}, {"nativeReloadDeviceAliases", "(J)V", (void*)nativeReloadDeviceAliases}, {"nativeDump", "(J)Ljava/lang/String;", (void*)nativeDump}, diff --git a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java index 743848c2453c..2932926b0b05 100644 --- a/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/VibratorServiceTest.java @@ -745,7 +745,8 @@ public class VibratorServiceTest { private InputDevice createInputDeviceWithVibrator(int id) { return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0, - null, /* hasVibrator= */ true, false, false, false /* hasSensor */); + null, /* hasVibrator= */ true, false, false, false /* hasSensor */, + false /* hasBattery */); } private static <T> void addLocalServiceMock(Class<T> clazz, T mock) { diff --git a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java index 28d313b4d4b5..e71c2f5ba8da 100644 --- a/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java +++ b/services/tests/servicestests/src/com/android/server/vibrator/InputDeviceDelegateTest.java @@ -294,6 +294,8 @@ public class InputDeviceDelegateTest { private InputDevice createInputDevice(int id, boolean hasVibrator) { return new InputDevice(id, 0, 0, "name", 0, 0, "description", false, 0, 0, - null, hasVibrator, false, false, false /* hasSensor */); + null, hasVibrator, false, false, false /* hasSensor */, false /* hasBattery */); + + } } |