Loading core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -9826,6 +9826,7 @@ package android.companion { method public void onAssociationPending(@NonNull android.content.IntentSender); method @Deprecated public void onDeviceFound(@NonNull android.content.IntentSender); method public abstract void onFailure(@Nullable CharSequence); method @FlaggedApi("android.companion.association_failure_code") public void onFailure(int); } public abstract class CompanionDeviceService extends android.app.Service { core/java/android/companion/CompanionDeviceManager.java +37 −6 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_P import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER; import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH; import static java.util.Collections.unmodifiableMap; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.IntDef; Loading Loading @@ -56,6 +58,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.util.ArrayMap; import android.util.ExceptionUtils; import android.util.Log; import android.util.SparseArray; Loading @@ -75,6 +78,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.BiConsumer; Loading Loading @@ -119,29 +123,31 @@ public final class CompanionDeviceManager { * is created successfully. */ public static final int RESULT_OK = -1; //TODO(b/331459560) Need to update the java doc after API cut for W. /** * The result code to propagate back to the user activity, indicates if the association dialog * is implicitly cancelled. * E.g. phone is locked, switch to another app or press outside the dialog. */ public static final int RESULT_CANCELED = 0; //TODO(b/331459560) Need to update the java doc after API cut for W. /** * The result code to propagate back to the user activity, indicates the association dialog * is explicitly declined by the users. */ public static final int RESULT_USER_REJECTED = 1; //TODO(b/331459560) Need to update the java doc after API cut for W. /** * The result code to propagate back to the user activity, indicates the association * dialog is dismissed if there's no device found after 20 seconds. */ public static final int RESULT_DISCOVERY_TIMEOUT = 2; //TODO(b/331459560) Need to update the java doc after API cut for W. /** * The result code to propagate back to the user activity, indicates the internal error * in CompanionDeviceManager. * E.g. Missing necessary permissions or duplicate {@link AssociationRequest}s when create the * {@link AssociationInfo}. */ public static final int RESULT_INTERNAL_ERROR = 3; Loading Loading @@ -368,12 +374,22 @@ public final class CompanionDeviceManager { */ public void onAssociationCreated(@NonNull AssociationInfo associationInfo) {} //TODO(b/331459560): Add deprecated and remove abstract after API cut for W. /** * Invoked if the association could not be created. * * @param error error message. */ public abstract void onFailure(@Nullable CharSequence error); /** * Invoked if the association could not be created. * * @param resultCode indicate the particular reason why the association * could not be created. */ @FlaggedApi(Flags.FLAG_ASSOCIATION_FAILURE_CODE) public void onFailure(@ResultCode int resultCode) {} } private final ICompanionDeviceManager mService; Loading Loading @@ -1803,8 +1819,12 @@ public final class CompanionDeviceManager { } @Override public void onFailure(CharSequence error) throws RemoteException { execute(mCallback::onFailure, error); public void onFailure(@ResultCode int resultCode) { if (Flags.associationFailureCode()) { execute(mCallback::onFailure, resultCode); } execute(mCallback::onFailure, RESULT_CODE_TO_REASON.get(resultCode)); } private <T> void execute(Consumer<T> callback, T arg) { Loading Loading @@ -1988,4 +2008,15 @@ public final class CompanionDeviceManager { } } } private static final Map<Integer, String> RESULT_CODE_TO_REASON; static { final Map<Integer, String> map = new ArrayMap<>(); map.put(RESULT_CANCELED, REASON_CANCELED); map.put(RESULT_USER_REJECTED, REASON_USER_REJECTED); map.put(RESULT_DISCOVERY_TIMEOUT, REASON_DISCOVERY_TIMEOUT); map.put(RESULT_INTERNAL_ERROR, REASON_INTERNAL_ERROR); RESULT_CODE_TO_REASON = unmodifiableMap(map); } } core/java/android/companion/IAssociationRequestCallback.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -25,5 +25,5 @@ interface IAssociationRequestCallback { oneway void onAssociationCreated(in AssociationInfo associationInfo); oneway void onFailure(in CharSequence error); oneway void onFailure(in int resultCode); } No newline at end of file core/java/android/companion/flags.aconfig +9 −1 Original line number Diff line number Diff line Loading @@ -54,3 +54,11 @@ flag { description: "Unpair with an associated bluetooth device" bug: "322237619" } flag { name: "association_failure_code" is_exported: true namespace: "companion" description: "Enable association failure code API" bug: "331459560" } packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java +19 −36 Original line number Diff line number Diff line Loading @@ -16,10 +16,7 @@ package com.android.companiondevicemanager; import static android.companion.CompanionDeviceManager.REASON_CANCELED; import static android.companion.CompanionDeviceManager.REASON_DISCOVERY_TIMEOUT; import static android.companion.CompanionDeviceManager.REASON_INTERNAL_ERROR; import static android.companion.CompanionDeviceManager.REASON_USER_REJECTED; import static android.companion.CompanionDeviceManager.RESULT_CANCELED; import static android.companion.CompanionDeviceManager.RESULT_DISCOVERY_TIMEOUT; import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR; import static android.companion.CompanionDeviceManager.RESULT_USER_REJECTED; Loading Loading @@ -234,8 +231,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements boolean forCancelDialog = intent.getBooleanExtra(EXTRA_FORCE_CANCEL_CONFIRMATION, false); if (forCancelDialog) { Slog.i(TAG, "Cancelling the user confirmation"); cancel(/* discoveryTimeOut */ false, /* userRejected */ false, /* internalError */ false); cancel(RESULT_CANCELED); return; } Loading @@ -243,8 +239,14 @@ public class CompanionAssociationActivity extends FragmentActivity implements // yet). We can only "process" one request at a time. final IAssociationRequestCallback appCallback = IAssociationRequestCallback.Stub .asInterface(intent.getExtras().getBinder(EXTRA_APPLICATION_CALLBACK)); if (appCallback == null) { return; } Slog.e(TAG, "More than one AssociationRequests are processing."); try { requireNonNull(appCallback).onFailure("Busy."); appCallback.onFailure(RESULT_INTERNAL_ERROR); } catch (RemoteException ignore) { } } Loading @@ -255,8 +257,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements // TODO: handle config changes without cancelling. if (!isDone()) { cancel(/* discoveryTimeOut */ false, /* userRejected */ false, /* internalError */ false); // will finish() cancel(RESULT_CANCELED); // will finish() } } Loading Loading @@ -330,8 +331,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements && CompanionDeviceDiscoveryService.getScanResult().getValue().isEmpty()) { synchronized (LOCK) { if (sDiscoveryStarted) { cancel(/* discoveryTimeOut */ true, /* userRejected */ false, /* internalError */ false); cancel(RESULT_DISCOVERY_TIMEOUT); } } } Loading Loading @@ -371,7 +371,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data); } private void cancel(boolean discoveryTimeout, boolean userRejected, boolean internalError) { private void cancel(int failureCode) { if (isDone()) { Slog.w(TAG, "Already done: " + (mApproved ? "Approved" : "Cancelled")); return; Loading @@ -379,35 +379,19 @@ public class CompanionAssociationActivity extends FragmentActivity implements mCancelled = true; // Stop discovery service if it was used. if (!mRequest.isSelfManaged() || discoveryTimeout) { if (!mRequest.isSelfManaged()) { CompanionDeviceDiscoveryService.stop(this); } final String cancelReason; final int resultCode; if (userRejected) { cancelReason = REASON_USER_REJECTED; resultCode = RESULT_USER_REJECTED; } else if (discoveryTimeout) { cancelReason = REASON_DISCOVERY_TIMEOUT; resultCode = RESULT_DISCOVERY_TIMEOUT; } else if (internalError) { cancelReason = REASON_INTERNAL_ERROR; resultCode = RESULT_INTERNAL_ERROR; } else { cancelReason = REASON_CANCELED; resultCode = CompanionDeviceManager.RESULT_CANCELED; } // First send callback to the app directly... try { Slog.i(TAG, "Sending onFailure to app due to reason=" + cancelReason); mAppCallback.onFailure(cancelReason); Slog.i(TAG, "Sending onFailure to app due to failureCode=" + failureCode); mAppCallback.onFailure(failureCode); } catch (RemoteException ignore) { } // ... then set result and finish ("sending" onActivityResult()). setResultAndFinish(null, resultCode); setResultAndFinish(null, failureCode); } private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) { Loading Loading @@ -452,8 +436,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements } } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Package u" + userId + "/" + packageName + " not found."); cancel(/* discoveryTimeout */ false, /* userRejected */ false, /* internalError */ true); cancel(RESULT_INTERNAL_ERROR); return; } Loading Loading @@ -637,7 +620,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements // Disable the button, to prevent more clicks. v.setEnabled(false); cancel(/* discoveryTimeout */ false, /* userRejected */ true, /* internalError */ false); cancel(RESULT_USER_REJECTED); } private void onShowHelperDialog(View view) { Loading Loading @@ -763,7 +746,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements @Override public void onShowHelperDialogFailed() { cancel(/* discoveryTimeout */ false, /* userRejected */ false, /* internalError */ true); cancel(RESULT_INTERNAL_ERROR); } @Override Loading Loading
core/api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -9826,6 +9826,7 @@ package android.companion { method public void onAssociationPending(@NonNull android.content.IntentSender); method @Deprecated public void onDeviceFound(@NonNull android.content.IntentSender); method public abstract void onFailure(@Nullable CharSequence); method @FlaggedApi("android.companion.association_failure_code") public void onFailure(int); } public abstract class CompanionDeviceService extends android.app.Service {
core/java/android/companion/CompanionDeviceManager.java +37 −6 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_P import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER; import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH; import static java.util.Collections.unmodifiableMap; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; import android.annotation.IntDef; Loading Loading @@ -56,6 +58,7 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.UserHandle; import android.service.notification.NotificationListenerService; import android.util.ArrayMap; import android.util.ExceptionUtils; import android.util.Log; import android.util.SparseArray; Loading @@ -75,6 +78,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.BiConsumer; Loading Loading @@ -119,29 +123,31 @@ public final class CompanionDeviceManager { * is created successfully. */ public static final int RESULT_OK = -1; //TODO(b/331459560) Need to update the java doc after API cut for W. /** * The result code to propagate back to the user activity, indicates if the association dialog * is implicitly cancelled. * E.g. phone is locked, switch to another app or press outside the dialog. */ public static final int RESULT_CANCELED = 0; //TODO(b/331459560) Need to update the java doc after API cut for W. /** * The result code to propagate back to the user activity, indicates the association dialog * is explicitly declined by the users. */ public static final int RESULT_USER_REJECTED = 1; //TODO(b/331459560) Need to update the java doc after API cut for W. /** * The result code to propagate back to the user activity, indicates the association * dialog is dismissed if there's no device found after 20 seconds. */ public static final int RESULT_DISCOVERY_TIMEOUT = 2; //TODO(b/331459560) Need to update the java doc after API cut for W. /** * The result code to propagate back to the user activity, indicates the internal error * in CompanionDeviceManager. * E.g. Missing necessary permissions or duplicate {@link AssociationRequest}s when create the * {@link AssociationInfo}. */ public static final int RESULT_INTERNAL_ERROR = 3; Loading Loading @@ -368,12 +374,22 @@ public final class CompanionDeviceManager { */ public void onAssociationCreated(@NonNull AssociationInfo associationInfo) {} //TODO(b/331459560): Add deprecated and remove abstract after API cut for W. /** * Invoked if the association could not be created. * * @param error error message. */ public abstract void onFailure(@Nullable CharSequence error); /** * Invoked if the association could not be created. * * @param resultCode indicate the particular reason why the association * could not be created. */ @FlaggedApi(Flags.FLAG_ASSOCIATION_FAILURE_CODE) public void onFailure(@ResultCode int resultCode) {} } private final ICompanionDeviceManager mService; Loading Loading @@ -1803,8 +1819,12 @@ public final class CompanionDeviceManager { } @Override public void onFailure(CharSequence error) throws RemoteException { execute(mCallback::onFailure, error); public void onFailure(@ResultCode int resultCode) { if (Flags.associationFailureCode()) { execute(mCallback::onFailure, resultCode); } execute(mCallback::onFailure, RESULT_CODE_TO_REASON.get(resultCode)); } private <T> void execute(Consumer<T> callback, T arg) { Loading Loading @@ -1988,4 +2008,15 @@ public final class CompanionDeviceManager { } } } private static final Map<Integer, String> RESULT_CODE_TO_REASON; static { final Map<Integer, String> map = new ArrayMap<>(); map.put(RESULT_CANCELED, REASON_CANCELED); map.put(RESULT_USER_REJECTED, REASON_USER_REJECTED); map.put(RESULT_DISCOVERY_TIMEOUT, REASON_DISCOVERY_TIMEOUT); map.put(RESULT_INTERNAL_ERROR, REASON_INTERNAL_ERROR); RESULT_CODE_TO_REASON = unmodifiableMap(map); } }
core/java/android/companion/IAssociationRequestCallback.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -25,5 +25,5 @@ interface IAssociationRequestCallback { oneway void onAssociationCreated(in AssociationInfo associationInfo); oneway void onFailure(in CharSequence error); oneway void onFailure(in int resultCode); } No newline at end of file
core/java/android/companion/flags.aconfig +9 −1 Original line number Diff line number Diff line Loading @@ -54,3 +54,11 @@ flag { description: "Unpair with an associated bluetooth device" bug: "322237619" } flag { name: "association_failure_code" is_exported: true namespace: "companion" description: "Enable association failure code API" bug: "331459560" }
packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java +19 −36 Original line number Diff line number Diff line Loading @@ -16,10 +16,7 @@ package com.android.companiondevicemanager; import static android.companion.CompanionDeviceManager.REASON_CANCELED; import static android.companion.CompanionDeviceManager.REASON_DISCOVERY_TIMEOUT; import static android.companion.CompanionDeviceManager.REASON_INTERNAL_ERROR; import static android.companion.CompanionDeviceManager.REASON_USER_REJECTED; import static android.companion.CompanionDeviceManager.RESULT_CANCELED; import static android.companion.CompanionDeviceManager.RESULT_DISCOVERY_TIMEOUT; import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR; import static android.companion.CompanionDeviceManager.RESULT_USER_REJECTED; Loading Loading @@ -234,8 +231,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements boolean forCancelDialog = intent.getBooleanExtra(EXTRA_FORCE_CANCEL_CONFIRMATION, false); if (forCancelDialog) { Slog.i(TAG, "Cancelling the user confirmation"); cancel(/* discoveryTimeOut */ false, /* userRejected */ false, /* internalError */ false); cancel(RESULT_CANCELED); return; } Loading @@ -243,8 +239,14 @@ public class CompanionAssociationActivity extends FragmentActivity implements // yet). We can only "process" one request at a time. final IAssociationRequestCallback appCallback = IAssociationRequestCallback.Stub .asInterface(intent.getExtras().getBinder(EXTRA_APPLICATION_CALLBACK)); if (appCallback == null) { return; } Slog.e(TAG, "More than one AssociationRequests are processing."); try { requireNonNull(appCallback).onFailure("Busy."); appCallback.onFailure(RESULT_INTERNAL_ERROR); } catch (RemoteException ignore) { } } Loading @@ -255,8 +257,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements // TODO: handle config changes without cancelling. if (!isDone()) { cancel(/* discoveryTimeOut */ false, /* userRejected */ false, /* internalError */ false); // will finish() cancel(RESULT_CANCELED); // will finish() } } Loading Loading @@ -330,8 +331,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements && CompanionDeviceDiscoveryService.getScanResult().getValue().isEmpty()) { synchronized (LOCK) { if (sDiscoveryStarted) { cancel(/* discoveryTimeOut */ true, /* userRejected */ false, /* internalError */ false); cancel(RESULT_DISCOVERY_TIMEOUT); } } } Loading Loading @@ -371,7 +371,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data); } private void cancel(boolean discoveryTimeout, boolean userRejected, boolean internalError) { private void cancel(int failureCode) { if (isDone()) { Slog.w(TAG, "Already done: " + (mApproved ? "Approved" : "Cancelled")); return; Loading @@ -379,35 +379,19 @@ public class CompanionAssociationActivity extends FragmentActivity implements mCancelled = true; // Stop discovery service if it was used. if (!mRequest.isSelfManaged() || discoveryTimeout) { if (!mRequest.isSelfManaged()) { CompanionDeviceDiscoveryService.stop(this); } final String cancelReason; final int resultCode; if (userRejected) { cancelReason = REASON_USER_REJECTED; resultCode = RESULT_USER_REJECTED; } else if (discoveryTimeout) { cancelReason = REASON_DISCOVERY_TIMEOUT; resultCode = RESULT_DISCOVERY_TIMEOUT; } else if (internalError) { cancelReason = REASON_INTERNAL_ERROR; resultCode = RESULT_INTERNAL_ERROR; } else { cancelReason = REASON_CANCELED; resultCode = CompanionDeviceManager.RESULT_CANCELED; } // First send callback to the app directly... try { Slog.i(TAG, "Sending onFailure to app due to reason=" + cancelReason); mAppCallback.onFailure(cancelReason); Slog.i(TAG, "Sending onFailure to app due to failureCode=" + failureCode); mAppCallback.onFailure(failureCode); } catch (RemoteException ignore) { } // ... then set result and finish ("sending" onActivityResult()). setResultAndFinish(null, resultCode); setResultAndFinish(null, failureCode); } private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) { Loading Loading @@ -452,8 +436,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements } } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Package u" + userId + "/" + packageName + " not found."); cancel(/* discoveryTimeout */ false, /* userRejected */ false, /* internalError */ true); cancel(RESULT_INTERNAL_ERROR); return; } Loading Loading @@ -637,7 +620,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements // Disable the button, to prevent more clicks. v.setEnabled(false); cancel(/* discoveryTimeout */ false, /* userRejected */ true, /* internalError */ false); cancel(RESULT_USER_REJECTED); } private void onShowHelperDialog(View view) { Loading Loading @@ -763,7 +746,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements @Override public void onShowHelperDialogFailed() { cancel(/* discoveryTimeout */ false, /* userRejected */ false, /* internalError */ true); cancel(RESULT_INTERNAL_ERROR); } @Override Loading