Store CDM device profile and apply role when device is connected
Test: manual - ensure role privileges are granted/revoked when device is connected/disconnected Bug: 165951651 Change-Id: Id24a4b3a3510781d9105763b1722f44583a7fd7c
This commit is contained in:
@@ -3689,7 +3689,7 @@ public final class BluetoothAdapter {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class BluetoothConnectionCallback {
|
||||
public abstract static class BluetoothConnectionCallback {
|
||||
/**
|
||||
* Callback triggered when a bluetooth device (classic or BLE) is connected
|
||||
* @param device is the connected bluetooth device
|
||||
|
||||
@@ -37,6 +37,8 @@ public final class Association implements Parcelable {
|
||||
private final @UserIdInt int mUserId;
|
||||
private final @NonNull String mDeviceMacAddress;
|
||||
private final @NonNull String mPackageName;
|
||||
private final @Nullable String mDeviceProfile;
|
||||
private final boolean mKeepProfilePrivilegesWhenDeviceAway;
|
||||
|
||||
/** @hide */
|
||||
public int getUserId() {
|
||||
@@ -45,7 +47,7 @@ public final class Association implements Parcelable {
|
||||
|
||||
|
||||
|
||||
// Code below generated by codegen v1.0.15.
|
||||
// Code below generated by codegen v1.0.21.
|
||||
//
|
||||
// DO NOT MODIFY!
|
||||
// CHECKSTYLE:OFF Generated code
|
||||
@@ -67,7 +69,9 @@ public final class Association implements Parcelable {
|
||||
public Association(
|
||||
@UserIdInt int userId,
|
||||
@NonNull String deviceMacAddress,
|
||||
@NonNull String packageName) {
|
||||
@NonNull String packageName,
|
||||
@Nullable String deviceProfile,
|
||||
boolean keepProfilePrivilegesWhenDeviceAway) {
|
||||
this.mUserId = userId;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
UserIdInt.class, null, mUserId);
|
||||
@@ -77,6 +81,8 @@ public final class Association implements Parcelable {
|
||||
this.mPackageName = packageName;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mPackageName);
|
||||
this.mDeviceProfile = deviceProfile;
|
||||
this.mKeepProfilePrivilegesWhenDeviceAway = keepProfilePrivilegesWhenDeviceAway;
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
@@ -91,6 +97,16 @@ public final class Association implements Parcelable {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public @Nullable String getDeviceProfile() {
|
||||
return mDeviceProfile;
|
||||
}
|
||||
|
||||
@DataClass.Generated.Member
|
||||
public boolean isKeepProfilePrivilegesWhenDeviceAway() {
|
||||
return mKeepProfilePrivilegesWhenDeviceAway;
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataClass.Generated.Member
|
||||
public String toString() {
|
||||
@@ -100,7 +116,9 @@ public final class Association implements Parcelable {
|
||||
return "Association { " +
|
||||
"userId = " + mUserId + ", " +
|
||||
"deviceMacAddress = " + mDeviceMacAddress + ", " +
|
||||
"packageName = " + mPackageName +
|
||||
"packageName = " + mPackageName + ", " +
|
||||
"deviceProfile = " + mDeviceProfile + ", " +
|
||||
"keepProfilePrivilegesWhenDeviceAway = " + mKeepProfilePrivilegesWhenDeviceAway +
|
||||
" }";
|
||||
}
|
||||
|
||||
@@ -119,7 +137,9 @@ public final class Association implements Parcelable {
|
||||
return true
|
||||
&& mUserId == that.mUserId
|
||||
&& Objects.equals(mDeviceMacAddress, that.mDeviceMacAddress)
|
||||
&& Objects.equals(mPackageName, that.mPackageName);
|
||||
&& Objects.equals(mPackageName, that.mPackageName)
|
||||
&& Objects.equals(mDeviceProfile, that.mDeviceProfile)
|
||||
&& mKeepProfilePrivilegesWhenDeviceAway == that.mKeepProfilePrivilegesWhenDeviceAway;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,6 +152,8 @@ public final class Association implements Parcelable {
|
||||
_hash = 31 * _hash + mUserId;
|
||||
_hash = 31 * _hash + Objects.hashCode(mDeviceMacAddress);
|
||||
_hash = 31 * _hash + Objects.hashCode(mPackageName);
|
||||
_hash = 31 * _hash + Objects.hashCode(mDeviceProfile);
|
||||
_hash = 31 * _hash + Boolean.hashCode(mKeepProfilePrivilegesWhenDeviceAway);
|
||||
return _hash;
|
||||
}
|
||||
|
||||
@@ -141,9 +163,14 @@ public final class Association implements Parcelable {
|
||||
// You can override field parcelling by defining methods like:
|
||||
// void parcelFieldName(Parcel dest, int flags) { ... }
|
||||
|
||||
byte flg = 0;
|
||||
if (mKeepProfilePrivilegesWhenDeviceAway) flg |= 0x10;
|
||||
if (mDeviceProfile != null) flg |= 0x8;
|
||||
dest.writeByte(flg);
|
||||
dest.writeInt(mUserId);
|
||||
dest.writeString(mDeviceMacAddress);
|
||||
dest.writeString(mPackageName);
|
||||
if (mDeviceProfile != null) dest.writeString(mDeviceProfile);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -157,9 +184,12 @@ public final class Association implements Parcelable {
|
||||
// You can override field unparcelling by defining methods like:
|
||||
// static FieldType unparcelFieldName(Parcel in) { ... }
|
||||
|
||||
byte flg = in.readByte();
|
||||
boolean keepProfilePrivilegesWhenDeviceAway = (flg & 0x10) != 0;
|
||||
int userId = in.readInt();
|
||||
String deviceMacAddress = in.readString();
|
||||
String packageName = in.readString();
|
||||
String deviceProfile = (flg & 0x8) == 0 ? null : in.readString();
|
||||
|
||||
this.mUserId = userId;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
@@ -170,6 +200,8 @@ public final class Association implements Parcelable {
|
||||
this.mPackageName = packageName;
|
||||
com.android.internal.util.AnnotationValidations.validate(
|
||||
NonNull.class, null, mPackageName);
|
||||
this.mDeviceProfile = deviceProfile;
|
||||
this.mKeepProfilePrivilegesWhenDeviceAway = keepProfilePrivilegesWhenDeviceAway;
|
||||
|
||||
// onConstructed(); // You can define this method to get a callback
|
||||
}
|
||||
@@ -189,10 +221,10 @@ public final class Association implements Parcelable {
|
||||
};
|
||||
|
||||
@DataClass.Generated(
|
||||
time = 1599083149942L,
|
||||
codegenVersion = "1.0.15",
|
||||
time = 1606940835778L,
|
||||
codegenVersion = "1.0.21",
|
||||
sourceFile = "frameworks/base/core/java/android/companion/Association.java",
|
||||
inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\npublic int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
|
||||
inputSignatures = "private final @android.annotation.UserIdInt int mUserId\nprivate final @android.annotation.NonNull java.lang.String mDeviceMacAddress\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mDeviceProfile\nprivate final boolean mKeepProfilePrivilegesWhenDeviceAway\npublic int getUserId()\nclass Association extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true, genToString=true, genHiddenConstructor=true)")
|
||||
@Deprecated
|
||||
private void __metadata() {}
|
||||
|
||||
|
||||
@@ -321,7 +321,8 @@ public class DeviceDiscoveryService extends Service {
|
||||
}
|
||||
|
||||
void onDeviceSelected(String callingPackage, String deviceAddress) {
|
||||
mServiceCallback.complete(new Association(getUserId(), deviceAddress, callingPackage));
|
||||
mServiceCallback.complete(new Association(
|
||||
getUserId(), deviceAddress, callingPackage, mRequest.getDeviceProfile(), false));
|
||||
}
|
||||
|
||||
void onCancel() {
|
||||
|
||||
@@ -31,8 +31,12 @@ import static java.util.concurrent.TimeUnit.MINUTES;
|
||||
import android.annotation.CheckResult;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AppOpsManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.role.RoleManager;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.companion.Association;
|
||||
import android.companion.AssociationRequest;
|
||||
import android.companion.CompanionDeviceManager;
|
||||
@@ -47,6 +51,7 @@ import android.content.pm.FeatureInfo;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageItemInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.net.NetworkPolicyManager;
|
||||
import android.os.Binder;
|
||||
import android.os.Environment;
|
||||
@@ -62,6 +67,7 @@ import android.os.ServiceManager;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.provider.SettingsStringUtil.ComponentNameSet;
|
||||
import android.text.BidiFormatter;
|
||||
@@ -70,6 +76,7 @@ import android.util.AtomicFile;
|
||||
import android.util.ExceptionUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.Xml;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -116,12 +123,16 @@ import java.util.function.Function;
|
||||
//TODO on associate called again after configuration change -> replace old callback with new
|
||||
//TODO avoid leaking calling activity in IFindDeviceCallback (see PrintManager#print for example)
|
||||
/** @hide */
|
||||
@SuppressLint("LongLogTag")
|
||||
public class CompanionDeviceManagerService extends SystemService implements Binder.DeathRecipient {
|
||||
|
||||
private static final ComponentName SERVICE_TO_BIND_TO = ComponentName.createRelative(
|
||||
CompanionDeviceManager.COMPANION_DEVICE_DISCOVERY_PACKAGE_NAME,
|
||||
".DeviceDiscoveryService");
|
||||
|
||||
// 10 min
|
||||
public static final int DEVICE_DISCONNECT_PROFILE_REVOKE_DELAY_MS = 10 * 60 * 1000;
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String LOG_TAG = "CompanionDeviceManagerService";
|
||||
|
||||
@@ -132,6 +143,8 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
private static final String XML_TAG_ASSOCIATION = "association";
|
||||
private static final String XML_ATTR_PACKAGE = "package";
|
||||
private static final String XML_ATTR_DEVICE = "device";
|
||||
private static final String XML_ATTR_PROFILE = "profile";
|
||||
private static final String XML_ATTR_PERSISTENT_PROFILE_GRANTS = "persistent_profile_grants";
|
||||
private static final String XML_FILE_NAME = "companion_device_manager_associations.xml";
|
||||
|
||||
private final CompanionDeviceManagerImpl mImpl;
|
||||
@@ -139,21 +152,29 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
private PowerWhitelistManager mPowerWhitelistManager;
|
||||
private PerUser<ServiceConnector<ICompanionDeviceDiscoveryService>> mServiceConnectors;
|
||||
private IAppOpsService mAppOpsManager;
|
||||
private RoleManager mRoleManager;
|
||||
private BluetoothAdapter mBluetoothAdapter;
|
||||
|
||||
private IFindDeviceCallback mFindDeviceCallback;
|
||||
private AssociationRequest mRequest;
|
||||
private String mCallingPackage;
|
||||
private AndroidFuture<Association> mOngoingDeviceDiscovery;
|
||||
|
||||
private BluetoothDeviceConnectedListener mBluetoothDeviceConnectedListener =
|
||||
new BluetoothDeviceConnectedListener();
|
||||
private List<String> mCurrentlyConnectedDevices = new ArrayList<>();
|
||||
|
||||
private final Object mLock = new Object();
|
||||
|
||||
/** userId -> [association] */
|
||||
@GuardedBy("mLock")
|
||||
private @Nullable Set<Association> mCachedAssociations = null;
|
||||
private @Nullable SparseArray<Set<Association>> mCachedAssociations = new SparseArray<>();
|
||||
|
||||
public CompanionDeviceManagerService(Context context) {
|
||||
super(context);
|
||||
mImpl = new CompanionDeviceManagerImpl();
|
||||
mPowerWhitelistManager = context.getSystemService(PowerWhitelistManager.class);
|
||||
mRoleManager = context.getSystemService(RoleManager.class);
|
||||
mAppOpsManager = IAppOpsService.Stub.asInterface(
|
||||
ServiceManager.getService(Context.APP_OPS_SERVICE));
|
||||
|
||||
@@ -184,9 +205,9 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
@Override
|
||||
public void onPackageModified(String packageName) {
|
||||
int userId = getChangingUserId();
|
||||
if (!ArrayUtils.isEmpty(getAllAssociations(userId, packageName))) {
|
||||
updateSpecialAccessPermissionForAssociatedPackage(packageName, userId);
|
||||
}
|
||||
forEach(getAllAssociations(userId, packageName), association -> {
|
||||
updateSpecialAccessPermissionForAssociatedPackage(association);
|
||||
});
|
||||
}
|
||||
|
||||
}.register(getContext(), FgThread.get().getLooper(), UserHandle.ALL, true);
|
||||
@@ -197,6 +218,18 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
publishBinderService(Context.COMPANION_DEVICE_SERVICE, mImpl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBootPhase(int phase) {
|
||||
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
|
||||
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
if (mBluetoothAdapter != null) {
|
||||
mBluetoothAdapter.registerBluetoothConnectionCallback(
|
||||
getContext().getMainExecutor(),
|
||||
mBluetoothDeviceConnectedListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUserUnlocking(@NonNull TargetUser user) {
|
||||
int userHandle = user.getUserIdentifier();
|
||||
@@ -495,12 +528,14 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
|
||||
fout.append("Companion Device Associations:").append('\n');
|
||||
synchronized (mLock) {
|
||||
forEach(mCachedAssociations, a -> {
|
||||
fout.append(" ")
|
||||
.append("u").append("" + a.getUserId()).append(": ")
|
||||
.append(a.getPackageName()).append(" - ")
|
||||
.append(a.getDeviceMacAddress()).append('\n');
|
||||
});
|
||||
for (UserInfo user : getAllUsers()) {
|
||||
forEach(mCachedAssociations.get(user.id), a -> {
|
||||
fout.append(" ")
|
||||
.append("u").append("" + a.getUserId()).append(": ")
|
||||
.append(a.getPackageName()).append(" - ")
|
||||
.append(a.getDeviceMacAddress()).append('\n');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -513,32 +548,34 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
return Binder.getCallingUid() == Process.SYSTEM_UID;
|
||||
}
|
||||
|
||||
void addAssociation(int userId, String packageName, String deviceAddress) {
|
||||
addAssociation(new Association(userId, deviceAddress, packageName));
|
||||
}
|
||||
|
||||
void addAssociation(Association association) {
|
||||
updateSpecialAccessPermissionForAssociatedPackage(
|
||||
association.getPackageName(), association.getUserId());
|
||||
updateSpecialAccessPermissionForAssociatedPackage(association);
|
||||
recordAssociation(association);
|
||||
}
|
||||
|
||||
void removeAssociation(int userId, String pkg, String deviceMacAddress) {
|
||||
updateAssociations(associations -> CollectionUtils.remove(associations,
|
||||
new Association(userId, deviceMacAddress, pkg)));
|
||||
updateAssociations(associations -> CollectionUtils.filter(associations, association -> {
|
||||
return association.getUserId() != userId
|
||||
|| !Objects.equals(association.getDeviceMacAddress(), deviceMacAddress)
|
||||
|| !Objects.equals(association.getPackageName(), pkg);
|
||||
}));
|
||||
}
|
||||
|
||||
private void updateSpecialAccessPermissionForAssociatedPackage(String packageName, int userId) {
|
||||
PackageInfo packageInfo = getPackageInfo(packageName, userId);
|
||||
private void updateSpecialAccessPermissionForAssociatedPackage(Association association) {
|
||||
PackageInfo packageInfo = getPackageInfo(
|
||||
association.getPackageName(),
|
||||
association.getUserId());
|
||||
if (packageInfo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Binder.withCleanCallingIdentity(obtainRunnable(CompanionDeviceManagerService::
|
||||
updateSpecialAccessPermissionAsSystem, this, packageInfo).recycleOnUse());
|
||||
updateSpecialAccessPermissionAsSystem, this, association, packageInfo)
|
||||
.recycleOnUse());
|
||||
}
|
||||
|
||||
private void updateSpecialAccessPermissionAsSystem(PackageInfo packageInfo) {
|
||||
private void updateSpecialAccessPermissionAsSystem(
|
||||
Association association, PackageInfo packageInfo) {
|
||||
if (containsEither(packageInfo.requestedPermissions,
|
||||
android.Manifest.permission.RUN_IN_BACKGROUND,
|
||||
android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
|
||||
@@ -602,10 +639,6 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
updateAssociations(associations -> CollectionUtils.add(associations, association));
|
||||
}
|
||||
|
||||
private void recordAssociation(String privilegedPackage, String deviceAddress) {
|
||||
recordAssociation(new Association(getCallingUserId(), deviceAddress, privilegedPackage));
|
||||
}
|
||||
|
||||
private void updateAssociations(Function<Set<Association>, Set<Association>> update) {
|
||||
updateAssociations(update, getCallingUserId());
|
||||
}
|
||||
@@ -625,7 +658,7 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
if (DEBUG) {
|
||||
Slog.i(LOG_TAG, "Updating associations: " + old + " --> " + associations);
|
||||
}
|
||||
mCachedAssociations = Collections.unmodifiableSet(associations);
|
||||
mCachedAssociations.put(userId, Collections.unmodifiableSet(associations));
|
||||
BackgroundThread.getHandler().sendMessage(PooledLambda.obtainMessage(
|
||||
CompanionDeviceManagerService::persistAssociations,
|
||||
this, associations, userId));
|
||||
@@ -651,10 +684,17 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
xml.startTag(null, XML_TAG_ASSOCIATIONS);
|
||||
|
||||
forEach(associations, association -> {
|
||||
xml.startTag(null, XML_TAG_ASSOCIATION)
|
||||
XmlSerializer tag = xml.startTag(null, XML_TAG_ASSOCIATION)
|
||||
.attribute(null, XML_ATTR_PACKAGE, association.getPackageName())
|
||||
.attribute(null, XML_ATTR_DEVICE, association.getDeviceMacAddress())
|
||||
.endTag(null, XML_TAG_ASSOCIATION);
|
||||
.attribute(null, XML_ATTR_DEVICE,
|
||||
association.getDeviceMacAddress());
|
||||
if (association.getDeviceProfile() != null) {
|
||||
tag.attribute(null, XML_ATTR_PROFILE, association.getDeviceProfile());
|
||||
tag.attribute(null, XML_ATTR_PERSISTENT_PROFILE_GRANTS,
|
||||
Boolean.toString(
|
||||
association.isKeepProfilePrivilegesWhenDeviceAway()));
|
||||
}
|
||||
tag.endTag(null, XML_TAG_ASSOCIATION);
|
||||
});
|
||||
|
||||
xml.endTag(null, XML_TAG_ASSOCIATIONS);
|
||||
@@ -678,17 +718,21 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
@Nullable
|
||||
private Set<Association> getAllAssociations(int userId) {
|
||||
synchronized (mLock) {
|
||||
if (mCachedAssociations == null) {
|
||||
mCachedAssociations = Collections.unmodifiableSet(
|
||||
emptyIfNull(readAllAssociations(userId)));
|
||||
if (mCachedAssociations.get(userId) == null) {
|
||||
mCachedAssociations.put(userId, Collections.unmodifiableSet(
|
||||
emptyIfNull(readAllAssociations(userId))));
|
||||
if (DEBUG) {
|
||||
Slog.i(LOG_TAG, "Read associations from disk: " + mCachedAssociations);
|
||||
}
|
||||
}
|
||||
return mCachedAssociations;
|
||||
return mCachedAssociations.get(userId);
|
||||
}
|
||||
}
|
||||
|
||||
private List<UserInfo> getAllUsers() {
|
||||
return getContext().getSystemService(UserManager.class).getUsers();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Set<Association> getAllAssociations(int userId, @Nullable String packageFilter) {
|
||||
return CollectionUtils.filter(
|
||||
@@ -714,10 +758,15 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
final String appPackage = parser.getAttributeValue(null, XML_ATTR_PACKAGE);
|
||||
final String deviceAddress = parser.getAttributeValue(null, XML_ATTR_DEVICE);
|
||||
|
||||
final String profile = parser.getAttributeValue(null, XML_ATTR_PROFILE);
|
||||
final boolean persistentGrants = Boolean.valueOf(
|
||||
parser.getAttributeValue(null, XML_ATTR_PERSISTENT_PROFILE_GRANTS));
|
||||
|
||||
if (appPackage == null || deviceAddress == null) continue;
|
||||
|
||||
result = ArrayUtils.add(result,
|
||||
new Association(userId, deviceAddress, appPackage));
|
||||
new Association(userId, deviceAddress, appPackage,
|
||||
profile, persistentGrants));
|
||||
}
|
||||
return result;
|
||||
} catch (XmlPullParserException | IOException e) {
|
||||
@@ -727,6 +776,77 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
}
|
||||
}
|
||||
|
||||
void onDeviceConnected(String address) {
|
||||
mCurrentlyConnectedDevices.add(address);
|
||||
|
||||
Handler.getMain().removeCallbacksAndMessages(getDisconnectJobHandlerId(address));
|
||||
|
||||
for (UserInfo user : getAllUsers()) {
|
||||
for (Association association : getAllAssociations(user.id)) {
|
||||
if (Objects.equals(address, association.getDeviceMacAddress())) {
|
||||
if (association.getDeviceProfile() != null) {
|
||||
Log.i(LOG_TAG, "Granting role " + association.getDeviceProfile()
|
||||
+ " to " + association.getPackageName()
|
||||
+ " due to device connected: " + address);
|
||||
mRoleManager.addRoleHolderAsUser(
|
||||
association.getDeviceProfile(),
|
||||
association.getPackageName(),
|
||||
RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
|
||||
UserHandle.of(association.getUserId()),
|
||||
getContext().getMainExecutor(),
|
||||
success -> {
|
||||
if (!success) {
|
||||
Log.e(LOG_TAG, "Failed to grant device profile role "
|
||||
+ association.getDeviceProfile()
|
||||
+ " to " + association.getPackageName()
|
||||
+ " for user " + association.getUserId());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onDeviceDisconnected(String address) {
|
||||
mCurrentlyConnectedDevices.remove(address);
|
||||
|
||||
Handler.getMain().postDelayed(() -> {
|
||||
if (!mCurrentlyConnectedDevices.contains(address)) {
|
||||
for (UserInfo user : getAllUsers()) {
|
||||
for (Association association : getAllAssociations(user.id)) {
|
||||
if (association.getDeviceProfile() != null
|
||||
&& Objects.equals(address, association.getDeviceMacAddress())
|
||||
&& !association.isKeepProfilePrivilegesWhenDeviceAway()) {
|
||||
Log.i(LOG_TAG, "Revoking role " + association.getDeviceProfile()
|
||||
+ " to " + association.getPackageName()
|
||||
+ " due to device disconnected: " + address);
|
||||
mRoleManager.removeRoleHolderAsUser(
|
||||
association.getDeviceProfile(),
|
||||
association.getPackageName(),
|
||||
RoleManager.MANAGE_HOLDERS_FLAG_DONT_KILL_APP,
|
||||
UserHandle.of(association.getUserId()),
|
||||
getContext().getMainExecutor(),
|
||||
success -> {
|
||||
if (!success) {
|
||||
Log.e(LOG_TAG, "Failed to revoke device profile role "
|
||||
+ association.getDeviceProfile()
|
||||
+ " to " + association.getPackageName()
|
||||
+ " for user " + association.getUserId());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, getDisconnectJobHandlerId(address), DEVICE_DISCONNECT_PROFILE_REVOKE_DELAY_MS);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String getDisconnectJobHandlerId(String address) {
|
||||
return "CDM_onDisconnected_" + address;
|
||||
}
|
||||
|
||||
private class ShellCmd extends ShellCommand {
|
||||
public static final String USAGE = "help\n"
|
||||
+ "list USER_ID\n"
|
||||
@@ -749,13 +869,22 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
} break;
|
||||
|
||||
case "associate": {
|
||||
addAssociation(getNextArgInt(), getNextArgRequired(), getNextArgRequired());
|
||||
addAssociation(new Association(getNextArgInt(), getNextArgRequired(),
|
||||
getNextArgRequired(), null, false));
|
||||
} break;
|
||||
|
||||
case "disassociate": {
|
||||
removeAssociation(getNextArgInt(), getNextArgRequired(), getNextArgRequired());
|
||||
} break;
|
||||
|
||||
case "simulate_connect": {
|
||||
onDeviceConnected(getNextArgRequired());
|
||||
} break;
|
||||
|
||||
case "simulate_disconnect": {
|
||||
onDeviceDisconnected(getNextArgRequired());
|
||||
} break;
|
||||
|
||||
default: return handleDefaultCommands(cmd);
|
||||
}
|
||||
return 0;
|
||||
@@ -771,4 +900,17 @@ public class CompanionDeviceManagerService extends SystemService implements Bind
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class BluetoothDeviceConnectedListener
|
||||
extends BluetoothAdapter.BluetoothConnectionCallback {
|
||||
@Override
|
||||
public void onDeviceConnected(BluetoothDevice device) {
|
||||
CompanionDeviceManagerService.this.onDeviceConnected(device.getAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceDisconnected(BluetoothDevice device) {
|
||||
CompanionDeviceManagerService.this.onDeviceDisconnected(device.getAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user