我们先看CarInputManager的requestInputEventCapture方法:
//packages/services/Car/car-lib/src/android/car/input/CarInputManager.java
public final class CarInputManager extends CarManagerBase {
private final ICarInput mService;
public int requestInputEventCapture(@DisplayTypeEnum int targetDisplayType,
@NonNull @InputTypeEnum int[] inputTypes,
@CaptureRequestFlags int requestFlags,
@NonNull @CallbackExecutor Executor executor,
@NonNull CarInputCaptureCallback callback) {
Objects.requireNonNull(executor);
Objects.requireNonNull(callback);
synchronized (mLock) {
mCarInputCaptureCallbacks.put(targetDisplayType,
new CallbackHolder(callback, executor));
}
try {
return mService.requestInputEventCapture(mServiceCallback, targetDisplayType,
inputTypes, requestFlags); //调用ICarInput 的requestInputEventCapture方法
} catch (RemoteException e) {
return handleRemoteExceptionFromCarService(e, INPUT_CAPTURE_RESPONSE_FAILED);
}
}
}
在CarInputManager的requestInputEventCapture中调用ICarInput的requestInputEventCapture方法,ICarInput接口由CarInputService 实现,因此会调用CarInputService 的requestInputEventCapture:
//packages/services/Car/service/src/com/android/car/CarInputService.java
public class CarInputService extends ICarInput.Stub {
private final InputCaptureClientController mCaptureController;
public int requestInputEventCapture(ICarInputCallback callback,
@DisplayTypeEnum int targetDisplayType,
int[] inputTypes, int requestFlags) {
return mCaptureController.requestInputEventCapture(callback, targetDisplayType, inputTypes,
requestFlags);
}
}
在CarInputService中调用InputCaptureClientController的requestInputEventCapture方法:
//packages/services/Car/service/src/com/android/car/InputCaptureClientController.java
public class InputCaptureClientController {
public int requestInputEventCapture(ICarInputCallback callback,
@DisplayTypeEnum int targetDisplayType,
int[] inputTypes, int requestFlags) {
CarServiceUtils.assertAnyPermission(mContext,
Car.PERMISSION_CAR_MONITOR_INPUT, PermissionHelper.MONITOR_INPUT);
Preconditions.checkArgument(SUPPORTED_DISPLAY_TYPES.contains(targetDisplayType),
"Display not supported yet:" + targetDisplayType);
boolean isRequestingAllEvents =
(requestFlags & CarInputManager.CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY) != 0;
if (isRequestingAllEvents) {
if (targetDisplayType != CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER) {
CarServiceUtils.assertCallingFromSystemProcessOrSelf();
} else { // for DISPLAY_TYPE_INSTRUMENT_CLUSTER
if (!CarServiceUtils.isCallingFromSystemProcessOrSelf()) {
CarServiceUtils.assertPackageName(mContext, mClusterHomePackage);
}
}
if (inputTypes.length != 1 || inputTypes[0] != CarInputManager.INPUT_TYPE_ALL_INPUTS) {
throw new IllegalArgumentException("Input type should be INPUT_TYPE_ALL_INPUTS"
+ " for CAPTURE_REQ_FLAGS_TAKE_ALL_EVENTS_FOR_DISPLAY");
}
}
if (targetDisplayType != CarOccupantZoneManager.DISPLAY_TYPE_INSTRUMENT_CLUSTER
&& targetDisplayType != CarOccupantZoneManager.DISPLAY_TYPE_MAIN) {
throw new IllegalArgumentException("Unrecognized display type:" + targetDisplayType);
}
if (inputTypes == null) {
throw new IllegalArgumentException("inputTypes cannot be null");
}
assertInputTypeValid(inputTypes);
Arrays.sort(inputTypes);
IBinder clientBinder = callback.asBinder();
boolean allowsDelayedGrant =
(requestFlags & CarInputManager.CAPTURE_REQ_FLAGS_ALLOW_DELAYED_GRANT) != 0;
int ret = CarInputManager.INPUT_CAPTURE_RESPONSE_SUCCEEDED;
if (DBG_CALLS) {
Slogf.i(TAG,
"requestInputEventCapture callback:" + callback
+ ", display:" + targetDisplayType
+ ", inputTypes:" + Arrays.toString(inputTypes)
+ ", flags:" + requestFlags);
}
ClientsToDispatch clientsToDispatch = new ClientsToDispatch(targetDisplayType);
synchronized (mLock) {
HashMap<IBinder, ClientInfoForDisplay> allClientsForDisplay = mAllClients.get(
targetDisplayType);
if (allClientsForDisplay == null) {
allClientsForDisplay = new HashMap<IBinder, ClientInfoForDisplay>();
mAllClients.put(targetDisplayType, allClientsForDisplay);
}
ClientInfoForDisplay oldClientInfo = allClientsForDisplay.remove(clientBinder);
LinkedList<ClientInfoForDisplay> fullCapturersStack = mFullDisplayEventCapturers.get(
targetDisplayType);
if (fullCapturersStack == null) {
fullCapturersStack = new LinkedList<ClientInfoForDisplay>();
mFullDisplayEventCapturers.put(targetDisplayType, fullCapturersStack);
}
if (!isRequestingAllEvents && fullCapturersStack.size() > 0
&& fullCapturersStack.getFirst() != oldClientInfo && !allowsDelayedGrant) {
// full capturing active. return failed if not delayed granting.
return CarInputManager.INPUT_CAPTURE_RESPONSE_FAILED;
}
// Now we need to register client anyway, so do death monitoring from here.
ClientInfoForDisplay newClient = new ClientInfoForDisplay(Binder.getCallingUid(),
Binder.getCallingPid(), callback, targetDisplayType,
inputTypes, requestFlags);
try {
newClient.linkToDeath();
} catch (RemoteException e) {
// client died
Slogf.i(TAG, "requestInputEventCapture, cannot linkToDeath to client, pid:"
+ Binder.getCallingUid());
return CarInputManager.INPUT_CAPTURE_RESPONSE_FAILED;
}
SparseArray<LinkedList<ClientInfoForDisplay>> perInputStacks =
mPerInputTypeCapturers.get(targetDisplayType);
if (perInputStacks == null) {
perInputStacks = new SparseArray<LinkedList<ClientInfoForDisplay>>();
mPerInputTypeCapturers.put(targetDisplayType, perInputStacks);
}
if (isRequestingAllEvents) {
if (!fullCapturersStack.isEmpty()) {
ClientInfoForDisplay oldCapturer = fullCapturersStack.getFirst();
if (oldCapturer != oldClientInfo) {
oldCapturer.mGrantedTypes.clear();
clientsToDispatch.add(oldCapturer);
}
fullCapturersStack.remove(oldClientInfo);
} else { // All per input type top stack client should be notified.
for (int i = 0; i < perInputStacks.size(); i++) {
LinkedList<ClientInfoForDisplay> perTypeStack = perInputStacks.valueAt(i);
if (!perTypeStack.isEmpty()) {
ClientInfoForDisplay topClient = perTypeStack.getFirst();
if (topClient != oldClientInfo) {
topClient.mGrantedTypes.clear();
clientsToDispatch.add(topClient);
}
// Even if the client was on top, the one in back does not need
// update.
perTypeStack.remove(oldClientInfo);
}
}
}
fullCapturersStack.addFirst(newClient);
} else {
boolean hadFullCapture = false;
boolean fullCaptureActive = false;
if (fullCapturersStack.size() > 0) {
if (fullCapturersStack.getFirst() == oldClientInfo) {
fullCapturersStack.remove(oldClientInfo);
// Now we need to check if there is other client in fullCapturersStack
if (fullCapturersStack.size() > 0) {
fullCaptureActive = true;
ret = CarInputManager.INPUT_CAPTURE_RESPONSE_DELAYED;
ClientInfoForDisplay topClient = fullCapturersStack.getFirst();
topClient.mGrantedTypes.clear();
topClient.mGrantedTypes.add(CarInputManager.INPUT_TYPE_ALL_INPUTS);
clientsToDispatch.add(topClient);
} else {
hadFullCapture = true;
}
} else {
// other client doing full capturing and it should have DELAYED_GRANT flag.
fullCaptureActive = true;
ret = CarInputManager.INPUT_CAPTURE_RESPONSE_DELAYED;
}
}
for (int i = 0; i < perInputStacks.size(); i++) {
LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.valueAt(i);
perInputStack.remove(oldClientInfo);
}
// Now go through per input stack
for (int inputType : inputTypes) {
LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.get(
inputType);
if (perInputStack == null) {
perInputStack = new LinkedList<ClientInfoForDisplay>();
perInputStacks.put(inputType, perInputStack);
}
if (perInputStack.size() > 0) {
ClientInfoForDisplay oldTopClient = perInputStack.getFirst();
if (oldTopClient.mGrantedTypes.remove(Integer.valueOf(inputType))) {
clientsToDispatch.add(oldTopClient);
}
}
if (!fullCaptureActive) {
newClient.mGrantedTypes.add(inputType);
}
perInputStack.addFirst(newClient);
}
if (!fullCaptureActive && hadFullCapture) {
for (int i = 0; i < perInputStacks.size(); i++) {
int inputType = perInputStacks.keyAt(i);
LinkedList<ClientInfoForDisplay> perInputStack = perInputStacks.valueAt(
i);
if (perInputStack.size() > 0) {
ClientInfoForDisplay topStackClient = perInputStack.getFirst();
if (topStackClient == newClient) {
continue;
}
if (!topStackClient.mGrantedTypes.contains(inputType)) {
topStackClient.mGrantedTypes.add(inputType);
clientsToDispatch.add(topStackClient);
}
}
}
}
}
allClientsForDisplay.put(clientBinder, newClient);
dispatchClientCallbackLocked(clientsToDispatch);
}
return ret;
}
}
在InputCaptureClientController中调用了dispatchClientCallbackLocked方法:
//packages/services/Car/service/src/com/android/car/InputCaptureClientController.java
public class InputCaptureClientController {
private void dispatchClientCallbackLocked(ClientsToDispatch clientsToDispatch) {
if (clientsToDispatch.mClientsToDispatch.isEmpty()) {
return;
}
if (DBG_DISPATCH) {
Slogf.i(TAG, "dispatchClientCallbackLocked, number of clients:"
+ clientsToDispatch.mClientsToDispatch.size());
}
mClientDispatchQueue.add(clientsToDispatch);
CarServiceUtils.runOnCommon(() -> {
ClientsToDispatch clients;
synchronized (mLock) {
if (mClientDispatchQueue.isEmpty()) {
return;
}
clients = mClientDispatchQueue.pop();
}
if (DBG_DISPATCH) {
Slogf.i(TAG, "dispatching to clients, num of clients:"
+ clients.mClientsToDispatch.size()
+ ", display:" + clients.mDisplayType);
}
for (int i = 0; i < clients.mClientsToDispatch.size(); i++) {
ICarInputCallback callback = clients.mClientsToDispatch.keyAt(i);
int[] inputTypes = clients.mClientsToDispatch.valueAt(i);
Arrays.sort(inputTypes);
if (DBG_DISPATCH) {
Slogf.i(TAG, "dispatching to client, callback:"
+ callback + ", inputTypes:" + Arrays.toString(inputTypes));
}
try {
callback.onCaptureStateChanged(clients.mDisplayType, inputTypes); //调用onCaptureStateChanged回调接口
} catch (RemoteException e) {
// Ignore. Let death handler deal with it.
}
}
});
}
}