Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 11e97698 authored by Evan Chen's avatar Evan Chen
Browse files

[W] Introduce new onFailure callback with resultCode

Test: CTS
Bug: 341993358
Flag: android.companion.association_failure_code
Change-Id: I5f549c5663b4887b4e2dd694c5ffb84136764be7
parent a96c939d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9824,6 +9824,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 {
+37 −6
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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;

@@ -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;
@@ -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) {
@@ -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);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -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
+9 −1
Original line number Diff line number Diff line
@@ -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"
}
+19 −36
Original line number Diff line number Diff line
@@ -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;
@@ -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;
        }

@@ -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) {
        }
    }
@@ -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()
        }
    }

@@ -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);
                }
            }
        }
@@ -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;
@@ -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) {
@@ -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;
        }

@@ -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) {
@@ -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