summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Evan Chen <evanxinchen@google.com> 2024-07-24 22:10:43 +0000
committer Evan Chen <evanxinchen@google.com> 2024-08-06 05:34:51 +0000
commitabcecc2795f056d2ac06dfa427a08acd1e30e177 (patch)
treef3e0e87064e6134e234eedcb9809769649cbd423
parent47d3c329a5a70b0c6d1367f2e854e5829fc81120 (diff)
[W] Return CharSquence and int for onFailure callback
Test: CTS Bug: 349401090 Flag: android.companion.association_failure_code Change-Id: Id08c1ba316873d5f62bede47a7ca31e687ba250c
-rw-r--r--core/api/current.txt3
-rw-r--r--core/java/android/companion/CompanionDeviceManager.java48
-rw-r--r--core/java/android/companion/IAssociationRequestCallback.aidl2
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionAssociationActivity.java35
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionVendorHelperDialogFragment.java4
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/Utils.java23
-rw-r--r--services/companion/java/com/android/server/companion/association/AssociationRequestsProcessor.java17
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) {
}
}