1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.stylus 18 19 import android.hardware.BatteryState 20 import android.hardware.input.InputManager 21 import android.view.InputDevice 22 import com.android.systemui.CoreStartable 23 import com.android.systemui.dagger.SysUISingleton 24 import com.android.systemui.flags.FeatureFlags 25 import com.android.systemui.flags.Flags 26 import javax.inject.Inject 27 28 /** 29 * A [CoreStartable] that listens to USI stylus battery events, to manage the [StylusUsiPowerUI] 30 * notification controller. 31 */ 32 @SysUISingleton 33 class StylusUsiPowerStartable 34 @Inject 35 constructor( 36 private val stylusManager: StylusManager, 37 private val inputManager: InputManager, 38 private val stylusUsiPowerUi: StylusUsiPowerUI, 39 private val featureFlags: FeatureFlags, 40 ) : CoreStartable, StylusManager.StylusCallback, StylusManager.StylusBatteryCallback { 41 onStylusAddednull42 override fun onStylusAdded(deviceId: Int) { 43 // On some devices, the addition of a new internal stylus indicates the use of a 44 // USI stylus with a different vendor/product ID. We would therefore like to reset 45 // the battery notification suppression, in case the user has dismissed a low battery 46 // notification of the previous stylus. 47 val device = inputManager.getInputDevice(deviceId) ?: return 48 if (!device.isExternal) { 49 stylusUsiPowerUi.updateSuppression(false) 50 } 51 } 52 onStylusBluetoothConnectednull53 override fun onStylusBluetoothConnected(deviceId: Int, btAddress: String) { 54 stylusUsiPowerUi.refresh() 55 } 56 onStylusBluetoothDisconnectednull57 override fun onStylusBluetoothDisconnected(deviceId: Int, btAddress: String) { 58 stylusUsiPowerUi.refresh() 59 } 60 onStylusUsiBatteryStateChangednull61 override fun onStylusUsiBatteryStateChanged( 62 deviceId: Int, 63 eventTimeMillis: Long, 64 batteryState: BatteryState 65 ) { 66 if (batteryState.isPresent && batteryState.capacity > 0f) { 67 stylusUsiPowerUi.updateBatteryState(deviceId, batteryState) 68 } 69 } 70 startnull71 override fun start() { 72 if (!featureFlags.isEnabled(Flags.ENABLE_USI_BATTERY_NOTIFICATIONS)) return 73 if (!hostDeviceSupportsStylusInput()) return 74 75 stylusUsiPowerUi.init() 76 stylusManager.registerCallback(this) 77 stylusManager.startListener() 78 } 79 hostDeviceSupportsStylusInputnull80 private fun hostDeviceSupportsStylusInput(): Boolean { 81 return inputManager.inputDeviceIds 82 .asSequence() 83 .mapNotNull { inputManager.getInputDevice(it) } 84 .any { it.supportsSource(InputDevice.SOURCE_STYLUS) && !it.isExternal } 85 } 86 87 companion object { 88 private val TAG = StylusUsiPowerStartable::class.simpleName.orEmpty() 89 } 90 } 91