diff options
7 files changed, 88 insertions, 44 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index 889b62751c7b..209890acc2b1 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -9820,6 +9820,7 @@ package android.companion { field public static final int RESULT_DISCOVERY_TIMEOUT = 2; // 0x2 field public static final int RESULT_INTERNAL_ERROR = 3; // 0x3 field public static final int RESULT_OK = -1; // 0xffffffff + field @FlaggedApi("android.companion.association_failure_code") public static final int RESULT_SECURITY_ERROR = 4; // 0x4 field public static final int RESULT_USER_REJECTED = 1; // 0x1 } @@ -9829,7 +9830,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); + method @FlaggedApi("android.companion.association_failure_code") public void onFailure(int, @Nullable CharSequence); } public abstract class CompanionDeviceService extends android.app.Service { diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index 34cfa584b683..e4087ba5d5ce 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -21,7 +21,6 @@ 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; @@ -58,7 +57,6 @@ 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; @@ -78,7 +76,6 @@ 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; @@ -146,12 +143,19 @@ public final class CompanionDeviceManager { /** * 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; /** + * The result code to propagate back to the user activity and + * {@link Callback#onFailure(int, CharSequence)}, indicates app is not allow to create the + * association due to the security issue. + * E.g. There are missing necessary permissions when creating association. + */ + @FlaggedApi(Flags.FLAG_ASSOCIATION_FAILURE_CODE) + public static final int RESULT_SECURITY_ERROR = 4; + + /** * Requesting applications will receive the String in {@link Callback#onFailure} if the * association dialog is explicitly declined by the users. E.g. press the Don't allow * button. @@ -374,7 +378,6 @@ 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. * @@ -385,11 +388,15 @@ public final class CompanionDeviceManager { /** * Invoked if the association could not be created. * - * @param resultCode indicate the particular reason why the association - * could not be created. + * Please note that both {@link #onFailure(CharSequence error)} and this + * API will be called if the association could not be created. + * + * @param errorCode indicate the particular error code why the association + * could not be created. + * @param error error message. */ @FlaggedApi(Flags.FLAG_ASSOCIATION_FAILURE_CODE) - public void onFailure(@ResultCode int resultCode) {} + public void onFailure(@ResultCode int errorCode, @Nullable CharSequence error) {} } private final ICompanionDeviceManager mService; @@ -1819,12 +1826,12 @@ public final class CompanionDeviceManager { } @Override - public void onFailure(@ResultCode int resultCode) { + public void onFailure(@ResultCode int errorCode, @Nullable CharSequence error) { if (Flags.associationFailureCode()) { - execute(mCallback::onFailure, resultCode); + execute(mCallback::onFailure, errorCode, error); } - execute(mCallback::onFailure, RESULT_CODE_TO_REASON.get(resultCode)); + execute(mCallback::onFailure, error); } private <T> void execute(Consumer<T> callback, T arg) { @@ -1834,6 +1841,12 @@ public final class CompanionDeviceManager { mHandler.post(() -> callback.accept(arg)); } } + + private <T, U> void execute(BiConsumer<T, U> callback, T arg1, U arg2) { + if (mExecutor != null) { + mExecutor.execute(() -> callback.accept(arg1, arg2)); + } + } } private static class OnAssociationsChangedListenerProxy @@ -2008,15 +2021,4 @@ 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); - } } diff --git a/core/java/android/companion/IAssociationRequestCallback.aidl b/core/java/android/companion/IAssociationRequestCallback.aidl index b1be30a1288c..a6f86a5e62a5 100644 --- a/core/java/android/companion/IAssociationRequestCallback.aidl +++ b/core/java/android/companion/IAssociationRequestCallback.aidl @@ -25,5 +25,5 @@ interface IAssociationRequestCallback { oneway void onAssociationCreated(in AssociationInfo associationInfo); - oneway void onFailure(in int resultCode); + oneway void onFailure(in int errorCode, in CharSequence error); }
\ No newline at end of file diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java index e00533422072..23dc4ed9efa9 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java @@ -19,6 +19,7 @@ package com.android.companiondevicemanager; 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_SECURITY_ERROR; import static android.companion.CompanionDeviceManager.RESULT_USER_REJECTED; import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS; @@ -33,6 +34,7 @@ import static com.android.companiondevicemanager.CompanionDeviceResources.PROFIL import static com.android.companiondevicemanager.CompanionDeviceResources.PROFILE_TITLES; import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_PROFILES; import static com.android.companiondevicemanager.CompanionDeviceResources.SUPPORTED_SELF_MANAGED_PROFILES; +import static com.android.companiondevicemanager.Utils.RESULT_CODE_TO_REASON; import static com.android.companiondevicemanager.Utils.getApplicationLabel; import static com.android.companiondevicemanager.Utils.getHtmlFromResources; import static com.android.companiondevicemanager.Utils.getIcon; @@ -51,6 +53,7 @@ import android.companion.AssociatedDevice; import android.companion.AssociationInfo; import android.companion.AssociationRequest; import android.companion.CompanionDeviceManager; +import android.companion.Flags; import android.companion.IAssociationRequestCallback; import android.content.Intent; import android.content.pm.PackageManager; @@ -231,7 +234,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(RESULT_CANCELED); + cancel(RESULT_CANCELED, null); return; } @@ -243,10 +246,15 @@ public class CompanionAssociationActivity extends FragmentActivity implements if (appCallback == null) { return; } - Slog.e(TAG, "More than one AssociationRequests are processing."); try { - appCallback.onFailure(RESULT_INTERNAL_ERROR); + if (Flags.associationFailureCode()) { + appCallback.onFailure( + RESULT_SECURITY_ERROR, "More than one AssociationRequests are processing."); + } else { + appCallback.onFailure( + RESULT_INTERNAL_ERROR, "More than one AssociationRequests are processing."); + } } catch (RemoteException ignore) { } } @@ -257,7 +265,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements // TODO: handle config changes without cancelling. if (!isDone()) { - cancel(RESULT_CANCELED); // will finish() + cancel(RESULT_CANCELED, null); // will finish() } } @@ -331,7 +339,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements && CompanionDeviceDiscoveryService.getScanResult().getValue().isEmpty()) { synchronized (LOCK) { if (sDiscoveryStarted) { - cancel(RESULT_DISCOVERY_TIMEOUT); + cancel(RESULT_DISCOVERY_TIMEOUT, null); } } } @@ -371,7 +379,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements mCdmServiceReceiver.send(RESULT_CODE_ASSOCIATION_APPROVED, data); } - private void cancel(int failureCode) { + private void cancel(int errorCode, @Nullable CharSequence error) { if (isDone()) { Slog.w(TAG, "Already done: " + (mApproved ? "Approved" : "Cancelled")); return; @@ -385,13 +393,14 @@ public class CompanionAssociationActivity extends FragmentActivity implements // First send callback to the app directly... try { - Slog.i(TAG, "Sending onFailure to app due to failureCode=" + failureCode); - mAppCallback.onFailure(failureCode); + CharSequence errorMessage = error != null + ? error : RESULT_CODE_TO_REASON.get(errorCode); + mAppCallback.onFailure(errorCode, errorMessage); } catch (RemoteException ignore) { } // ... then set result and finish ("sending" onActivityResult()). - setResultAndFinish(null, failureCode); + setResultAndFinish(null, errorCode); } private void setResultAndFinish(@Nullable AssociationInfo association, int resultCode) { @@ -436,7 +445,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements } } catch (PackageManager.NameNotFoundException e) { Slog.e(TAG, "Package u" + userId + "/" + packageName + " not found."); - cancel(RESULT_INTERNAL_ERROR); + cancel(RESULT_INTERNAL_ERROR, e.getMessage()); return; } @@ -624,7 +633,7 @@ public class CompanionAssociationActivity extends FragmentActivity implements // Disable the button, to prevent more clicks. v.setEnabled(false); - cancel(RESULT_USER_REJECTED); + cancel(RESULT_USER_REJECTED, null); } private void onShowHelperDialog(View view) { @@ -749,8 +758,8 @@ public class CompanionAssociationActivity extends FragmentActivity implements }; @Override - public void onShowHelperDialogFailed() { - cancel(RESULT_INTERNAL_ERROR); + public void onShowHelperDialogFailed(CharSequence errorMessage) { + cancel(RESULT_INTERNAL_ERROR, errorMessage); } @Override diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java index fe0e021b363c..5797bcabba08 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java @@ -58,7 +58,7 @@ public class CompanionVendorHelperDialogFragment extends DialogFragment { private Button mButton; interface CompanionVendorHelperDialogListener { - void onShowHelperDialogFailed(); + void onShowHelperDialogFailed(CharSequence error); void onHelperDialogDismissed(); } @@ -114,7 +114,7 @@ public class CompanionVendorHelperDialogFragment extends DialogFragment { appLabel = getApplicationLabel(getContext(), packageName, userId); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "Package u" + userId + "/" + packageName + " not found."); - mListener.onShowHelperDialogFailed(); + mListener.onShowHelperDialogFailed(e.getMessage()); return; } diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java index 8c14f8037e64..2f971321d905 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java @@ -16,6 +16,15 @@ 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_USER_REJECTED; +import static android.companion.CompanionDeviceManager.RESULT_CANCELED; +import static android.companion.CompanionDeviceManager.RESULT_DISCOVERY_TIMEOUT; +import static android.companion.CompanionDeviceManager.RESULT_USER_REJECTED; + +import static java.util.Collections.unmodifiableMap; + import android.annotation.NonNull; import android.annotation.StringRes; import android.content.Context; @@ -31,6 +40,9 @@ import android.os.Parcel; import android.os.ResultReceiver; import android.text.Html; import android.text.Spanned; +import android.util.ArrayMap; + +import java.util.Map; /** * Utilities. @@ -40,6 +52,17 @@ class Utils { "android.companion.vendor_icon"; private static final String COMPANION_DEVICE_ACTIVITY_VENDOR_NAME = "android.companion.vendor_name"; + // This map solely the common error messages that occur during the Association + // creation process. + 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); + + RESULT_CODE_TO_REASON = unmodifiableMap(map); + } /** * Convert an instance of a "locally-defined" ResultReceiver to an instance of diff --git a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java index b3a2da40ff4d..d56f17bf5edd 100644 --- a/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java +++ b/services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java @@ -20,6 +20,7 @@ import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.app.PendingIntent.FLAG_ONE_SHOT; import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR; +import static android.companion.CompanionDeviceManager.RESULT_SECURITY_ERROR; import static android.content.ComponentName.createRelative; import static android.content.pm.PackageManager.FEATURE_WATCH; @@ -40,6 +41,7 @@ import android.app.PendingIntent; import android.companion.AssociatedDevice; import android.companion.AssociationInfo; import android.companion.AssociationRequest; +import android.companion.Flags; import android.companion.IAssociationRequestCallback; import android.content.ComponentName; import android.content.Context; @@ -182,7 +184,11 @@ public class AssociationRequestsProcessor { String errorMessage = "3p apps are not allowed to create associations on watch."; Slog.e(TAG, errorMessage); try { - callback.onFailure(RESULT_INTERNAL_ERROR); + if (Flags.associationFailureCode()) { + callback.onFailure(RESULT_SECURITY_ERROR, errorMessage); + } else { + callback.onFailure(RESULT_INTERNAL_ERROR, errorMessage); + } } catch (RemoteException e) { // ignored } @@ -251,9 +257,12 @@ public class AssociationRequestsProcessor { } catch (SecurityException e) { // Since, at this point the caller is our own UI, we need to catch the exception on // forward it back to the application via the callback. - Slog.e(TAG, e.getMessage()); try { - callback.onFailure(RESULT_INTERNAL_ERROR); + if (Flags.associationFailureCode()) { + callback.onFailure(RESULT_SECURITY_ERROR, e.getMessage()); + } else { + callback.onFailure(RESULT_INTERNAL_ERROR, e.getMessage()); + } } catch (RemoteException ignore) { } return; @@ -378,7 +387,7 @@ public class AssociationRequestsProcessor { // Send the association back via the app's callback if (callback != null) { try { - callback.onFailure(RESULT_INTERNAL_ERROR); + callback.onFailure(RESULT_INTERNAL_ERROR, "Association doesn't exist."); } catch (RemoteException ignore) { } } |