Loading core/java/android/companion/CompanionDeviceManager.java +89 −0 Original line number Diff line number Diff line Loading @@ -419,6 +419,11 @@ public final class CompanionDeviceManager { private final ArrayList<OnTransportsChangedListenerProxy> mTransportsChangedListeners = new ArrayList<>(); /** Association ID -> List of listeners */ @GuardedBy("mTransportEventListeners") private final SparseArray<List<OnTransportEventListenerProxy>> mTransportEventListeners = new SparseArray<>(); @GuardedBy("mMessageReceivedListeners") private final SparseArray<Set<OnMessageReceivedListenerProxy>> mMessageReceivedListeners = new SparseArray<>(); Loading Loading @@ -1189,6 +1194,73 @@ public final class CompanionDeviceManager { } } /** * Adds a listener for an event reported by attached transport. * * @param executor The executor which will be used to invoke the listener. * @param listener Called when a transport reports an event. * @see com.android.server.companion.transport.Transport * @hide */ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void addOnTransportEventListener( @NonNull @CallbackExecutor Executor executor, int associationId, @NonNull Consumer<Integer> listener) { if (mService == null) { Log.w(TAG, "CompanionDeviceManager service is not available."); return; } synchronized (mTransportsChangedListeners) { final OnTransportEventListenerProxy proxy = new OnTransportEventListenerProxy( executor, listener); try { mService.addOnTransportEventListener(associationId, proxy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } if (!mTransportEventListeners.contains(associationId)) { mTransportEventListeners.put(associationId, new ArrayList<>()); } mTransportEventListeners.get(associationId).add(proxy); } } /** * Removes the registered listener for transport events. * @see com.android.server.companion.transport.Transport * @hide */ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void removeOnTransportEventListener(int associationId, @NonNull Consumer<Integer> listener) { if (mService == null) { Log.w(TAG, "CompanionDeviceManager service is not available."); return; } synchronized (mTransportEventListeners) { if (!mTransportEventListeners.contains(associationId)) { throw new IllegalArgumentException("Association id=[" + associationId + "] doesn't have any registered event listener."); } final Iterator<OnTransportEventListenerProxy> iterator = mTransportEventListeners.get(associationId).iterator(); while (iterator.hasNext()) { final OnTransportEventListenerProxy proxy = iterator.next(); if (proxy.mListener == listener) { try { mService.removeOnTransportEventListener(associationId, proxy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } iterator.remove(); } } } } /** * Checks whether the bluetooth device represented by the mac address was recently associated * with the companion app. This allows these devices to skip the Bluetooth pairing dialog if Loading Loading @@ -2003,6 +2075,23 @@ public final class CompanionDeviceManager { } } private static class OnTransportEventListenerProxy extends IOnTransportEventListener.Stub { private final Executor mExecutor; private final Consumer<Integer> mListener; private OnTransportEventListenerProxy(Executor executor, Consumer<Integer> listener) { mExecutor = executor; mListener = listener; } @Override public void onTransportEvent(int eventCode) { mExecutor.execute(() -> mListener.accept(eventCode)); } } private static class SystemDataTransferCallbackProxy extends ISystemDataTransferCallback.Stub { private final Executor mExecutor; private final OutcomeReceiver<Void, CompanionException> mCallback; Loading core/java/android/companion/ICompanionDeviceManager.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.app.PendingIntent; import android.companion.IAssociationRequestCallback; import android.companion.IOnAssociationsChangedListener; import android.companion.IOnMessageReceivedListener; import android.companion.IOnTransportEventListener; import android.companion.IOnTransportsChangedListener; import android.companion.ISystemDataTransferCallback; import android.companion.AssociationInfo; Loading Loading @@ -98,6 +99,12 @@ interface ICompanionDeviceManager { @EnforcePermission("USE_COMPANION_TRANSPORTS") void removeOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener); @EnforcePermission("USE_COMPANION_TRANSPORTS") void addOnTransportEventListener(int associationId, IOnTransportEventListener listener); @EnforcePermission("USE_COMPANION_TRANSPORTS") void removeOnTransportEventListener(int associationId, IOnTransportEventListener listener); @EnforcePermission("REQUEST_COMPANION_SELF_MANAGED") void notifySelfManagedDeviceAppeared(int associationId); Loading core/java/android/companion/IOnTransportEventListener.aidl 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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 per missions and * limitations under the License. */ package android.companion; /** @hide */ interface IOnTransportEventListener { oneway void onTransportEvent(int eventCode); } No newline at end of file services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +19 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.companion.IAssociationRequestCallback; import android.companion.ICompanionDeviceManager; import android.companion.IOnAssociationsChangedListener; import android.companion.IOnMessageReceivedListener; import android.companion.IOnTransportEventListener; import android.companion.IOnTransportsChangedListener; import android.companion.ISystemDataTransferCallback; import android.companion.ObservingDevicePresenceRequest; Loading Loading @@ -418,6 +419,24 @@ public class CompanionDeviceManagerService extends SystemService { mTransportManager.removeListener(messageType, listener); } @Override @EnforcePermission(USE_COMPANION_TRANSPORTS) public void addOnTransportEventListener(int associationId, IOnTransportEventListener listener) { addOnTransportEventListener_enforcePermission(); mTransportManager.addListener(associationId, listener); } @Override @EnforcePermission(USE_COMPANION_TRANSPORTS) public void removeOnTransportEventListener(int associationId, IOnTransportEventListener listener) { removeOnTransportEventListener_enforcePermission(); mTransportManager.removeListener(associationId, listener); } /** * @deprecated use {@link #disassociate(int)} instead */ Loading services/companion/java/com/android/server/companion/association/DisassociationProcessor.java +2 −1 Original line number Diff line number Diff line Loading @@ -137,7 +137,8 @@ public class DisassociationProcessor { return; } // Detach transport if exists // Detach transports and listeners if exists mTransportManager.removeListeners(id); mTransportManager.detachSystemDataTransport(id); // Association cleanup. Loading Loading
core/java/android/companion/CompanionDeviceManager.java +89 −0 Original line number Diff line number Diff line Loading @@ -419,6 +419,11 @@ public final class CompanionDeviceManager { private final ArrayList<OnTransportsChangedListenerProxy> mTransportsChangedListeners = new ArrayList<>(); /** Association ID -> List of listeners */ @GuardedBy("mTransportEventListeners") private final SparseArray<List<OnTransportEventListenerProxy>> mTransportEventListeners = new SparseArray<>(); @GuardedBy("mMessageReceivedListeners") private final SparseArray<Set<OnMessageReceivedListenerProxy>> mMessageReceivedListeners = new SparseArray<>(); Loading Loading @@ -1189,6 +1194,73 @@ public final class CompanionDeviceManager { } } /** * Adds a listener for an event reported by attached transport. * * @param executor The executor which will be used to invoke the listener. * @param listener Called when a transport reports an event. * @see com.android.server.companion.transport.Transport * @hide */ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void addOnTransportEventListener( @NonNull @CallbackExecutor Executor executor, int associationId, @NonNull Consumer<Integer> listener) { if (mService == null) { Log.w(TAG, "CompanionDeviceManager service is not available."); return; } synchronized (mTransportsChangedListeners) { final OnTransportEventListenerProxy proxy = new OnTransportEventListenerProxy( executor, listener); try { mService.addOnTransportEventListener(associationId, proxy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } if (!mTransportEventListeners.contains(associationId)) { mTransportEventListeners.put(associationId, new ArrayList<>()); } mTransportEventListeners.get(associationId).add(proxy); } } /** * Removes the registered listener for transport events. * @see com.android.server.companion.transport.Transport * @hide */ @RequiresPermission(android.Manifest.permission.USE_COMPANION_TRANSPORTS) public void removeOnTransportEventListener(int associationId, @NonNull Consumer<Integer> listener) { if (mService == null) { Log.w(TAG, "CompanionDeviceManager service is not available."); return; } synchronized (mTransportEventListeners) { if (!mTransportEventListeners.contains(associationId)) { throw new IllegalArgumentException("Association id=[" + associationId + "] doesn't have any registered event listener."); } final Iterator<OnTransportEventListenerProxy> iterator = mTransportEventListeners.get(associationId).iterator(); while (iterator.hasNext()) { final OnTransportEventListenerProxy proxy = iterator.next(); if (proxy.mListener == listener) { try { mService.removeOnTransportEventListener(associationId, proxy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } iterator.remove(); } } } } /** * Checks whether the bluetooth device represented by the mac address was recently associated * with the companion app. This allows these devices to skip the Bluetooth pairing dialog if Loading Loading @@ -2003,6 +2075,23 @@ public final class CompanionDeviceManager { } } private static class OnTransportEventListenerProxy extends IOnTransportEventListener.Stub { private final Executor mExecutor; private final Consumer<Integer> mListener; private OnTransportEventListenerProxy(Executor executor, Consumer<Integer> listener) { mExecutor = executor; mListener = listener; } @Override public void onTransportEvent(int eventCode) { mExecutor.execute(() -> mListener.accept(eventCode)); } } private static class SystemDataTransferCallbackProxy extends ISystemDataTransferCallback.Stub { private final Executor mExecutor; private final OutcomeReceiver<Void, CompanionException> mCallback; Loading
core/java/android/companion/ICompanionDeviceManager.aidl +7 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.app.PendingIntent; import android.companion.IAssociationRequestCallback; import android.companion.IOnAssociationsChangedListener; import android.companion.IOnMessageReceivedListener; import android.companion.IOnTransportEventListener; import android.companion.IOnTransportsChangedListener; import android.companion.ISystemDataTransferCallback; import android.companion.AssociationInfo; Loading Loading @@ -98,6 +99,12 @@ interface ICompanionDeviceManager { @EnforcePermission("USE_COMPANION_TRANSPORTS") void removeOnMessageReceivedListener(int messageType, IOnMessageReceivedListener listener); @EnforcePermission("USE_COMPANION_TRANSPORTS") void addOnTransportEventListener(int associationId, IOnTransportEventListener listener); @EnforcePermission("USE_COMPANION_TRANSPORTS") void removeOnTransportEventListener(int associationId, IOnTransportEventListener listener); @EnforcePermission("REQUEST_COMPANION_SELF_MANAGED") void notifySelfManagedDeviceAppeared(int associationId); Loading
core/java/android/companion/IOnTransportEventListener.aidl 0 → 100644 +22 −0 Original line number Diff line number Diff line /* * Copyright (C) 2025 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 per missions and * limitations under the License. */ package android.companion; /** @hide */ interface IOnTransportEventListener { oneway void onTransportEvent(int eventCode); } No newline at end of file
services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java +19 −0 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.companion.IAssociationRequestCallback; import android.companion.ICompanionDeviceManager; import android.companion.IOnAssociationsChangedListener; import android.companion.IOnMessageReceivedListener; import android.companion.IOnTransportEventListener; import android.companion.IOnTransportsChangedListener; import android.companion.ISystemDataTransferCallback; import android.companion.ObservingDevicePresenceRequest; Loading Loading @@ -418,6 +419,24 @@ public class CompanionDeviceManagerService extends SystemService { mTransportManager.removeListener(messageType, listener); } @Override @EnforcePermission(USE_COMPANION_TRANSPORTS) public void addOnTransportEventListener(int associationId, IOnTransportEventListener listener) { addOnTransportEventListener_enforcePermission(); mTransportManager.addListener(associationId, listener); } @Override @EnforcePermission(USE_COMPANION_TRANSPORTS) public void removeOnTransportEventListener(int associationId, IOnTransportEventListener listener) { removeOnTransportEventListener_enforcePermission(); mTransportManager.removeListener(associationId, listener); } /** * @deprecated use {@link #disassociate(int)} instead */ Loading
services/companion/java/com/android/server/companion/association/DisassociationProcessor.java +2 −1 Original line number Diff line number Diff line Loading @@ -137,7 +137,8 @@ public class DisassociationProcessor { return; } // Detach transport if exists // Detach transports and listeners if exists mTransportManager.removeListeners(id); mTransportManager.detachSystemDataTransport(id); // Association cleanup. Loading