Merge "Move and rename Bluetooth profile inhibits to CarProjectionManager."
diff --git a/car-lib/api/system-current.txt b/car-lib/api/system-current.txt
index 1c34646..9ab0716 100644
--- a/car-lib/api/system-current.txt
+++ b/car-lib/api/system-current.txt
@@ -46,6 +46,8 @@
method public void onCarDisconnected();
method public void registerProjectionListener(android.car.CarProjectionManager.CarProjectionListener, int) throws android.car.CarNotConnectedException;
method public void registerProjectionRunner(android.content.Intent) throws android.car.CarNotConnectedException;
+ method public boolean releaseBluetoothProfileInhibit(android.bluetooth.BluetoothDevice, int, android.os.IBinder);
+ method public boolean requestBluetoothProfileInhibit(android.bluetooth.BluetoothDevice, int, android.os.IBinder);
method public void startProjectionAccessPoint(android.car.CarProjectionManager.ProjectionAccessPointCallback);
method public void stopProjectionAccessPoint();
method public void unregisterProjectionListener();
diff --git a/car-lib/src/android/car/CarBluetoothManager.java b/car-lib/src/android/car/CarBluetoothManager.java
index bb9c8ff..e6b9161 100644
--- a/car-lib/src/android/car/CarBluetoothManager.java
+++ b/car-lib/src/android/car/CarBluetoothManager.java
@@ -128,48 +128,6 @@
}
}
- /**
- * Request to disconnect the given profile on the given device, and prevent it from reconnecting
- * until either the request is released, or the process owning the given token dies.
- *
- * @param device The device on which to disconnect a profile.
- * @param profile The {@link android.bluetooth.BluetoothProfile} to disconnect.
- * @param token A {@link IBinder} to be used as an identity for the request. If the process
- * owning the token dies, the request will automatically be released.
- * @return True if the profile was successfully disconnected, false if an error occurred.
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean requestTemporaryProfileDisconnect(
- BluetoothDevice device, int profile, IBinder token) throws CarNotConnectedException {
- try {
- return mService.requestTemporaryDisconnect(device, profile, token);
- } catch (RemoteException e) {
- Log.e(CarLibLog.TAG_CAR, "requestTemporaryDisconnect failed", e);
- throw new CarNotConnectedException(e);
- }
- }
-
- /**
- * Undo a previous call to {@link #requestTemporaryProfileDisconnect} with the same parameters,
- * and reconnect the profile if no other requests are active.
- *
- * @param device The device on which to release the disconnect request.
- * @param profile The profile on which to release the disconnect request.
- * @param token The token provided in the original call to
- * {@link #requestTemporaryProfileDisconnect}.
- *
- * @return True if the request was released, false if an error occurred.
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean releaseTemporaryProfileDisconnect(
- BluetoothDevice device, int profile, IBinder token) throws CarNotConnectedException {
- try {
- return mService.releaseTemporaryDisconnect(device, profile, token);
- } catch (RemoteException e) {
- Log.e(CarLibLog.TAG_CAR, "requestTemporaryDisconnect failed", e);
- throw new CarNotConnectedException(e);
- }
- }
/** @hide */
public CarBluetoothManager(IBinder service, Context context) {
diff --git a/car-lib/src/android/car/CarProjectionManager.java b/car-lib/src/android/car/CarProjectionManager.java
index 2fc5944..a5a25b5 100644
--- a/car-lib/src/android/car/CarProjectionManager.java
+++ b/car-lib/src/android/car/CarProjectionManager.java
@@ -17,6 +17,7 @@
package android.car;
import android.annotation.SystemApi;
+import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.net.wifi.WifiConfiguration;
import android.os.Binder;
@@ -237,6 +238,46 @@
}
/**
+ * Request to disconnect the given profile on the given device, and prevent it from reconnecting
+ * until either the request is released, or the process owning the given token dies.
+ *
+ * @param device The device on which to inhibit a profile.
+ * @param profile The {@link android.bluetooth.BluetoothProfile} to inhibit.
+ * @param token A {@link IBinder} to be used as an identity for the request. If the process
+ * owning the token dies, the request will automatically be released.
+ * @return True if the profile was successfully inhibited, false if an error occurred.
+ */
+ public boolean requestBluetoothProfileInhibit(
+ BluetoothDevice device, int profile, IBinder token) {
+ try {
+ return mService.requestBluetoothProfileInhibit(device, profile, token);
+ } catch (RemoteException e) {
+ Log.e(CarLibLog.TAG_CAR, "requestBluetoothProfileInhibit failed", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Release an inhibit request made by {@link #requestBluetoothProfileInhibit}, and reconnect the
+ * profile if no other inhibit requests are active.
+ *
+ * @param device The device on which to release the inhibit request.
+ * @param profile The profile on which to release the inhibit request.
+ * @param token The token provided in the original call to
+ * {@link #requestBluetoothProfileInhibit}.
+ * @return True if the request was released, false if an error occurred.
+ */
+ public boolean releaseBluetoothProfileInhibit(
+ BluetoothDevice device, int profile, IBinder token) {
+ try {
+ return mService.releaseBluetoothProfileInhibit(device, profile, token);
+ } catch (RemoteException e) {
+ Log.e(CarLibLog.TAG_CAR, "releaseBluetoothProfileInhibit failed", e);
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback class for applications to receive updates about the LocalOnlyHotspot status.
*/
public abstract static class ProjectionAccessPointCallback {
diff --git a/car-lib/src/android/car/ICarBluetooth.aidl b/car-lib/src/android/car/ICarBluetooth.aidl
index ee7eb29..a5fbb73 100644
--- a/car-lib/src/android/car/ICarBluetooth.aidl
+++ b/car-lib/src/android/car/ICarBluetooth.aidl
@@ -24,6 +24,4 @@
void clearBluetoothDeviceConnectionPriority(in int profileToClear,in int priorityToClear);
boolean isPriorityDevicePresent(in int profile, in int priorityToCheck);
String getDeviceNameWithPriority(in int profile, in int priorityToCheck);
- boolean requestTemporaryDisconnect(in BluetoothDevice device, in int profile, in IBinder token);
- boolean releaseTemporaryDisconnect(in BluetoothDevice device, in int profile, in IBinder token);
}
diff --git a/car-lib/src/android/car/ICarProjection.aidl b/car-lib/src/android/car/ICarProjection.aidl
index 4f80e6c..efaac0d 100644
--- a/car-lib/src/android/car/ICarProjection.aidl
+++ b/car-lib/src/android/car/ICarProjection.aidl
@@ -16,6 +16,7 @@
package android.car;
+import android.bluetooth.BluetoothDevice;
import android.car.ICarProjectionCallback;
import android.content.Intent;
import android.os.Messenger;
@@ -60,4 +61,12 @@
* Stops previously requested Wi-Fi access point.
*/
void stopProjectionAccessPoint(in IBinder binder) = 5;
+
+ /** Disconnect a Bluetooth profile, and prevent it from reconnecting. */
+ boolean requestBluetoothProfileInhibit(
+ in BluetoothDevice device, in int profile, in IBinder token) = 6;
+
+ /** Undo the effects of requestBluetoothProfileInhibit. */
+ boolean releaseBluetoothProfileInhibit(
+ in BluetoothDevice device, in int profile, in IBinder token) = 7;
}
diff --git a/car-lib/src/android/car/settings/CarSettings.java b/car-lib/src/android/car/settings/CarSettings.java
index f614601..f89f521 100644
--- a/car-lib/src/android/car/settings/CarSettings.java
+++ b/car-lib/src/android/car/settings/CarSettings.java
@@ -206,7 +206,7 @@
* Read and written by {@link com.android.car.BluetoothDeviceConnectionPolicy}.
* @hide
*/
- public static final String KEY_BLUETOOTH_TEMPORARY_DISCONNECTS =
- "android.car.BLUETOOTH_TEMPORARY_DISCONNECTS";
+ public static final String KEY_BLUETOOTH_PROFILES_INHIBITED =
+ "android.car.BLUETOOTH_PROFILES_INHIBITED";
}
}
diff --git a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
index dcd7e16..5d7fc0e 100644
--- a/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
+++ b/service/src/com/android/car/BluetoothDeviceConnectionPolicy.java
@@ -20,7 +20,7 @@
import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_AUTOCONNECT_MUSIC_DEVICES;
import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_AUTOCONNECT_NETWORK_DEVICES;
import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_AUTOCONNECT_PHONE_DEVICES;
-import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_TEMPORARY_DISCONNECTS;
+import static android.car.settings.CarSettings.Secure.KEY_BLUETOOTH_PROFILES_INHIBITED;
import android.annotation.Nullable;
import android.app.ActivityManager;
@@ -59,6 +59,7 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
@@ -100,7 +101,7 @@
private static final String SETTINGS_DELIMITER = ",";
private static final boolean DBG = Utils.DBG;
- private static final Binder RESTORED_TEMPORARY_DISCONNECT_TOKEN = new Binder();
+ private static final Binder RESTORED_PROFILE_INHIBIT_TOKEN = new Binder();
private static final long RESTORE_BACKOFF_MILLIS = 1000L;
private final Context mContext;
@@ -158,9 +159,13 @@
// Maintain a list of Paired devices which haven't connected on any profiles yet.
private Set<BluetoothDevice> mPairedButUnconnectedDevices = new HashSet<>();
- // State for temporary disconnects. Guarded by lock on `this`.
- private final SetMultimap<ConnectionParams, DisconnectRecord> mTemporaryDisconnects;
- private final HashSet<DisconnectRecord> mRestoredDisconnects = new HashSet<>();
+ // State for profile inhibits.
+ @GuardedBy("this")
+ private final SetMultimap<ConnectionParams, InhibitRecord> mProfileInhibits =
+ new SetMultimap<>();
+ @GuardedBy("this")
+ private final HashSet<InhibitRecord> mRestoredInhibits = new HashSet<>();
+ @GuardedBy("this")
private final HashSet<ConnectionParams> mAlreadyDisabledProfiles = new HashSet<>();
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -227,8 +232,6 @@
Log.w(TAG, "No Bluetooth Adapter Available");
}
mFastPairProvider = new FastPairProvider(mContext);
-
- mTemporaryDisconnects = new SetMultimap<>();
}
/**
@@ -331,13 +334,13 @@
}
}
- private class DisconnectRecord implements IBinder.DeathRecipient {
+ private class InhibitRecord implements IBinder.DeathRecipient {
private final ConnectionParams mParams;
private final IBinder mToken;
private boolean mRemoved = false;
- DisconnectRecord(ConnectionParams params, IBinder token) {
+ InhibitRecord(ConnectionParams params, IBinder token) {
this.mParams = params;
this.mToken = token;
}
@@ -356,7 +359,7 @@
return true;
}
- if (removeDisconnectRecord(this)) {
+ if (removeInhibitRecord(this)) {
mRemoved = true;
return true;
} else {
@@ -368,7 +371,7 @@
@Override
public void binderDied() {
if (DBG) {
- Log.d(TAG, "Releasing disconnect request on profile "
+ Log.d(TAG, "Releasing inhibit request on profile "
+ Utils.getProfileName(mParams.getBluetoothProfile())
+ " for device " + mParams.getBluetoothDevice()
+ ": requesting process died");
@@ -497,15 +500,19 @@
}
if (mCarBluetoothUserService != null) {
for (Integer profile : mProfilesToConnect) {
- // If this profile is temporarily disconnected, don't try to change its priority
- // until the temporary disconnect is released.
synchronized (this) {
ConnectionParams params = new ConnectionParams(profile, device);
- if (mTemporaryDisconnects.keySet().contains(params)) {
+ // If this profile is inhibited, don't try to change its priority until the
+ // inhibit is released. Instead, if the profile is being enabled, take it off of
+ // the "previously disabled profiles" list, so it will be restored when all
+ // inhibits are removed.
+ if (mProfileInhibits.keySet().contains(params)) {
if (DBG) {
Log.i(TAG, "Not setting profile " + profile + " priority of "
- + device.getAddress() + " to " + priority + ": "
- + "temporarily disconnected");
+ + device.getAddress() + " to " + priority + ": inhibited");
+ }
+ if (priority == BluetoothProfile.PRIORITY_ON) {
+ mAlreadyDisabledProfiles.remove(params);
}
continue;
}
@@ -578,10 +585,10 @@
mCarBluetoothUserService = setupBluetoothUserService();
// re-initialize for current user.
initializeUserSpecificInfo();
- // Restore temporary disconnects, if any, that were saved from last run...
- restoreTemporaryDisconnectsFromSettings();
+ // Restore profile inhibits, if any, that were saved from last run...
+ restoreProfileInhibitsFromSettings();
// ... and start trying to remove them.
- removeRestoredTemporaryDisconnects();
+ removeRestoredProfileInhibits();
}
@Override
@@ -590,13 +597,13 @@
Log.d(TAG, "Before Unbinding from UserService");
}
- // Try to release temporary disconnects now, before CarBluetoothUserService goes away.
- // This also stops any active attempts to remove restored disconnects.
+ // Try to release profile inhibits now, before CarBluetoothUserService goes away.
+ // This also stops any active attempts to remove restored inhibits.
//
// If any can't be released, they'll persist in settings and will be cleaned up
// next time this user starts. This can happen if the Bluetooth profile proxies in
// CarBluetoothUserService unbind before we get the chance to make calls on them.
- releaseAllDisconnectRecordsBeforeUnbind();
+ releaseAllInhibitsBeforeUnbind();
try {
if (mCarBluetoothUserService != null) {
@@ -974,34 +981,34 @@
/**
* Request to disconnect the given profile on the given device, and prevent it from reconnecting
* until either the request is released, or the process owning the given token dies.
- * @return True if the profile was successfully disconnected, false if an error occurred.
+ * @return True if the profile was successfully inhibited, false if an error occurred.
*/
- public boolean requestProfileDisconnect(BluetoothDevice device, int profile, IBinder token) {
+ boolean requestProfileInhibit(BluetoothDevice device, int profile, IBinder token) {
if (DBG) {
- Log.d(TAG, "Request profile disconnect: profile " + Utils.getProfileName(profile)
+ Log.d(TAG, "Request profile inhibit: profile " + Utils.getProfileName(profile)
+ ", device " + device.getAddress());
}
ConnectionParams params = new ConnectionParams(profile, device);
- DisconnectRecord record = new DisconnectRecord(params, token);
- return addDisconnectRecord(record);
+ InhibitRecord record = new InhibitRecord(params, token);
+ return addInhibitRecord(record);
}
/**
- * Undo a previous call to {@link #requestProfileDisconnect} with the same parameters,
+ * Undo a previous call to {@link #requestProfileInhibit} with the same parameters,
* and reconnect the profile if no other requests are active.
*
* @return True if the request was released, false if an error occurred.
*/
- public boolean releaseProfileDisconnect(BluetoothDevice device, int profile, IBinder token) {
+ boolean releaseProfileInhibit(BluetoothDevice device, int profile, IBinder token) {
if (DBG) {
- Log.d(TAG, "Release profile disconnect: profile " + Utils.getProfileName(profile)
+ Log.d(TAG, "Release profile inhibit: profile " + Utils.getProfileName(profile)
+ ", device " + device.getAddress());
}
ConnectionParams params = new ConnectionParams(profile, device);
- DisconnectRecord record;
+ InhibitRecord record;
synchronized (this) {
- record = findDisconnectRecordLocked(params, token);
+ record = findInhibitRecordLocked(params, token);
}
if (record == null) {
@@ -1012,28 +1019,28 @@
return record.removeSelf();
}
- /** Add a temporary disconnect record, disconnecting if necessary. */
- private synchronized boolean addDisconnectRecord(DisconnectRecord record) {
+ /** Add a profile inhibit record, disabling the profile if necessary. */
+ private synchronized boolean addInhibitRecord(InhibitRecord record) {
ConnectionParams params = record.getParams();
if (!isProxyAvailable(params.getBluetoothProfile())) {
return false;
}
- Set<DisconnectRecord> previousRecords = mTemporaryDisconnects.get(params);
- if (findDisconnectRecordLocked(params, record.getToken()) != null) {
- Log.e(TAG, "Disconnect request already registered - skipping duplicate");
+ Set<InhibitRecord> previousRecords = mProfileInhibits.get(params);
+ if (findInhibitRecordLocked(params, record.getToken()) != null) {
+ Log.e(TAG, "Inhibit request already registered - skipping duplicate");
return false;
}
try {
record.getToken().linkToDeath(record, 0);
} catch (RemoteException e) {
- Log.e(TAG, "Could not link to death on disconnect token (already dead?)", e);
+ Log.e(TAG, "Could not link to death on inhibit token (already dead?)", e);
return false;
}
boolean isNewlyAdded = previousRecords.isEmpty();
- mTemporaryDisconnects.put(params, record);
+ mProfileInhibits.put(params, record);
if (isNewlyAdded) {
try {
@@ -1042,8 +1049,8 @@
params.getBluetoothProfile(),
params.getBluetoothDevice());
if (priority == BluetoothProfile.PRIORITY_OFF) {
- // This profile was already disabled (and not as the result of a temporary
- // disconnect). Add it to the already-disabled list, and do nothing else.
+ // This profile was already disabled (and not as the result of an inhibit).
+ // Add it to the already-disabled list, and do nothing else.
mAlreadyDisabledProfiles.add(params);
if (DBG) {
@@ -1068,22 +1075,22 @@
} catch (RemoteException e) {
Log.e(TAG, "Could not disable profile", e);
record.getToken().unlinkToDeath(record, 0);
- mTemporaryDisconnects.remove(params, record);
+ mProfileInhibits.remove(params, record);
return false;
}
}
- saveTemporaryDisconnectsToSettingsLocked();
+ saveProfileInhibitsToSettingsLocked();
return true;
}
- /** Remove a given temporary disconnect record, reconnecting if necessary. */
- private synchronized boolean removeDisconnectRecord(DisconnectRecord record) {
+ /** Remove a given profile inhibit record, reconnecting if necessary. */
+ private synchronized boolean removeInhibitRecord(InhibitRecord record) {
ConnectionParams params = record.getParams();
if (!isProxyAvailable(params.getBluetoothProfile())) {
return false;
}
- if (!mTemporaryDisconnects.containsEntry(params, record)) {
+ if (!mProfileInhibits.containsEntry(params, record)) {
Log.e(TAG, "Record already removed");
// Removing something a second time vacuously succeeds.
return true;
@@ -1092,23 +1099,23 @@
// Re-enable profile before unlinking and removing the record, in case of error.
// The profile should be re-enabled if this record is the only one left for that
// device and profile combination.
- if (mTemporaryDisconnects.get(params).size() == 1) {
+ if (mProfileInhibits.get(params).size() == 1) {
if (!restoreProfilePriority(params)) {
return false;
}
}
record.getToken().unlinkToDeath(record, 0);
- mTemporaryDisconnects.remove(params, record);
+ mProfileInhibits.remove(params, record);
- saveTemporaryDisconnectsToSettingsLocked();
+ saveProfileInhibitsToSettingsLocked();
return true;
}
- /** Find the disconnect record, if any, corresponding to the given parameters and token. */
+ /** Find the inhibit record, if any, corresponding to the given parameters and token. */
@Nullable
- private DisconnectRecord findDisconnectRecordLocked(ConnectionParams params, IBinder token) {
- return mTemporaryDisconnects.get(params)
+ private InhibitRecord findInhibitRecordLocked(ConnectionParams params, IBinder token) {
+ return mProfileInhibits.get(params)
.stream()
.filter(r -> r.getToken() == token)
.findAny()
@@ -1123,7 +1130,7 @@
if (mAlreadyDisabledProfiles.remove(params)) {
// The profile does not need any state changes, since it was disabled
- // before it was temporarily disconnected. Leave it disconnected.
+ // before it was inhibited. Leave it disabled.
if (DBG) {
Log.d(TAG, "Not restoring profile "
+ Utils.getProfileName(params.getBluetoothProfile()) + " for device "
@@ -1151,37 +1158,37 @@
}
}
- /** Dump all currently-active temporary disconnects to {@link Settings.Secure}. */
- private void saveTemporaryDisconnectsToSettingsLocked() {
- Set<ConnectionParams> disconnectedProfiles = new HashSet<>(mTemporaryDisconnects.keySet());
- // Don't write out profiles that were disconnected before a request was made, since
+ /** Dump all currently-active profile inhibits to {@link Settings.Secure}. */
+ private void saveProfileInhibitsToSettingsLocked() {
+ Set<ConnectionParams> inhibitedProfiles = new HashSet<>(mProfileInhibits.keySet());
+ // Don't write out profiles that were disabled before a request was made, since
// restoring those profiles is a no-op.
- disconnectedProfiles.removeAll(mAlreadyDisabledProfiles);
+ inhibitedProfiles.removeAll(mAlreadyDisabledProfiles);
String savedDisconnects =
- disconnectedProfiles
+ inhibitedProfiles
.stream()
.map(ConnectionParams::flattenToString)
.collect(Collectors.joining(SETTINGS_DELIMITER));
if (DBG) {
- Log.d(TAG, "Saving disconnects to settings for u" + mUserId + ": " + savedDisconnects);
+ Log.d(TAG, "Saving inhibits to settings for u" + mUserId + ": " + savedDisconnects);
}
Settings.Secure.putStringForUser(
- mContext.getContentResolver(), KEY_BLUETOOTH_TEMPORARY_DISCONNECTS,
+ mContext.getContentResolver(), KEY_BLUETOOTH_PROFILES_INHIBITED,
savedDisconnects, mUserId);
}
- /** Create {@link DisconnectRecord}s for all temporary disconnects written to settings. */
- private synchronized void restoreTemporaryDisconnectsFromSettings() {
+ /** Create {@link InhibitRecord}s for all profile inhibits written to settings. */
+ private synchronized void restoreProfileInhibitsFromSettings() {
if (mBluetoothAdapter == null) {
- Log.e(TAG, "Cannot restore disconnect records - Bluetooth not available");
+ Log.e(TAG, "Cannot restore inhibit records - Bluetooth not available");
return;
}
String savedConnectionParams = Settings.Secure.getStringForUser(
mContext.getContentResolver(),
- KEY_BLUETOOTH_TEMPORARY_DISCONNECTS,
+ KEY_BLUETOOTH_PROFILES_INHIBITED,
mUserId);
if (TextUtils.isEmpty(savedConnectionParams)) {
@@ -1189,89 +1196,89 @@
}
if (DBG) {
- Log.d(TAG, "Restoring temporary disconnects: " + savedConnectionParams);
+ Log.d(TAG, "Restoring profile inhibits: " + savedConnectionParams);
}
for (String paramsStr : savedConnectionParams.split(SETTINGS_DELIMITER)) {
try {
ConnectionParams params = ConnectionParams.parse(paramsStr, mBluetoothAdapter);
- DisconnectRecord record =
- new DisconnectRecord(params, RESTORED_TEMPORARY_DISCONNECT_TOKEN);
- mTemporaryDisconnects.put(params, record);
- mRestoredDisconnects.add(record);
+ InhibitRecord record =
+ new InhibitRecord(params, RESTORED_PROFILE_INHIBIT_TOKEN);
+ mProfileInhibits.put(params, record);
+ mRestoredInhibits.add(record);
if (DBG) {
- Log.d(TAG, "Restored temporary disconnect for " + params);
+ Log.d(TAG, "Restored profile inhibits for " + params);
}
} catch (IllegalArgumentException e) {
- Log.e(TAG, "Bad format for saved temporary disconnect: " + paramsStr, e);
+ Log.e(TAG, "Bad format for saved profile inhibit: " + paramsStr, e);
// We won't ever be able to fix a bad parse, so skip it and move on.
}
}
}
/**
- * Try once to remove all temporary disconnects.
+ * Try once to remove all restored profile inhibits.
*
* If the CarBluetoothUserService is not yet available, or it hasn't yet bound its profile
* proxies, the removal will fail, and will need to be retried later.
*/
- private void tryRemoveRestoredTemporaryDisconnectsLocked() {
- HashSet<DisconnectRecord> successfullyRemoved = new HashSet<>();
+ private void tryRemoveRestoredProfileInhibitsLocked() {
+ HashSet<InhibitRecord> successfullyRemoved = new HashSet<>();
- for (DisconnectRecord record : mRestoredDisconnects) {
- if (removeDisconnectRecord(record)) {
+ for (InhibitRecord record : mRestoredInhibits) {
+ if (removeInhibitRecord(record)) {
successfullyRemoved.add(record);
}
}
- mRestoredDisconnects.removeAll(successfullyRemoved);
+ mRestoredInhibits.removeAll(successfullyRemoved);
}
/**
- * Keep trying to remove all temporary disconnects that were restored from settings
- * until all such temporary disconnects have been removed.
+ * Keep trying to remove all profile inhibits that were restored from settings
+ * until all such inhibits have been removed.
*/
- private synchronized void removeRestoredTemporaryDisconnects() {
- tryRemoveRestoredTemporaryDisconnectsLocked();
+ private synchronized void removeRestoredProfileInhibits() {
+ tryRemoveRestoredProfileInhibitsLocked();
- if (!mRestoredDisconnects.isEmpty()) {
+ if (!mRestoredInhibits.isEmpty()) {
if (DBG) {
- Log.d(TAG, "Could not remove all restored temporary disconnects - "
+ Log.d(TAG, "Could not remove all restored profile inhibits - "
+ "trying again in " + RESTORE_BACKOFF_MILLIS + "ms");
}
mHandler.postDelayed(
- this::removeRestoredTemporaryDisconnects,
- RESTORED_TEMPORARY_DISCONNECT_TOKEN,
+ this::removeRestoredProfileInhibits,
+ RESTORED_PROFILE_INHIBIT_TOKEN,
RESTORE_BACKOFF_MILLIS);
}
}
- /** Release all active disconnect records prior to user switch or shutdown. */
- private synchronized void releaseAllDisconnectRecordsBeforeUnbind() {
+ /** Release all active inhibit records prior to user switch or shutdown. */
+ private synchronized void releaseAllInhibitsBeforeUnbind() {
if (DBG) {
- Log.d(TAG, "Unbinding CarBluetoothUserService - releasing all temporary disconnects");
+ Log.d(TAG, "Unbinding CarBluetoothUserService - releasing all profile inhibits");
}
- for (ConnectionParams params : mTemporaryDisconnects.keySet()) {
- for (DisconnectRecord record : mTemporaryDisconnects.get(params)) {
+ for (ConnectionParams params : mProfileInhibits.keySet()) {
+ for (InhibitRecord record : mProfileInhibits.get(params)) {
record.removeSelf();
}
}
- // Some disconnects might be hanging around because they couldn't be cleaned up.
+ // Some inhibits might be hanging around because they couldn't be cleaned up.
// Make sure they get persisted...
- saveTemporaryDisconnectsToSettingsLocked();
+ saveProfileInhibitsToSettingsLocked();
// ...then clear them from the map.
- mTemporaryDisconnects.clear();
+ mProfileInhibits.clear();
- // We don't need to maintain previously-disconnected profiles any more - they were already
- // skipped in saveTemporaryDisconnectsToSettingsLocked() above, and they don't need any
+ // We don't need to maintain previously-disabled profiles any more - they were already
+ // skipped in saveProfileInhibitsToSettingsLocked() above, and they don't need any
// further handling when the user resumes.
mAlreadyDisabledProfiles.clear();
- // Clean up bookkeeping for restored disconnects. (If any are still around, they'll be
+ // Clean up bookkeeping for restored inhibits. (If any are still around, they'll be
// restored again when this user restarts.)
- mHandler.removeCallbacksAndMessages(RESTORED_TEMPORARY_DISCONNECT_TOKEN);
- mRestoredDisconnects.clear();
+ mHandler.removeCallbacksAndMessages(RESTORED_PROFILE_INHIBIT_TOKEN);
+ mRestoredInhibits.clear();
}
/**
@@ -2074,11 +2081,10 @@
writer.println("*BluetoothDeviceConnectionPolicy*");
printDeviceMap(writer);
mBluetoothAutoConnectStateMachine.dump(writer);
- writer.println("Temporary disconnects active:");
- String disconnects;
+ String inhibits;
synchronized (this) {
- disconnects = mTemporaryDisconnects.keySet().toString();
+ inhibits = mProfileInhibits.keySet().toString();
}
- writer.println(disconnects);
+ writer.println("Inhibited profiles: " + inhibits);
}
}
diff --git a/service/src/com/android/car/CarBluetoothService.java b/service/src/com/android/car/CarBluetoothService.java
index a8ffdcc..d34d165 100644
--- a/service/src/com/android/car/CarBluetoothService.java
+++ b/service/src/com/android/car/CarBluetoothService.java
@@ -31,7 +31,6 @@
import android.car.ICarBluetooth;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.os.Binder;
import android.os.IBinder;
import android.provider.Settings;
import android.util.Log;
@@ -155,60 +154,28 @@
* Request to disconnect the given profile on the given device, and prevent it from reconnecting
* until either the request is released, or the process owning the given token dies.
*
- * @param device The device on which to disconnect a profile.
- * @param profile The {@link android.bluetooth.BluetoothProfile} to disconnect.
- * @param token A {@link IBinder} to be used as an identity for the request. If the process
- * owning the token dies, the request will automatically be released.
- * @return True if the profile was successfully disconnected, false if an error occurred.
+ * @param device The device on which to inhibit a profile.
+ * @param profile The {@link android.bluetooth.BluetoothProfile} to inhibit.
+ * @param token A {@link IBinder} to be used as an identity for the request. If the process
+ * owning the token dies, the request will automatically be released.
+ * @return True if the profile was successfully inhibited, false if an error occurred.
*/
- @Override
- public boolean requestTemporaryDisconnect(BluetoothDevice device, int profile, IBinder token) {
- if (DBG) {
- Log.d(TAG, "requestTemporaryDisconnect device=" + device + " profile=" + profile
- + " from uid " + Binder.getCallingUid());
- }
- try {
- enforceBluetoothAdminPermission();
- if (device == null) {
- // Will be caught by AIDL and thrown to caller.
- throw new NullPointerException("Null device in requestTemporaryDisconnect");
- }
- return mBluetoothDeviceConnectionPolicy
- .requestProfileDisconnect(device, profile, token);
- } catch (RuntimeException e) {
- Log.e(TAG, "Error in requestTemporaryDisconnect", e);
- throw e;
- }
+ boolean requestProfileInhibit(BluetoothDevice device, int profile, IBinder token) {
+ return mBluetoothDeviceConnectionPolicy.requestProfileInhibit(device, profile, token);
}
/**
- * Undo a previous call to {@link #requestProfileDisconnect} with the same parameters,
- * and reconnect the profile if no other requests are active.
+ * Release an inhibit request made by {@link #requestProfileInhibit}, and reconnect the
+ * profile if no other inhibit requests are active.
*
- * @param device The device on which to release the disconnect request.
- * @param profile The profile on which to release the disconnect request.
- * @param token The token provided in the original call to {@link #requestTemporaryDisconnect}.
- *
+ * @param device The device on which to release the inhibit request.
+ * @param profile The profile on which to release the inhibit request.
+ * @param token The token provided in the original call to
+ * {@link #requestProfileInhibit}.
* @return True if the request was released, false if an error occurred.
*/
- @Override
- public boolean releaseTemporaryDisconnect(BluetoothDevice device, int profile, IBinder token) {
- if (DBG) {
- Log.d(TAG, "releaseTemporaryDisconnect device=" + device + " profile=" + profile
- + " from uid " + Binder.getCallingUid());
- }
- try {
- enforceBluetoothAdminPermission();
- if (device == null) {
- // Will be caught by AIDL and thrown to caller.
- throw new NullPointerException("Null device in releaseTemporaryDisconnect");
- }
- return mBluetoothDeviceConnectionPolicy
- .releaseProfileDisconnect(device, profile, token);
- } catch (RuntimeException e) {
- Log.e(TAG, "Error in releaseTemporaryDisconnect", e);
- throw e;
- }
+ boolean releaseProfileInhibit(BluetoothDevice device, int profile, IBinder token) {
+ return mBluetoothDeviceConnectionPolicy.releaseProfileInhibit(device, profile, token);
}
/**
diff --git a/service/src/com/android/car/CarProjectionService.java b/service/src/com/android/car/CarProjectionService.java
index d673eab..582d535 100644
--- a/service/src/com/android/car/CarProjectionService.java
+++ b/service/src/com/android/car/CarProjectionService.java
@@ -28,6 +28,7 @@
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
import android.annotation.Nullable;
+import android.bluetooth.BluetoothDevice;
import android.car.CarProjectionManager;
import android.car.CarProjectionManager.ProjectionAccessPointCallback;
import android.car.ICarProjection;
@@ -78,6 +79,7 @@
private final ProjectionCallbackHolder mProjectionCallbacks;
private final CarInputService mCarInputService;
+ private final CarBluetoothService mCarBluetoothService;
private final Context mContext;
private final WifiManager mWifiManager;
private final Handler mHandler;
@@ -137,10 +139,12 @@
private boolean mBound;
private Intent mRegisteredService;
- CarProjectionService(Context context, CarInputService carInputService) {
+ CarProjectionService(Context context, CarInputService carInputService,
+ CarBluetoothService carBluetoothService) {
mContext = context;
mHandler = new Handler();
mCarInputService = carInputService;
+ mCarBluetoothService = carBluetoothService;
mProjectionCallbacks = new ProjectionCallbackHolder(this);
mWifiManager = context.getSystemService(WifiManager.class);
mProjectionWifiConfiguration = createWifiConfiguration(context);
@@ -260,6 +264,70 @@
}
}
+ /**
+ * Request to disconnect the given profile on the given device, and prevent it from reconnecting
+ * until either the request is released, or the process owning the given token dies.
+ *
+ * @param device The device on which to inhibit a profile.
+ * @param profile The {@link android.bluetooth.BluetoothProfile} to inhibit.
+ * @param token A {@link IBinder} to be used as an identity for the request. If the process
+ * owning the token dies, the request will automatically be released.
+ * @return True if the profile was successfully inhibited, false if an error occurred.
+ */
+ @Override
+ public boolean requestBluetoothProfileInhibit(
+ BluetoothDevice device, int profile, IBinder token) {
+ if (DBG) {
+ Log.d(TAG, "requestBluetoothProfileInhibit device=" + device + " profile=" + profile
+ + " from uid " + Binder.getCallingUid());
+ }
+ try {
+ if (device == null) {
+ // Will be caught by AIDL and thrown to caller.
+ throw new NullPointerException("Device must not be null");
+ }
+ if (token == null) {
+ throw new NullPointerException("Token must not be null");
+ }
+ return mCarBluetoothService.requestProfileInhibit(device, profile, token);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Error in requestBluetoothProfileInhibit", e);
+ throw e;
+ }
+ }
+
+ /**
+ * Release an inhibit request made by {@link #requestBluetoothProfileInhibit}, and reconnect the
+ * profile if no other inhibit requests are active.
+ *
+ * @param device The device on which to release the inhibit request.
+ * @param profile The profile on which to release the inhibit request.
+ * @param token The token provided in the original call to
+ * {@link #requestBluetoothProfileInhibit}.
+ * @return True if the request was released, false if an error occurred.
+ */
+ @Override
+ public boolean releaseBluetoothProfileInhibit(
+ BluetoothDevice device, int profile, IBinder token) {
+ if (DBG) {
+ Log.d(TAG, "releaseBluetoothProfileInhibit device=" + device + " profile=" + profile
+ + " from uid " + Binder.getCallingUid());
+ }
+ try {
+ if (device == null) {
+ // Will be caught by AIDL and thrown to caller.
+ throw new NullPointerException("Device must not be null");
+ }
+ if (token == null) {
+ throw new NullPointerException("Token must not be null");
+ }
+ return mCarBluetoothService.releaseProfileInhibit(device, profile, token);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Error in releaseBluetoothProfileInhibit", e);
+ throw e;
+ }
+ }
+
private void startAccessPoint() {
synchronized (mLock) {
switch (mWifiMode) {
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index adcedf3..63ea2a7 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -124,8 +124,12 @@
mCarPackageManagerService = new CarPackageManagerService(serviceContext,
mCarUXRestrictionsService,
mSystemActivityMonitoringService);
+ mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext);
+ mCarBluetoothService = new CarBluetoothService(serviceContext, mCarPropertyService,
+ mPerUserCarServiceHelper, mCarUXRestrictionsService);
mCarInputService = new CarInputService(serviceContext, mHal.getInputHal());
- mCarProjectionService = new CarProjectionService(serviceContext, mCarInputService);
+ mCarProjectionService = new CarProjectionService(
+ serviceContext, mCarInputService, mCarBluetoothService);
mGarageModeService = new GarageModeService(mContext);
mAppFocusService = new AppFocusService(serviceContext, mSystemActivityMonitoringService);
mCarAudioService = new CarAudioService(serviceContext);
@@ -134,9 +138,6 @@
mAppFocusService, mCarInputService);
mSystemStateControllerService = new SystemStateControllerService(
serviceContext, mCarAudioService, this);
- mPerUserCarServiceHelper = new PerUserCarServiceHelper(serviceContext);
- mCarBluetoothService = new CarBluetoothService(serviceContext, mCarPropertyService,
- mPerUserCarServiceHelper, mCarUXRestrictionsService);
mVmsSubscriberService = new VmsSubscriberService(serviceContext, mHal.getVmsHal());
mVmsPublisherService = new VmsPublisherService(serviceContext, mHal.getVmsHal());
mCarDiagnosticService = new CarDiagnosticService(serviceContext, mHal.getDiagnosticHal());
@@ -162,11 +163,11 @@
allServices.add(mCarAudioService);
allServices.add(mCarNightService);
allServices.add(mInstrumentClusterService);
- allServices.add(mCarProjectionService);
allServices.add(mSystemStateControllerService);
- allServices.add(mCarBluetoothService);
- allServices.add(mCarDiagnosticService);
allServices.add(mPerUserCarServiceHelper);
+ allServices.add(mCarBluetoothService);
+ allServices.add(mCarProjectionService);
+ allServices.add(mCarDiagnosticService);
allServices.add(mCarStorageMonitoringService);
allServices.add(mCarConfigurationService);
allServices.add(mVmsSubscriberService);