Merge "Add an API for cancelling current CDM activity"
This commit is contained in:
@@ -9015,6 +9015,7 @@ package android.companion {
|
||||
public final class CompanionDeviceManager {
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER, android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull android.companion.CompanionDeviceManager.Callback, @Nullable android.os.Handler);
|
||||
method @RequiresPermission(anyOf={android.Manifest.permission.REQUEST_COMPANION_PROFILE_WATCH, android.Manifest.permission.REQUEST_COMPANION_PROFILE_COMPUTER, android.Manifest.permission.REQUEST_COMPANION_PROFILE_APP_STREAMING, android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION}, conditional=true) public void associate(@NonNull android.companion.AssociationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.companion.CompanionDeviceManager.Callback);
|
||||
method @Nullable public android.content.IntentSender buildAssociationCancellationIntent();
|
||||
method @Nullable public android.content.IntentSender buildPermissionTransferUserConsentIntent(int) throws android.companion.DeviceNotAssociatedException;
|
||||
method @Deprecated public void disassociate(@NonNull String);
|
||||
method public void disassociate(int);
|
||||
|
||||
@@ -402,6 +402,34 @@ public final class CompanionDeviceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel the current association activity.
|
||||
*
|
||||
* <p>The app should launch the returned {@code intentSender} by calling
|
||||
* {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int)} to
|
||||
* cancel the current association activity</p>
|
||||
*
|
||||
* <p>Calling this API requires a uses-feature
|
||||
* {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
|
||||
*
|
||||
* @return An {@link IntentSender} that the app should use to launch in order to cancel the
|
||||
* current association activity
|
||||
*/
|
||||
@UserHandleAware
|
||||
@Nullable
|
||||
public IntentSender buildAssociationCancellationIntent() {
|
||||
if (!checkFeaturePresent()) return null;
|
||||
|
||||
try {
|
||||
PendingIntent pendingIntent = mService.buildAssociationCancellationIntent(
|
||||
mContext.getOpPackageName(), mContext.getUserId());
|
||||
return pendingIntent.getIntentSender();
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Calling this API requires a uses-feature
|
||||
* {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
|
||||
|
||||
@@ -82,4 +82,6 @@ interface ICompanionDeviceManager {
|
||||
void detachSystemDataTransport(String packageName, int userId, int associationId);
|
||||
|
||||
boolean isCompanionApplicationBound(String packageName, int userId);
|
||||
|
||||
PendingIntent buildAssociationCancellationIntent(in String callingPackage, int userId);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import static java.util.Objects.requireNonNull;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.companion.AssociationInfo;
|
||||
import android.companion.AssociationRequest;
|
||||
import android.companion.CompanionDeviceManager;
|
||||
@@ -81,6 +82,7 @@ import java.util.List;
|
||||
* A CompanionDevice activity response for showing the available
|
||||
* nearby devices to be associated with.
|
||||
*/
|
||||
@SuppressLint("LongLogTag")
|
||||
public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
CompanionVendorHelperDialogFragment.CompanionVendorHelperDialogListener {
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -94,6 +96,7 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
private static final String EXTRA_APPLICATION_CALLBACK = "application_callback";
|
||||
private static final String EXTRA_ASSOCIATION_REQUEST = "association_request";
|
||||
private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
|
||||
private static final String EXTRA_FORCE_CANCEL_CONFIRMATION = "cancel_confirmation";
|
||||
|
||||
private static final String FRAGMENT_DIALOG_TAG = "fragment_dialog";
|
||||
|
||||
@@ -162,6 +165,12 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
if (DEBUG) Log.d(TAG, "onCreate()");
|
||||
boolean forceCancelDialog = getIntent().getBooleanExtra("cancel_confirmation", false);
|
||||
// Must handle the force cancel request in onNewIntent.
|
||||
if (forceCancelDialog) {
|
||||
Log.i(TAG, "The confirmation does not exist, skipping the cancel request");
|
||||
finish();
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
|
||||
@@ -195,10 +204,23 @@ public class CompanionDeviceActivity extends FragmentActivity implements
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
// Force cancels the CDM dialog if this activity receives another intent with
|
||||
// EXTRA_FORCE_CANCEL_CONFIRMATION.
|
||||
boolean forCancelDialog = intent.getBooleanExtra(EXTRA_FORCE_CANCEL_CONFIRMATION, false);
|
||||
|
||||
if (forCancelDialog) {
|
||||
|
||||
Log.i(TAG, "Cancelling the user confirmation");
|
||||
|
||||
cancel(false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle another incoming request (while we are not done with the original - mRequest -
|
||||
// yet).
|
||||
final AssociationRequest request = requireNonNull(
|
||||
intent.getParcelableExtra(EXTRA_ASSOCIATION_REQUEST));
|
||||
|
||||
if (DEBUG) Log.d(TAG, "onNewIntent(), request=" + request);
|
||||
|
||||
// We can only "process" one request at a time.
|
||||
|
||||
@@ -29,6 +29,7 @@ import static java.util.Objects.requireNonNull;
|
||||
import android.annotation.MainThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Service;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
@@ -68,6 +69,7 @@ import java.util.Objects;
|
||||
/**
|
||||
* A CompanionDevice service response for scanning nearby devices
|
||||
*/
|
||||
@SuppressLint("LongLogTag")
|
||||
public class CompanionDeviceDiscoveryService extends Service {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "CDM_CompanionDeviceDiscoveryService";
|
||||
|
||||
@@ -116,6 +116,7 @@ class AssociationRequestsProcessor {
|
||||
private static final String EXTRA_APPLICATION_CALLBACK = "application_callback";
|
||||
private static final String EXTRA_ASSOCIATION_REQUEST = "association_request";
|
||||
private static final String EXTRA_RESULT_RECEIVER = "result_receiver";
|
||||
private static final String EXTRA_FORCE_CANCEL_CONFIRMATION = "cancel_confirmation";
|
||||
|
||||
// AssociationRequestsProcessor -> UI
|
||||
private static final int RESULT_CODE_ASSOCIATION_CREATED = 0;
|
||||
@@ -195,21 +196,7 @@ class AssociationRequestsProcessor {
|
||||
intent.putExtras(extras);
|
||||
|
||||
// 2b.3. Create a PendingIntent.
|
||||
final PendingIntent pendingIntent;
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
// Using uid of the application that will own the association (usually the same
|
||||
// application that sent the request) allows us to have multiple "pending" association
|
||||
// requests at the same time.
|
||||
// If the application already has a pending association request, that PendingIntent
|
||||
// will be cancelled.
|
||||
pendingIntent = PendingIntent.getActivityAsUser(
|
||||
mContext, /*requestCode */ packageUid, intent,
|
||||
FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE,
|
||||
/* options= */ null, UserHandle.CURRENT);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
final PendingIntent pendingIntent = createPendingIntent(packageUid, intent);
|
||||
|
||||
// 2b.4. Send the PendingIntent back to the app.
|
||||
try {
|
||||
@@ -217,6 +204,27 @@ class AssociationRequestsProcessor {
|
||||
} catch (RemoteException ignore) { }
|
||||
}
|
||||
|
||||
/**
|
||||
* Process another AssociationRequest in CompanionDeviceActivity to cancel current dialog.
|
||||
*/
|
||||
PendingIntent buildAssociationCancellationIntent(@NonNull String packageName,
|
||||
@UserIdInt int userId) {
|
||||
requireNonNull(packageName, "Package name MUST NOT be null");
|
||||
|
||||
enforceUsesCompanionDeviceFeature(mContext, userId, packageName);
|
||||
|
||||
final int packageUid = mPackageManager.getPackageUid(packageName, 0, userId);
|
||||
|
||||
final Bundle extras = new Bundle();
|
||||
extras.putBoolean(EXTRA_FORCE_CANCEL_CONFIRMATION, true);
|
||||
|
||||
final Intent intent = new Intent();
|
||||
intent.setComponent(ASSOCIATION_REQUEST_APPROVAL_ACTIVITY);
|
||||
intent.putExtras(extras);
|
||||
|
||||
return createPendingIntent(packageUid, intent);
|
||||
}
|
||||
|
||||
private void processAssociationRequestApproval(@NonNull AssociationRequest request,
|
||||
@NonNull IAssociationRequestCallback callback,
|
||||
@NonNull ResultReceiver resultReceiver, @Nullable MacAddress macAddress) {
|
||||
@@ -286,6 +294,27 @@ class AssociationRequestsProcessor {
|
||||
return !isRoleHolder;
|
||||
}
|
||||
|
||||
private PendingIntent createPendingIntent(int packageUid, Intent intent) {
|
||||
final PendingIntent pendingIntent;
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
|
||||
// Using uid of the application that will own the association (usually the same
|
||||
// application that sent the request) allows us to have multiple "pending" association
|
||||
// requests at the same time.
|
||||
// If the application already has a pending association request, that PendingIntent
|
||||
// will be cancelled except application wants to cancel the request by the system.
|
||||
try {
|
||||
pendingIntent = PendingIntent.getActivityAsUser(
|
||||
mContext, /*requestCode */ packageUid, intent,
|
||||
FLAG_ONE_SHOT | FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE,
|
||||
/* options= */ null, UserHandle.CURRENT);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
return pendingIntent;
|
||||
}
|
||||
|
||||
private final ResultReceiver mOnRequestConfirmationReceiver =
|
||||
new ResultReceiver(Handler.getMain()) {
|
||||
@Override
|
||||
|
||||
@@ -548,6 +548,18 @@ public class CompanionDeviceManagerService extends SystemService {
|
||||
request, packageName, userId, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PendingIntent buildAssociationCancellationIntent(String packageName,
|
||||
int userId) throws RemoteException {
|
||||
Slog.i(TAG, "buildAssociationCancellationIntent() "
|
||||
+ "package=u" + userId + "/" + packageName);
|
||||
enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName,
|
||||
"build association cancellation intent");
|
||||
|
||||
return mAssociationRequestsProcessor.buildAssociationCancellationIntent(
|
||||
packageName, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AssociationInfo> getAssociations(String packageName, int userId) {
|
||||
enforceCallerCanManageAssociationsForPackage(getContext(), userId, packageName,
|
||||
|
||||
Reference in New Issue
Block a user