Merge changes from topic "showBackground-api"
* changes:
Support backgrounds during animations in shell
Add API to show background behind animating windows
diff --git a/Android.bp b/Android.bp
index e96c731..ab11899 100644
--- a/Android.bp
+++ b/Android.bp
@@ -81,6 +81,7 @@
// Java/AIDL sources under frameworks/base
":framework-annotations",
":framework-blobstore-sources",
+ ":framework-bluetooth-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready
":framework-connectivity-tiramisu-sources",
":framework-core-sources",
":framework-drm-sources",
@@ -93,7 +94,7 @@
":framework-mca-effect-sources",
":framework-mca-filterfw-sources",
":framework-mca-filterpacks-sources",
- ":framework-media-sources",
+ ":framework-media-non-updatable-sources",
":framework-mms-sources",
":framework-omapi-sources",
":framework-opengl-sources",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index 321952d..4aecc8f 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -60,9 +60,9 @@
defaults: ["android-non-updatable-stubs-defaults"],
srcs: [
// No longer part of the stubs, but are included in the docs.
- "test-base/src/**/*.java",
- "test-mock/src/**/*.java",
- "test-runner/src/**/*.java",
+ ":android-test-base-sources",
+ ":android-test-mock-sources",
+ ":android-test-runner-sources",
],
libs: framework_docs_only_libs,
create_doc_stubs: true,
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 260c8a4..b384e70 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -259,7 +259,8 @@
public void runDisableAppDataIsolation() throws RemoteException {
if (!SystemProperties.getBoolean(
ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
- throw new IllegalStateException("Storage app data isolation is not enabled.");
+ System.err.println("Storage app data isolation is not enabled.");
+ return;
}
final String pkgName = nextArg();
final int pid = Integer.parseInt(nextArg());
diff --git a/core/api/current.txt b/core/api/current.txt
index 967199e..4d27dde 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7287,6 +7287,10 @@
method @Nullable public java.util.List<java.lang.String> getDelegatePackages(@NonNull android.content.ComponentName, @NonNull String);
method @NonNull public java.util.List<java.lang.String> getDelegatedScopes(@Nullable android.content.ComponentName, @NonNull String);
method public CharSequence getDeviceOwnerLockScreenInfo();
+ method @Nullable public android.graphics.drawable.Drawable getDrawable(int, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawable(int, int, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(int, int, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
+ method @Nullable public android.graphics.drawable.Drawable getDrawableForDensity(int, int, int, int, @NonNull java.util.concurrent.Callable<android.graphics.drawable.Drawable>);
method public CharSequence getEndUserSessionMessage(@NonNull android.content.ComponentName);
method @NonNull public String getEnrollmentSpecificId();
method @Nullable public android.app.admin.FactoryResetProtectionPolicy getFactoryResetProtectionPolicy(@Nullable android.content.ComponentName);
@@ -7510,6 +7514,7 @@
field public static final String ACTION_CHECK_POLICY_COMPLIANCE = "android.app.action.CHECK_POLICY_COMPLIANCE";
field public static final String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE";
field public static final String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED";
+ field public static final String ACTION_DEVICE_POLICY_RESOURCE_UPDATED = "android.app.action.DEVICE_POLICY_RESOURCE_UPDATED";
field public static final String ACTION_GET_PROVISIONING_MODE = "android.app.action.GET_PROVISIONING_MODE";
field public static final String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
field public static final String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED";
@@ -7585,6 +7590,8 @@
field public static final String EXTRA_PROVISIONING_WIFI_SECURITY_TYPE = "android.app.extra.PROVISIONING_WIFI_SECURITY_TYPE";
field public static final String EXTRA_PROVISIONING_WIFI_SSID = "android.app.extra.PROVISIONING_WIFI_SSID";
field public static final String EXTRA_PROVISIONING_WIFI_USER_CERTIFICATE = "android.app.extra.PROVISIONING_WIFI_USER_CERTIFICATE";
+ field public static final String EXTRA_RESOURCE_ID = "android.app.extra.RESOURCE_ID";
+ field public static final String EXTRA_RESOURCE_TYPE_DRAWABLE = "android.app.extra.RESOURCE_TYPE_DRAWABLE";
field public static final int FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY = 1; // 0x1
field public static final int FLAG_MANAGED_CAN_ACCESS_PARENT = 2; // 0x2
field public static final int FLAG_PARENT_CAN_ACCESS_MANAGED = 1; // 0x1
@@ -7679,6 +7686,35 @@
method public void onApplicationUserDataCleared(String, boolean);
}
+ public final class DevicePolicyResources {
+ ctor public DevicePolicyResources();
+ }
+
+ public static final class DevicePolicyResources.Drawable {
+ field public static final int INVALID_ID = -1; // 0xffffffff
+ field public static final int WORK_PROFILE_ICON = 1; // 0x1
+ field public static final int WORK_PROFILE_ICON_BADGE = 0; // 0x0
+ field public static final int WORK_PROFILE_OFF_ICON = 2; // 0x2
+ field public static final int WORK_PROFILE_USER_ICON = 3; // 0x3
+ }
+
+ public static final class DevicePolicyResources.Drawable.Source {
+ field public static final int HOME_WIDGET = 2; // 0x2
+ field public static final int LAUNCHER_OFF_BUTTON = 3; // 0x3
+ field public static final int NOTIFICATION = 0; // 0x0
+ field public static final int PROFILE_SWITCH_ANIMATION = 1; // 0x1
+ field public static final int QUICK_SETTINGS = 4; // 0x4
+ field public static final int STATUS_BAR = 5; // 0x5
+ field public static final int UNDEFINED = -1; // 0xffffffff
+ }
+
+ public static final class DevicePolicyResources.Drawable.Style {
+ field public static final int DEFAULT = -1; // 0xffffffff
+ field public static final int OUTLINE = 2; // 0x2
+ field public static final int SOLID_COLORED = 0; // 0x0
+ field public static final int SOLID_NOT_COLORED = 1; // 0x1
+ }
+
public final class DnsEvent extends android.app.admin.NetworkEvent implements android.os.Parcelable {
method public String getHostname();
method public java.util.List<java.net.InetAddress> getInetAddresses();
@@ -15243,6 +15279,11 @@
public class BitmapShader extends android.graphics.Shader {
ctor public BitmapShader(@NonNull android.graphics.Bitmap, @NonNull android.graphics.Shader.TileMode, @NonNull android.graphics.Shader.TileMode);
+ method public int getFilterMode();
+ method public void setFilterMode(int);
+ field public static final int FILTER_MODE_DEFAULT = 0; // 0x0
+ field public static final int FILTER_MODE_LINEAR = 2; // 0x2
+ field public static final int FILTER_MODE_NEAREST = 1; // 0x1
}
public enum BlendMode {
@@ -16649,6 +16690,7 @@
method public void setFloatUniform(@NonNull String, float, float, float);
method public void setFloatUniform(@NonNull String, float, float, float, float);
method public void setFloatUniform(@NonNull String, @NonNull float[]);
+ method public void setInputBuffer(@NonNull String, @NonNull android.graphics.BitmapShader);
method public void setInputShader(@NonNull String, @NonNull android.graphics.Shader);
method public void setIntUniform(@NonNull String, int);
method public void setIntUniform(@NonNull String, int, int);
@@ -48188,6 +48230,18 @@
method @NonNull public android.graphics.Insets getWaterfallInsets();
}
+ public static final class DisplayCutout.Builder {
+ ctor public DisplayCutout.Builder();
+ method @NonNull public android.view.DisplayCutout build();
+ method @NonNull public android.view.DisplayCutout.Builder setBoundingRectBottom(@NonNull android.graphics.Rect);
+ method @NonNull public android.view.DisplayCutout.Builder setBoundingRectLeft(@NonNull android.graphics.Rect);
+ method @NonNull public android.view.DisplayCutout.Builder setBoundingRectRight(@NonNull android.graphics.Rect);
+ method @NonNull public android.view.DisplayCutout.Builder setBoundingRectTop(@NonNull android.graphics.Rect);
+ method @NonNull public android.view.DisplayCutout.Builder setCutoutPath(@NonNull android.graphics.Path);
+ method @NonNull public android.view.DisplayCutout.Builder setSafeInsets(@NonNull android.graphics.Insets);
+ method @NonNull public android.view.DisplayCutout.Builder setWaterfallInsets(@NonNull android.graphics.Insets);
+ }
+
public final class DragAndDropPermissions implements android.os.Parcelable {
method public int describeContents();
method public void release();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index d674507..800c8ab0 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -993,6 +993,18 @@
package android.app.admin {
+ public final class DevicePolicyDrawableResource implements android.os.Parcelable {
+ ctor public DevicePolicyDrawableResource(@NonNull android.content.Context, int, int, int, @DrawableRes int);
+ ctor public DevicePolicyDrawableResource(@NonNull android.content.Context, int, int, @DrawableRes int);
+ method public int describeContents();
+ method @DrawableRes public int getCallingPackageResourceId();
+ method public int getDrawableId();
+ method public int getDrawableSource();
+ method public int getDrawableStyle();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.app.admin.DevicePolicyDrawableResource> CREATOR;
+ }
+
public class DevicePolicyKeyguardService extends android.app.Service {
ctor public DevicePolicyKeyguardService();
method @Nullable public void dismiss();
@@ -1025,8 +1037,10 @@
method @RequiresPermission("android.permission.NOTIFY_PENDING_SYSTEM_UPDATE") public void notifyPendingSystemUpdate(long, boolean);
method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public boolean packageHasActiveAdmins(String);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void provisionFullyManagedDevice(@NonNull android.app.admin.FullyManagedDeviceProvisioningParams) throws android.app.admin.ProvisioningException;
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void resetDrawables(@NonNull int[]);
method @Deprecated @RequiresPermission(android.Manifest.permission.MANAGE_DEVICE_ADMINS) public boolean setActiveProfileOwner(@NonNull android.content.ComponentName, String) throws java.lang.IllegalArgumentException;
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setDeviceProvisioningConfigApplied();
+ method @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES) public void setDrawables(@NonNull java.util.Set<android.app.admin.DevicePolicyDrawableResource>);
method @Deprecated @RequiresPermission(value=android.Manifest.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS, conditional=true) public void setProfileOwnerCanAccessDeviceIds(@NonNull android.content.ComponentName);
method public void setSecondaryLockscreenEnabled(@NonNull android.content.ComponentName, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS) public void setUserProvisioningState(int, @NonNull android.os.UserHandle);
@@ -1058,6 +1072,7 @@
field public static final int CODE_USER_HAS_PROFILE_OWNER = 2; // 0x2
field public static final int CODE_USER_NOT_RUNNING = 3; // 0x3
field public static final int CODE_USER_SETUP_COMPLETED = 4; // 0x4
+ field public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER = "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
field public static final String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_ICON_URI";
field @Deprecated public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_LABEL";
@@ -1069,6 +1084,7 @@
field public static final String EXTRA_PROVISIONING_SUPPORT_URL = "android.app.extra.PROVISIONING_SUPPORT_URL";
field public static final String EXTRA_PROVISIONING_TRIGGER = "android.app.extra.PROVISIONING_TRIGGER";
field public static final String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
+ field public static final String EXTRA_ROLE_HOLDER_STATE = "android.app.extra.ROLE_HOLDER_STATE";
field public static final int FLAG_SUPPORTED_MODES_DEVICE_OWNER = 4; // 0x4
field public static final int FLAG_SUPPORTED_MODES_ORGANIZATION_OWNED = 1; // 0x1
field public static final int FLAG_SUPPORTED_MODES_PERSONALLY_OWNED = 2; // 0x2
@@ -1084,6 +1100,7 @@
field public static final int RESULT_DEVICE_OWNER_SET = 123; // 0x7b
field public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_RECOVERABLE_ERROR = 1; // 0x1
field public static final int RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR = 2; // 0x2
+ field public static final int RESULT_UPDATE_ROLE_HOLDER = 2; // 0x2
field public static final int RESULT_WORK_PROFILE_CREATED = 122; // 0x7a
field public static final int STATE_USER_PROFILE_COMPLETE = 4; // 0x4
field public static final int STATE_USER_PROFILE_FINALIZED = 5; // 0x5
@@ -8215,6 +8232,7 @@
public class TrafficStats {
method public static void setThreadStatsTagApp();
method public static void setThreadStatsTagBackup();
+ method public static void setThreadStatsTagDownload();
method public static void setThreadStatsTagRestore();
field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f
field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80
@@ -14051,14 +14069,21 @@
public class ImsService extends android.app.Service {
ctor public ImsService();
- method public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int);
- method public android.telephony.ims.feature.RcsFeature createRcsFeature(int);
- method public void disableIms(int);
- method public void enableIms(int);
- method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
+ method @Nullable public android.telephony.ims.feature.MmTelFeature createEmergencyOnlyMmTelFeature(int);
+ method @Deprecated public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int);
+ method @Nullable public android.telephony.ims.feature.MmTelFeature createMmTelFeatureForSubscription(int, int);
+ method @Deprecated public android.telephony.ims.feature.RcsFeature createRcsFeature(int);
+ method @Nullable public android.telephony.ims.feature.RcsFeature createRcsFeatureForSubscription(int, int);
+ method @Deprecated public void disableIms(int);
+ method public void disableImsForSubscription(int, int);
+ method @Deprecated public void enableIms(int);
+ method public void enableImsForSubscription(int, int);
+ method @Deprecated public android.telephony.ims.stub.ImsConfigImplBase getConfig(int);
+ method @NonNull public android.telephony.ims.stub.ImsConfigImplBase getConfigForSubscription(int, int);
method @NonNull public java.util.concurrent.Executor getExecutor();
method public long getImsServiceCapabilities();
- method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
+ method @Deprecated public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int);
+ method @NonNull public android.telephony.ims.stub.ImsRegistrationImplBase getRegistrationForSubscription(int, int);
method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int);
method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException;
method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures();
diff --git a/core/java/android/app/admin/DevicePolicyDrawableResource.aidl b/core/java/android/app/admin/DevicePolicyDrawableResource.aidl
new file mode 100644
index 0000000..6b73d981
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyDrawableResource.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+parcelable DevicePolicyDrawableResource;
diff --git a/core/java/android/app/admin/DevicePolicyDrawableResource.java b/core/java/android/app/admin/DevicePolicyDrawableResource.java
new file mode 100644
index 0000000..d32ff84
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyDrawableResource.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Used to pass in the required information for updating an enterprise drawable resource using
+ * {@link DevicePolicyManager#setDrawables}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class DevicePolicyDrawableResource implements Parcelable {
+ private final @DevicePolicyResources.UpdatableDrawableId int mDrawableId;
+ private final @DevicePolicyResources.UpdatableDrawableStyle int mDrawableStyle;
+ private final @DevicePolicyResources.UpdatableDrawableSource int mDrawableSource;
+ private final @DrawableRes int mCallingPackageResourceId;
+ @NonNull private ParcelableResource mResource;
+
+ /**
+ * Creates an object containing the required information for updating an enterprise drawable
+ * resource using {@link DevicePolicyManager#setDrawables}.
+ *
+ * <p>It will be used to update the drawable defined by {@code drawableId} with style
+ * {@code drawableStyle} located in source {@code drawableSource} to the drawable with ID
+ * {@code callingPackageResourceId} in the calling package</p>
+ *
+ * @param drawableId The ID of the drawable to update.
+ * @param drawableStyle The style of the drawable to update.
+ * @param drawableSource The source of the drawable to update.
+ * @param callingPackageResourceId The ID of the drawable resource in the calling package to
+ * use as an updated resource.
+ *
+ * @throws IllegalStateException if the resource with ID
+ * {@code callingPackageResourceId} doesn't exist in the {@code context} package.
+ */
+ public DevicePolicyDrawableResource(
+ @NonNull Context context,
+ @DevicePolicyResources.UpdatableDrawableId int drawableId,
+ @DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
+ @DevicePolicyResources.UpdatableDrawableSource int drawableSource,
+ @DrawableRes int callingPackageResourceId) {
+ this(drawableId, drawableStyle, drawableSource, callingPackageResourceId,
+ new ParcelableResource(context, callingPackageResourceId,
+ ParcelableResource.RESOURCE_TYPE_DRAWABLE));
+ }
+
+ private DevicePolicyDrawableResource(
+ @DevicePolicyResources.UpdatableDrawableId int drawableId,
+ @DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
+ @DevicePolicyResources.UpdatableDrawableSource int drawableSource,
+ @DrawableRes int callingPackageResourceId,
+ @NonNull ParcelableResource resource) {
+ this.mDrawableId = drawableId;
+ this.mDrawableStyle = drawableStyle;
+ this.mDrawableSource = drawableSource;
+ this.mCallingPackageResourceId = callingPackageResourceId;
+ this.mResource = resource;
+ }
+
+ /**
+ * Creates an object containing the required information for updating an enterprise drawable
+ * resource using {@link DevicePolicyManager#setDrawables}.
+ * <p>It will be used to update the drawable defined by {@code drawableId} with style
+ * {@code drawableStyle} to the drawable with ID {@code callingPackageResourceId} in the
+ * calling package</p>
+ *
+ * @param drawableId The ID of the drawable to update.
+ * @param drawableStyle The style of the drawable to update.
+ * @param callingPackageResourceId The ID of the drawable resource in the calling package to
+ * use as an updated resource.
+ *
+ * @throws IllegalStateException if the resource with ID
+ * {@code callingPackageResourceId} doesn't exist in the calling package.
+ */
+ public DevicePolicyDrawableResource(
+ @NonNull Context context,
+ @DevicePolicyResources.UpdatableDrawableId int drawableId,
+ @DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
+ @DrawableRes int callingPackageResourceId) {
+ this(context, drawableId, drawableStyle, DevicePolicyResources.Drawable.Source.UNDEFINED,
+ callingPackageResourceId);
+ }
+
+ /**
+ * Returns the ID of the drawable to update.
+ */
+ @DevicePolicyResources.UpdatableDrawableId
+ public int getDrawableId() {
+ return mDrawableId;
+ }
+
+ /**
+ * Returns the style of the drawable to update
+ */
+ @DevicePolicyResources.UpdatableDrawableStyle
+ public int getDrawableStyle() {
+ return mDrawableStyle;
+ }
+
+ /**
+ * Returns the source of the drawable to update.
+ */
+ @DevicePolicyResources.UpdatableDrawableSource
+ public int getDrawableSource() {
+ return mDrawableSource;
+ }
+
+ /**
+ * Returns the ID of the drawable resource in the calling package to use as an updated
+ * resource.
+ */
+ @DrawableRes
+ public int getCallingPackageResourceId() {
+ return mCallingPackageResourceId;
+ }
+
+ /**
+ * Returns the {@link ParcelableResource} of the drawable.
+ *
+ * @hide
+ */
+ @NonNull
+ public ParcelableResource getResource() {
+ return mResource;
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DevicePolicyDrawableResource other = (DevicePolicyDrawableResource) o;
+ return mDrawableId == other.mDrawableId
+ && mDrawableStyle == other.mDrawableStyle
+ && mDrawableSource == other.mDrawableSource
+ && mCallingPackageResourceId == other.mCallingPackageResourceId
+ && mResource.equals(other.mResource);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ mDrawableId, mDrawableStyle, mDrawableSource, mCallingPackageResourceId, mResource);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mDrawableId);
+ dest.writeInt(mDrawableStyle);
+ dest.writeInt(mDrawableSource);
+ dest.writeInt(mCallingPackageResourceId);
+ dest.writeTypedObject(mResource, flags);
+ }
+
+ public static final @NonNull Creator<DevicePolicyDrawableResource> CREATOR =
+ new Creator<DevicePolicyDrawableResource>() {
+ @Override
+ public DevicePolicyDrawableResource createFromParcel(Parcel in) {
+ int drawableId = in.readInt();
+ int drawableStyle = in.readInt();
+ int drawableSource = in.readInt();
+ int callingPackageResourceId = in.readInt();
+ ParcelableResource resource = in.readTypedObject(ParcelableResource.CREATOR);
+
+ return new DevicePolicyDrawableResource(
+ drawableId, drawableStyle, drawableSource, callingPackageResourceId,
+ resource);
+ }
+
+ @Override
+ public DevicePolicyDrawableResource[] newArray(int size) {
+ return new DevicePolicyDrawableResource[size];
+ }
+ };
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a60de08..2bfb938e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -16,6 +16,9 @@
package android.app.admin;
+import static android.app.admin.DevicePolicyResources.Drawable.INVALID_ID;
+import static android.app.admin.DevicePolicyResources.Drawable.Source.UNDEFINED;
+
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.Manifest.permission;
@@ -52,7 +55,9 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
+import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.drawable.Drawable;
import android.net.PrivateDnsConnectivityChecker;
import android.net.ProxyInfo;
import android.net.Uri;
@@ -89,6 +94,7 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.DebugUtils;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Pair;
@@ -123,6 +129,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
@@ -480,6 +487,10 @@
*
* <p>Device management role holders are required to have a handler for this intent action.
*
+ * <p>If {@link #EXTRA_ROLE_HOLDER_STATE} is supplied to this intent, it is the responsibility
+ * of the role holder to restore its state from this extra. This is the same {@link Bundle}
+ * which the role holder returns alongside {@link #RESULT_UPDATE_ROLE_HOLDER}.
+ *
* <p>A result code of {@link Activity#RESULT_OK} implies that managed profile provisioning
* finished successfully. If it did not, a result code of {@link Activity#RESULT_CANCELED}
* is used instead.
@@ -527,6 +538,10 @@
*
* <p>Device management role holders are required to have a handler for this intent action.
*
+ * <p>If {@link #EXTRA_ROLE_HOLDER_STATE} is supplied to this intent, it is the responsibility
+ * of the role holder to restore its state from this extra. This is the same {@link Bundle}
+ * which the role holder returns alongside {@link #RESULT_UPDATE_ROLE_HOLDER}.
+ *
* <p>The result codes can be either {@link #RESULT_WORK_PROFILE_CREATED}, {@link
* #RESULT_DEVICE_OWNER_SET} or {@link Activity#RESULT_CANCELED} if provisioning failed.
*
@@ -566,6 +581,47 @@
"android.app.action.ROLE_HOLDER_PROVISION_FINALIZATION";
/**
+ * {@link Activity} result code which can be returned by {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE} and {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} to signal that an update
+ * to the role holder is required.
+ *
+ * <p>This result code must be accompanied by {@link #EXTRA_ROLE_HOLDER_STATE}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int RESULT_UPDATE_ROLE_HOLDER = 2;
+
+ /**
+ * A {@link Bundle} extra which describes the state of the role holder at the time when it
+ * returns {@link #RESULT_UPDATE_ROLE_HOLDER}.
+ *
+ * <p>After the update completes, the role holder's {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_PROFILE} or {@link
+ * #ACTION_ROLE_HOLDER_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE} intent will be relaunched,
+ * which will contain this extra. It is the role holder's responsibility to restore its
+ * state from this extra.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_ROLE_HOLDER_STATE = "android.app.extra.ROLE_HOLDER_STATE";
+
+ /**
+ * A {@code boolean} extra which determines whether to force a role holder update, regardless
+ * of any internal conditions {@link #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER} might have.
+ *
+ * <p>This extra can be provided to intents with action {@link
+ * #ACTION_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER}.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_FORCE_UPDATE_ROLE_HOLDER =
+ "android.app.extra.FORCE_UPDATE_ROLE_HOLDER";
+
+ /**
* Action: Bugreport sharing with device owner has been accepted by the user.
*
* @hide
@@ -2854,6 +2910,9 @@
* #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR} if it encounters a problem
* that will not be solved by relaunching it again.
*
+ * <p>If this activity has additional internal conditions which are not met, it should return
+ * {@link #RESULT_UPDATE_DEVICE_MANAGEMENT_ROLE_HOLDER_UNRECOVERABLE_ERROR}.
+ *
* @hide
*/
@RequiresPermission(android.Manifest.permission.LAUNCH_DEVICE_MANAGER_SETUP)
@@ -3181,6 +3240,36 @@
*/
public static final int OPERATION_SAFETY_REASON_DRIVING_DISTRACTION = 1;
+ /**
+ * Broadcast action: notify system apps (e.g. settings, SysUI, etc) that the device management
+ * resources with IDs {@link #EXTRA_RESOURCE_ID} has been updated using, the updated resources
+ * can be retrieved using {@link #getDrawable}.
+ *
+ * <p>This broadcast is sent to registered receivers only.
+ *
+ * <p> The following extras will be included to identify the type of resource being updated:
+ * <ul>
+ * <li>{@link #EXTRA_RESOURCE_TYPE_DRAWABLE} for drawable resources</li>
+ * </ul>
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_DEVICE_POLICY_RESOURCE_UPDATED =
+ "android.app.action.DEVICE_POLICY_RESOURCE_UPDATED";
+
+ /**
+ * A boolean extra for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to indicate that a
+ * resource of type {@link Drawable} is being updated.
+ */
+ public static final String EXTRA_RESOURCE_TYPE_DRAWABLE =
+ "android.app.extra.RESOURCE_TYPE_DRAWABLE";
+
+ /**
+ * An integer array extra for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to indicate which
+ * drawable IDs (see {@link DevicePolicyResources.UpdatableDrawableId}) have been updated.
+ */
+ public static final String EXTRA_RESOURCE_ID =
+ "android.app.extra.RESOURCE_ID";
+
/** @hide */
@NonNull
@TestApi
@@ -14372,4 +14461,243 @@
public Intent createProvisioningIntentFromNfcIntent(@NonNull Intent nfcIntent) {
return ProvisioningIntentHelper.createProvisioningIntentFromNfcIntent(nfcIntent);
}
+
+ /**
+ * For each {@link DevicePolicyDrawableResource} item in {@code drawables}, if
+ * {@link DevicePolicyDrawableResource#getDrawableSource()} is not set or is set to
+ * {@link DevicePolicyResources.Drawable.Source#UNDEFINED}, it updates the drawable resource for
+ * the combination of {@link DevicePolicyDrawableResource#getDrawableId()} and
+ * {@link DevicePolicyDrawableResource#getDrawableStyle()}, (see
+ * {@link DevicePolicyResources.Drawable} and {@link DevicePolicyResources.Drawable.Style}) to
+ * the drawable with ID {@link DevicePolicyDrawableResource#getCallingPackageResourceId()},
+ * meaning any system UI surface calling {@link #getDrawable}
+ * with {@code drawableId} and {@code drawableStyle} will get the new resource after this API
+ * is called.
+ *
+ * <p>Otherwise, if {@link DevicePolicyDrawableResource#getDrawableSource()} is set (see
+ * {@link DevicePolicyResources.Drawable.Source}, it overrides any drawables that was set for
+ * the same {@code drawableId} and {@code drawableStyle} for the provided source.
+ *
+ * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
+ * registered receivers when a resource has been updated successfully.
+ *
+ * <p>Important notes to consider when using this API:
+ * <ul>
+ * <li>{@link #getDrawable} references the resource
+ * {@link DevicePolicyDrawableResource#getCallingPackageResourceId()} in the
+ * calling package each time it gets called. You have to ensure that the resource is always
+ * available in the calling package as long as it is used as an updated resource.
+ * <li>You still have to re-call {@code setDrawables} even if you only make changes to the
+ * content of the resource with ID
+ * {@link DevicePolicyDrawableResource#getCallingPackageResourceId()} as the content might be
+ * cached and would need updating.
+ * </ul>
+ *
+ * @param drawables The list of {@link DevicePolicyDrawableResource} to update.
+ *
+ * @throws IllegalArgumentException if {@link DevicePolicyDrawableResource#getDrawableId()},
+ * {@link DevicePolicyDrawableResource#getDrawableStyle()}, or
+ * {@link DevicePolicyDrawableResource#getDrawableSource()} aren't defined in
+ * {@link DevicePolicyResources.Drawable}.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+ public void setDrawables(@NonNull Set<DevicePolicyDrawableResource> drawables) {
+ if (mService != null) {
+ try {
+ mService.setDrawables(new ArrayList<>(drawables));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Removes all updated drawables for the list of {@code drawableIds} (see
+ * {@link DevicePolicyResources.Drawable} that was previously set by calling
+ * {@link #setDrawables}, meaning any subsequent calls to {@link #getDrawable} for the provided
+ * IDs with any {@link DevicePolicyResources.Drawable.Style} and any
+ * {@link DevicePolicyResources.Drawable.Source} will return the default drawable from
+ * {@code defaultDrawableLoader}.
+ *
+ * <p>Sends a broadcast with action {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to
+ * registered receivers when a resource has been reset successfully.
+ *
+ * @param drawableIds The list of IDs to remove.
+ *
+ * @throws IllegalArgumentException if IDs are not defined in
+ * {@link DevicePolicyResources.Drawable}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES)
+ public void resetDrawables(@NonNull int[] drawableIds) {
+ if (mService != null) {
+ try {
+ mService.resetDrawables(drawableIds);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
+ /**
+ * Returns the appropriate updated drawable for the {@code drawableId}
+ * (see {@link DevicePolicyResources.Drawable}), with style {@code drawableStyle}
+ * (see {@link DevicePolicyResources.Drawable.Style}) if one was set using
+ * {@code setDrawables}, otherwise returns the drawable from {@code defaultDrawableLoader}.
+ *
+ * <p>Also returns the drawable from {@code defaultDrawableLoader} if
+ * {@link DevicePolicyResources.Drawable#INVALID_ID} was passed.
+ *
+ * <p>This API uses the screen density returned from {@link Resources#getConfiguration()}, to
+ * set a different value use
+ * {@link #getDrawableForDensity(int, int, int, Callable)}.
+ *
+ * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
+ * notified when a resource has been updated.
+ *
+ * <p>Note that each call to this API loads the resource from the package that called
+ * {@code setDrawables} to set the updated resource.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+ * the provided params.
+ */
+ @Nullable
+ public Drawable getDrawable(
+ @DevicePolicyResources.UpdatableDrawableId int drawableId,
+ @DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
+ @NonNull Callable<Drawable> defaultDrawableLoader) {
+ return getDrawable(drawableId, drawableStyle, UNDEFINED, defaultDrawableLoader);
+ }
+
+ /**
+ * Similar to {@link #getDrawable(int, int, Callable)}, but also accepts
+ * a {@code drawableSource} (see {@link DevicePolicyResources.Drawable.Source}) which
+ * could result in returning a different drawable than {@link #getDrawable(int, int, Callable)}
+ * if an override was set for that specific source.
+ *
+ * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
+ * notified when a resource has been updated.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param drawableSource The source for the caller.
+ * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+ * the provided params.
+ */
+ @Nullable
+ public Drawable getDrawable(
+ @DevicePolicyResources.UpdatableDrawableId int drawableId,
+ @DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
+ @DevicePolicyResources.UpdatableDrawableSource int drawableSource,
+ @NonNull Callable<Drawable> defaultDrawableLoader) {
+ Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
+ if (drawableId == INVALID_ID) {
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+ if (mService != null) {
+ try {
+ ParcelableResource resource = mService.getDrawable(
+ drawableId, drawableStyle, drawableSource);
+ if (resource == null) {
+ return ParcelableResource.loadDefaultDrawable(
+ defaultDrawableLoader);
+ }
+ return resource.getDrawable(
+ mContext,
+ /* density= */ 0,
+ defaultDrawableLoader);
+
+ } catch (RemoteException e) {
+ Log.e(
+ TAG,
+ "Error getting the updated drawable from DevicePolicyManagerService.",
+ e);
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+ }
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+
+ /**
+ * Similar to {@link #getDrawable(int, int, Callable)}, but also accepts
+ * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
+ *
+ * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
+ * notified when a resource has been updated.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param density The desired screen density indicated by the resource as
+ * found in {@link DisplayMetrics}. A value of 0 means to use the
+ * density returned from {@link Resources#getConfiguration()}.
+ * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+ * the provided params.
+ */
+ @Nullable
+ public Drawable getDrawableForDensity(
+ @DevicePolicyResources.UpdatableDrawableId int drawableId,
+ @DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
+ int density,
+ @NonNull Callable<Drawable> defaultDrawableLoader) {
+ return getDrawableForDensity(
+ drawableId,
+ drawableStyle,
+ UNDEFINED,
+ density,
+ defaultDrawableLoader);
+ }
+
+ /**
+ * Similar to {@link #getDrawable(int, int, int, Callable)}, but also accepts
+ * {@code density}. See {@link Resources#getDrawableForDensity(int, int, Resources.Theme)}.
+ *
+ * <p>Callers should register for {@link #ACTION_DEVICE_POLICY_RESOURCE_UPDATED} to get
+ * notified when a resource has been updated.
+ *
+ * @param drawableId The drawable ID to get the updated resource for.
+ * @param drawableStyle The drawable style to use.
+ * @param drawableSource The source for the caller.
+ * @param density The desired screen density indicated by the resource as
+ * found in {@link DisplayMetrics}. A value of 0 means to use the
+ * density returned from {@link Resources#getConfiguration()}.
+ * @param defaultDrawableLoader To get the default drawable if no updated drawable was set for
+ * the provided params.
+ */
+ @Nullable
+ public Drawable getDrawableForDensity(
+ @DevicePolicyResources.UpdatableDrawableId int drawableId,
+ @DevicePolicyResources.UpdatableDrawableStyle int drawableStyle,
+ @DevicePolicyResources.UpdatableDrawableSource int drawableSource,
+ int density,
+ @NonNull Callable<Drawable> defaultDrawableLoader) {
+ Objects.requireNonNull(defaultDrawableLoader, "defaultDrawableLoader can't be null");
+ if (drawableId == INVALID_ID) {
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+ if (mService != null) {
+ try {
+ ParcelableResource resource = mService.getDrawable(
+ drawableId, drawableStyle, drawableSource);
+ if (resource == null) {
+ return ParcelableResource.loadDefaultDrawable(
+ defaultDrawableLoader);
+ }
+ return resource.getDrawable(mContext, density, defaultDrawableLoader);
+ } catch (RemoteException e) {
+ Log.e(
+ TAG,
+ "Error getting the updated drawable from DevicePolicyManagerService.",
+ e);
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
+ }
+ return ParcelableResource.loadDefaultDrawable(defaultDrawableLoader);
+ }
}
diff --git a/core/java/android/app/admin/DevicePolicyResources.java b/core/java/android/app/admin/DevicePolicyResources.java
new file mode 100644
index 0000000..5133f26
--- /dev/null
+++ b/core/java/android/app/admin/DevicePolicyResources.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import android.annotation.IntDef;
+import android.annotation.SuppressLint;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Class containing the required identifiers to update device management resources.
+ *
+ * <p>See {@link DevicePolicyManager#getDrawable}.
+ *
+ */
+public final class DevicePolicyResources {
+
+ /**
+ * Resource identifiers used to update device management-related system drawable resources.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ Drawable.INVALID_ID,
+ Drawable.WORK_PROFILE_ICON_BADGE,
+ Drawable.WORK_PROFILE_ICON,
+ Drawable.WORK_PROFILE_OFF_ICON,
+ Drawable.WORK_PROFILE_USER_ICON
+ })
+ public @interface UpdatableDrawableId {}
+
+ /**
+ * Identifiers to specify the desired style for the updatable device management system
+ * resource.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ Drawable.Style.SOLID_COLORED,
+ Drawable.Style.SOLID_NOT_COLORED,
+ Drawable.Style.OUTLINE,
+ })
+ public @interface UpdatableDrawableStyle {}
+
+ /**
+ * Identifiers to specify the location if the updatable device management system resource.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ Drawable.Source.UNDEFINED,
+ Drawable.Source.NOTIFICATION,
+ Drawable.Source.PROFILE_SWITCH_ANIMATION,
+ Drawable.Source.HOME_WIDGET,
+ Drawable.Source.LAUNCHER_OFF_BUTTON,
+ Drawable.Source.QUICK_SETTINGS,
+ Drawable.Source.STATUS_BAR
+ })
+ public @interface UpdatableDrawableSource {}
+
+
+ /**
+ * Class containing the identifiers used to update device management-related system drawable.
+ */
+ public static final class Drawable {
+
+ private Drawable() {
+ }
+
+ /**
+ * An ID for any drawable that can't be updated.
+ */
+ public static final int INVALID_ID = -1;
+
+ /**
+ * Specifically used to badge work profile app icons.
+ */
+ public static final int WORK_PROFILE_ICON_BADGE = 0;
+
+ /**
+ * General purpose work profile icon (i.e. generic icon badging). For badging app icons
+ * specifically, see {@link #WORK_PROFILE_ICON_BADGE}.
+ */
+ public static final int WORK_PROFILE_ICON = 1;
+
+ /**
+ * General purpose icon representing the work profile off state.
+ */
+ public static final int WORK_PROFILE_OFF_ICON = 2;
+
+ /**
+ * General purpose icon for the work profile user avatar.
+ */
+ public static final int WORK_PROFILE_USER_ICON = 3;
+
+ /**
+ * @hide
+ */
+ public static final Set<Integer> UPDATABLE_DRAWABLE_IDS = buildDrawablesSet();
+
+ private static Set<Integer> buildDrawablesSet() {
+ Set<Integer> drawables = new HashSet<>();
+ drawables.add(WORK_PROFILE_ICON_BADGE);
+ drawables.add(WORK_PROFILE_ICON);
+ drawables.add(WORK_PROFILE_OFF_ICON);
+ drawables.add(WORK_PROFILE_USER_ICON);
+ return drawables;
+ }
+
+ /**
+ * Class containing the source identifiers used to update device management-related system
+ * drawable.
+ */
+ public static final class Source {
+
+ private Source() {
+ }
+
+ /**
+ * A source identifier indicating that the updatable resource is used in a generic
+ * undefined location.
+ */
+ public static final int UNDEFINED = -1;
+
+ /**
+ * A source identifier indicating that the updatable drawable is used in notifications.
+ */
+ public static final int NOTIFICATION = 0;
+
+ /**
+ * A source identifier indicating that the updatable drawable is used in a cross
+ * profile switching animation.
+ */
+ public static final int PROFILE_SWITCH_ANIMATION = 1;
+
+ /**
+ * A source identifier indicating that the updatable drawable is used in a work
+ * profile home screen widget.
+ */
+ public static final int HOME_WIDGET = 2;
+
+ /**
+ * A source identifier indicating that the updatable drawable is used in the launcher
+ * turn off work button.
+ */
+ public static final int LAUNCHER_OFF_BUTTON = 3;
+
+ /**
+ * A source identifier indicating that the updatable drawable is used in quick settings.
+ */
+ public static final int QUICK_SETTINGS = 4;
+
+ /**
+ * A source identifier indicating that the updatable drawable is used in the status bar.
+ */
+ public static final int STATUS_BAR = 5;
+
+ /**
+ * @hide
+ */
+ public static final Set<Integer> UPDATABLE_DRAWABLE_SOURCES = buildSourcesSet();
+
+ private static Set<Integer> buildSourcesSet() {
+ Set<Integer> sources = new HashSet<>();
+ sources.add(UNDEFINED);
+ sources.add(NOTIFICATION);
+ sources.add(PROFILE_SWITCH_ANIMATION);
+ sources.add(HOME_WIDGET);
+ sources.add(LAUNCHER_OFF_BUTTON);
+ sources.add(QUICK_SETTINGS);
+ sources.add(STATUS_BAR);
+ return sources;
+ }
+ }
+
+ /**
+ * Class containing the style identifiers used to update device management-related system
+ * drawable.
+ */
+ @SuppressLint("StaticUtils")
+ public static final class Style {
+
+ private Style() {
+ }
+
+ /**
+ * A style identifier indicating that the updatable drawable should use the default
+ * style.
+ */
+ public static final int DEFAULT = -1;
+
+ /**
+ * A style identifier indicating that the updatable drawable has a solid color fill.
+ */
+ public static final int SOLID_COLORED = 0;
+
+ /**
+ * A style identifier indicating that the updatable drawable has a solid non-colored
+ * fill.
+ */
+ public static final int SOLID_NOT_COLORED = 1;
+
+ /**
+ * A style identifier indicating that the updatable drawable is an outline.
+ */
+ public static final int OUTLINE = 2;
+
+ /**
+ * @hide
+ */
+ public static final Set<Integer> UPDATABLE_DRAWABLE_STYLES = buildStylesSet();
+
+ private static Set<Integer> buildStylesSet() {
+ Set<Integer> styles = new HashSet<>();
+ styles.add(DEFAULT);
+ styles.add(SOLID_COLORED);
+ styles.add(SOLID_NOT_COLORED);
+ styles.add(OUTLINE);
+ return styles;
+ }
+ }
+ }
+}
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index b9fcdf5..8320087 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -17,6 +17,8 @@
package android.app.admin;
+import android.app.admin.DevicePolicyDrawableResource;
+import android.app.admin.ParcelableResource;
import android.app.admin.NetworkEvent;
import android.app.IApplicationThread;
import android.app.IServiceConnection;
@@ -531,4 +533,7 @@
boolean canUsbDataSignalingBeDisabled();
List<UserHandle> listForegroundAffiliatedUsers();
+ void setDrawables(in List<DevicePolicyDrawableResource> resource);
+ void resetDrawables(in int[] drawableIds);
+ ParcelableResource getDrawable(int drawableId, int drawableStyle, int drawableSource);
}
diff --git a/core/java/android/app/admin/ParcelableResource.aidl b/core/java/android/app/admin/ParcelableResource.aidl
new file mode 100644
index 0000000..dd2b975
--- /dev/null
+++ b/core/java/android/app/admin/ParcelableResource.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+parcelable ParcelableResource;
diff --git a/core/java/android/app/admin/ParcelableResource.java b/core/java/android/app/admin/ParcelableResource.java
new file mode 100644
index 0000000..e517162
--- /dev/null
+++ b/core/java/android/app/admin/ParcelableResource.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.admin;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.AnyRes;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Slog;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.concurrent.Callable;
+
+/**
+ * Used to store the required information to load a resource that was updated using
+ * {@link DevicePolicyManager#setDrawables}.
+ *
+ * @hide
+ */
+public final class ParcelableResource implements Parcelable {
+
+ private static String TAG = "DevicePolicyManager";
+
+ private static final String ATTR_RESOURCE_ID = "resource-id";
+ private static final String ATTR_PACKAGE_NAME = "package-name";
+ private static final String ATTR_RESOURCE_NAME = "resource-name";
+ private static final String ATTR_RESOURCE_TYPE = "resource-type";
+
+ public static final int RESOURCE_TYPE_DRAWABLE = 1;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "RESOURCE_TYPE_" }, value = {
+ RESOURCE_TYPE_DRAWABLE
+ })
+ public @interface ResourceType {}
+
+ private final int mResourceId;
+ @NonNull private final String mPackageName;
+ @NonNull private final String mResourceName;
+ private final int mResourceType;
+
+ /**
+ *
+ * Creates a {@code ParcelableDevicePolicyResource} for the given {@code resourceId} and
+ * verifies that it exists in the package of the given {@code context}.
+ *
+ * @param context for the package containing the {@code resourceId} to use as the updated
+ * resource
+ * @param resourceId of the resource to use as an updated resource
+ * @param resourceType see {@link ResourceType}
+ * @throws IllegalArgumentException if the given {@code resourceId} doesn't exist in the
+ * {@link Context#getResources()} of the given {@code context}
+ */
+ public ParcelableResource(@NonNull Context context, @AnyRes int resourceId,
+ @ResourceType int resourceType) throws IllegalArgumentException {
+ Objects.requireNonNull(context, "context must be provided");
+
+ verifyResourceExistsInCallingPackage(context, resourceId, resourceType);
+
+ this.mResourceId = resourceId;
+ this.mPackageName = context.getResources().getResourcePackageName(resourceId);
+ this.mResourceName = context.getResources().getResourceName(resourceId);
+ this.mResourceType = resourceType;
+ }
+
+ /**
+ * Creates a {@code ParcelableDevicePolicyResource} with the given params, this DOES NOT make
+ * any verifications on whether the given {@code resourceId} actually exists.
+ */
+ private ParcelableResource(
+ @AnyRes int resourceId, @NonNull String packageName, @NonNull String resourceName,
+ @ResourceType int resourceType) {
+ this.mResourceId = resourceId;
+ this.mPackageName = requireNonNull(packageName);
+ this.mResourceName = requireNonNull(resourceName);
+ this.mResourceType = resourceType;
+ }
+
+ private static void verifyResourceExistsInCallingPackage(
+ Context context, @AnyRes int resourceId, @ResourceType int resourceType)
+ throws IllegalArgumentException {
+ switch (resourceType) {
+ case RESOURCE_TYPE_DRAWABLE:
+ if (!hasDrawableInCallingPackage(context, resourceId)) {
+ throw new IllegalArgumentException(String.format(
+ "Drawable with id %d doesn't exist in the calling package %s",
+ resourceId,
+ context.getPackageName()));
+ }
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown ParcelableDevicePolicyResourceType: " + resourceType);
+ }
+ }
+
+ private static boolean hasDrawableInCallingPackage(Context context, @AnyRes int resourceId) {
+ try {
+ return context.getDrawable(resourceId) != null;
+ } catch (Resources.NotFoundException e) {
+ return false;
+ }
+ }
+
+ public @AnyRes int getResourceId() {
+ return mResourceId;
+ }
+
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @NonNull
+ public String getResourceName() {
+ return mResourceName;
+ }
+
+ public int getResourceType() {
+ return mResourceType;
+ }
+
+ /**
+ * Loads the drawable with id {@code mResourceId} from {@code mPackageName} using the provided
+ * {@code density} and {@link Resources.Theme} and {@link Resources#getConfiguration} of the
+ * provided {@code context}.
+ *
+ * <p>Returns the default drawable by calling the {@code defaultDrawableLoader} if the updated
+ * drawable was not found or could not be loaded.</p>
+ */
+ @Nullable
+ public Drawable getDrawable(
+ Context context,
+ int density,
+ @NonNull Callable<Drawable> defaultDrawableLoader) {
+ // TODO(b/203548565): properly handle edge case when the device manager role holder is
+ // unavailable because it's being updated.
+ try {
+ Resources resources = getAppResourcesWithCallersConfiguration(context);
+ verifyResourceName(resources);
+ return resources.getDrawableForDensity(mResourceId, density, context.getTheme());
+ } catch (PackageManager.NameNotFoundException | RuntimeException e) {
+ Slog.e(TAG, "Unable to load drawable resource " + mResourceName, e);
+ return loadDefaultDrawable(defaultDrawableLoader);
+ }
+ }
+
+ private Resources getAppResourcesWithCallersConfiguration(Context context)
+ throws PackageManager.NameNotFoundException {
+ PackageManager pm = context.getPackageManager();
+ ApplicationInfo ai = pm.getApplicationInfo(
+ mPackageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES
+ | PackageManager.GET_SHARED_LIBRARY_FILES);
+ return pm.getResourcesForApplication(ai, context.getResources().getConfiguration());
+ }
+
+ private void verifyResourceName(Resources resources) throws IllegalStateException {
+ String name = resources.getResourceName(mResourceId);
+ if (!mResourceName.equals(name)) {
+ throw new IllegalStateException(String.format("Current resource name %s for resource id"
+ + " %d has changed from the previously stored resource name %s.",
+ name, mResourceId, mResourceName));
+ }
+ }
+
+ /**
+ * returns the {@link Drawable} loaded from calling
+ * {@code defaultDrawableLoader}.
+ */
+ public static Drawable loadDefaultDrawable(
+ @NonNull Callable<Drawable> defaultDrawableLoader) {
+ try {
+ return defaultDrawableLoader.call();
+ } catch (Exception e) {
+ throw new RuntimeException("Couldn't load default drawable", e);
+ }
+ }
+
+ /**
+ * Writes the content of the current {@code ParcelableDevicePolicyResource} to the xml file
+ * specified by {@code xmlSerializer}.
+ */
+ public void writeToXmlFile(TypedXmlSerializer xmlSerializer) throws IOException {
+ xmlSerializer.attributeInt(/* namespace= */ null, ATTR_RESOURCE_ID, mResourceId);
+ xmlSerializer.attribute(/* namespace= */ null, ATTR_PACKAGE_NAME, mPackageName);
+ xmlSerializer.attribute(/* namespace= */ null, ATTR_RESOURCE_NAME, mResourceName);
+ xmlSerializer.attributeInt(/* namespace= */ null, ATTR_RESOURCE_TYPE, mResourceType);
+ }
+
+ /**
+ * Creates a new {@code ParcelableDevicePolicyResource} using the content of
+ * {@code xmlPullParser}.
+ */
+ public static ParcelableResource createFromXml(TypedXmlPullParser xmlPullParser)
+ throws XmlPullParserException, IOException {
+ int resourceId = xmlPullParser.getAttributeInt(/* namespace= */ null, ATTR_RESOURCE_ID);
+ String packageName = xmlPullParser.getAttributeValue(
+ /* namespace= */ null, ATTR_PACKAGE_NAME);
+ String resourceName = xmlPullParser.getAttributeValue(
+ /* namespace= */ null, ATTR_RESOURCE_NAME);
+ int resourceType = xmlPullParser.getAttributeInt(
+ /* namespace= */ null, ATTR_RESOURCE_TYPE);
+
+ return new ParcelableResource(
+ resourceId, packageName, resourceName, resourceType);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ParcelableResource other = (ParcelableResource) o;
+ return mResourceId == other.mResourceId
+ && mPackageName.equals(other.mPackageName)
+ && mResourceName.equals(other.mResourceName)
+ && mResourceType == other.mResourceType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mResourceId, mPackageName, mResourceName, mResourceType);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mResourceId);
+ dest.writeString(mPackageName);
+ dest.writeString(mResourceName);
+ dest.writeInt(mResourceType);
+ }
+
+ public static final @NonNull Creator<ParcelableResource> CREATOR =
+ new Creator<ParcelableResource>() {
+ @Override
+ public ParcelableResource createFromParcel(Parcel in) {
+ int resourceId = in.readInt();
+ String packageName = in.readString();
+ String resourceName = in.readString();
+ int resourceType = in.readInt();
+
+ return new ParcelableResource(
+ resourceId, packageName, resourceName, resourceType);
+ }
+
+ @Override
+ public ParcelableResource[] newArray(int size) {
+ return new ParcelableResource[size];
+ }
+ };
+}
diff --git a/core/java/android/bluetooth/Attributable.java b/core/java/android/bluetooth/Attributable.java
deleted file mode 100644
index d9acbe3..0000000
--- a/core/java/android/bluetooth/Attributable.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.AttributionSource;
-
-import java.util.List;
-
-/**
- * Marker interface for a class which can have an {@link AttributionSource}
- * assigned to it; these are typically {@link android.os.Parcelable} classes
- * which need to be updated after crossing Binder transaction boundaries.
- *
- * @hide
- */
-public interface Attributable {
- void setAttributionSource(@NonNull AttributionSource attributionSource);
-
- static @Nullable <T extends Attributable> T setAttributionSource(
- @Nullable T attributable,
- @NonNull AttributionSource attributionSource) {
- if (attributable != null) {
- attributable.setAttributionSource(attributionSource);
- }
- return attributable;
- }
-
- static @Nullable <T extends Attributable> List<T> setAttributionSource(
- @Nullable List<T> attributableList,
- @NonNull AttributionSource attributionSource) {
- if (attributableList != null) {
- final int size = attributableList.size();
- for (int i = 0; i < size; i++) {
- setAttributionSource(attributableList.get(i), attributionSource);
- }
- }
- return attributableList;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
deleted file mode 100644
index 8b9cec1..0000000
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ /dev/null
@@ -1,1149 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.ParcelUuid;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-
-/**
- * This class provides the public APIs to control the Bluetooth A2DP
- * profile.
- *
- * <p>BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothA2dp proxy object.
- *
- * <p> Android only supports one connected Bluetooth A2dp device at a time.
- * Each method is protected with its appropriate permission.
- */
-public final class BluetoothA2dp implements BluetoothProfile {
- private static final String TAG = "BluetoothA2dp";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the A2DP
- * profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.a2dp.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * Intent used to broadcast the change in the Playing state of the A2DP
- * profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_PLAYING}, {@link #STATE_NOT_PLAYING},
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PLAYING_STATE_CHANGED =
- "android.bluetooth.a2dp.profile.action.PLAYING_STATE_CHANGED";
-
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_AVRCP_CONNECTION_STATE_CHANGED =
- "android.bluetooth.a2dp.profile.action.AVRCP_CONNECTION_STATE_CHANGED";
-
- /**
- * Intent used to broadcast the selection of a connected device as active.
- *
- * <p>This intent will have one extra:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
- * be null if no device is active. </li>
- * </ul>
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage(trackingBug = 171933273)
- public static final String ACTION_ACTIVE_DEVICE_CHANGED =
- "android.bluetooth.a2dp.profile.action.ACTIVE_DEVICE_CHANGED";
-
- /**
- * Intent used to broadcast the change in the Audio Codec state of the
- * A2DP Source profile.
- *
- * <p>This intent will have 2 extras:
- * <ul>
- * <li> {@link BluetoothCodecStatus#EXTRA_CODEC_STATUS} - The codec status. </li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device if the device is currently
- * connected, otherwise it is not included.</li>
- * </ul>
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage(trackingBug = 181103983)
- public static final String ACTION_CODEC_CONFIG_CHANGED =
- "android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED";
-
- /**
- * A2DP sink device is streaming music. This state can be one of
- * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
- * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
- */
- public static final int STATE_PLAYING = 10;
-
- /**
- * A2DP sink device is NOT streaming music. This state can be one of
- * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
- * {@link #ACTION_PLAYING_STATE_CHANGED} intent.
- */
- public static final int STATE_NOT_PLAYING = 11;
-
- /** @hide */
- @IntDef(prefix = "OPTIONAL_CODECS_", value = {
- OPTIONAL_CODECS_SUPPORT_UNKNOWN,
- OPTIONAL_CODECS_NOT_SUPPORTED,
- OPTIONAL_CODECS_SUPPORTED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface OptionalCodecsSupportStatus {}
-
- /**
- * We don't have a stored preference for whether or not the given A2DP sink device supports
- * optional codecs.
- *
- * @hide
- */
- @SystemApi
- public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1;
-
- /**
- * The given A2DP sink device does not support optional codecs.
- *
- * @hide
- */
- @SystemApi
- public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0;
-
- /**
- * The given A2DP sink device does support optional codecs.
- *
- * @hide
- */
- @SystemApi
- public static final int OPTIONAL_CODECS_SUPPORTED = 1;
-
- /** @hide */
- @IntDef(prefix = "OPTIONAL_CODECS_PREF_", value = {
- OPTIONAL_CODECS_PREF_UNKNOWN,
- OPTIONAL_CODECS_PREF_DISABLED,
- OPTIONAL_CODECS_PREF_ENABLED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface OptionalCodecsPreferenceStatus {}
-
- /**
- * We don't have a stored preference for whether optional codecs should be enabled or
- * disabled for the given A2DP device.
- *
- * @hide
- */
- @SystemApi
- public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1;
-
- /**
- * Optional codecs should be disabled for the given A2DP device.
- *
- * @hide
- */
- @SystemApi
- public static final int OPTIONAL_CODECS_PREF_DISABLED = 0;
-
- /**
- * Optional codecs should be enabled for the given A2DP device.
- *
- * @hide
- */
- @SystemApi
- public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
-
- /** @hide */
- @IntDef(prefix = "DYNAMIC_BUFFER_SUPPORT_", value = {
- DYNAMIC_BUFFER_SUPPORT_NONE,
- DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD,
- DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- /**
- * Indicates the supported type of Dynamic Audio Buffer is not supported.
- *
- * @hide
- */
- @SystemApi
- public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0;
-
- /**
- * Indicates the supported type of Dynamic Audio Buffer is A2DP offload.
- *
- * @hide
- */
- @SystemApi
- public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1;
-
- /**
- * Indicates the supported type of Dynamic Audio Buffer is A2DP software encoding.
- *
- * @hide
- */
- @SystemApi
- public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp",
- IBluetoothA2dp.class.getName()) {
- @Override
- public IBluetoothA2dp getServiceInterface(IBinder service) {
- return IBluetoothA2dp.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothA2dp proxy object for interacting with the local
- * Bluetooth A2DP service.
- */
- /* package */ BluetoothA2dp(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- @UnsupportedAppUsage
- /*package*/ void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothA2dp getService() {
- return mProfileConnector.getService();
- }
-
- @Override
- public void finalize() {
- // The empty finalize needs to be kept or the
- // cts signature tests would fail.
- }
-
- /**
- * Initiate connection to a profile of the remote Bluetooth device.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is already connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that
- * connection state intent for the profile will be broadcasted with
- * the state. Users can get the connection state of the profile
- * from this intent.
- *
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @UnsupportedAppUsage
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- final IBluetoothA2dp service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connectWithAttribution(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnection from a profile
- *
- * <p> This API will return false in scenarios like the profile on the
- * Bluetooth device is not in connected state etc. When this API returns,
- * true, it is guaranteed that the connection state change
- * intent will be broadcasted with the state. Users can get the
- * disconnection state of the profile from this intent.
- *
- * <p> If the disconnection is initiated by a remote device, the state
- * will transition from {@link #STATE_CONNECTED} to
- * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
- * host (local) device the state will transition from
- * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
- * state {@link #STATE_DISCONNECTED}. The transition to
- * {@link #STATE_DISCONNECTING} can be used to distinguish between the
- * two scenarios.
- *
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @UnsupportedAppUsage
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothA2dp service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnectWithAttribution(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothA2dp service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevicesWithAttribution(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothA2dp service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStatesWithAttribution(states,
- mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @BtProfileState int getConnectionState(BluetoothDevice device) {
- if (VDBG) log("getState(" + device + ")");
- final IBluetoothA2dp service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionStateWithAttribution(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Select a connected device as active.
- *
- * The active device selection is per profile. An active device's
- * purpose is profile-specific. For example, A2DP audio streaming
- * is to the active A2DP Sink device. If a remote device is not
- * connected, it cannot be selected as active.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is not connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that the
- * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
- * with the active device.
- *
- * @param device the remote Bluetooth device. Could be null to clear
- * the active device and stop streaming audio to a Bluetooth device.
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @UnsupportedAppUsage(trackingBug = 171933273)
- public boolean setActiveDevice(@Nullable BluetoothDevice device) {
- if (DBG) log("setActiveDevice(" + device + ")");
- final IBluetoothA2dp service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && ((device == null) || isValidDevice(device))) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setActiveDevice(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the connected device that is active.
- *
- * @return the connected device that is active or null if no device
- * is active
- * @hide
- */
- @UnsupportedAppUsage(trackingBug = 171933273)
- @Nullable
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothDevice getActiveDevice() {
- if (VDBG) log("getActiveDevice()");
- final IBluetoothA2dp service = getService();
- final BluetoothDevice defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<BluetoothDevice> recv =
- new SynchronousResultReceiver();
- service.getActiveDevice(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) log("setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothA2dp service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothA2dp service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Checks if Avrcp device supports the absolute volume feature.
- *
- * @return true if device supports absolute volume
- * @hide
- */
- @RequiresNoPermission
- public boolean isAvrcpAbsoluteVolumeSupported() {
- if (DBG) Log.d(TAG, "isAvrcpAbsoluteVolumeSupported");
- final IBluetoothA2dp service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isAvrcpAbsoluteVolumeSupported(recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Tells remote device to set an absolute volume. Only if absolute volume is supported
- *
- * @param volume Absolute volume to be set on AVRCP side
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setAvrcpAbsoluteVolume(int volume) {
- if (DBG) Log.d(TAG, "setAvrcpAbsoluteVolume");
- final IBluetoothA2dp service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- service.setAvrcpAbsoluteVolume(volume, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Check if A2DP profile is streaming music.
- *
- * @param device BluetoothDevice device
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isA2dpPlaying(BluetoothDevice device) {
- if (DBG) log("isA2dpPlaying(" + device + ")");
- final IBluetoothA2dp service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isA2dpPlaying(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * This function checks if the remote device is an AVCRP
- * target and thus whether we should send volume keys
- * changes or not.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean shouldSendVolumeKeys(BluetoothDevice device) {
- if (isEnabled() && isValidDevice(device)) {
- ParcelUuid[] uuids = device.getUuids();
- if (uuids == null) return false;
-
- for (ParcelUuid uuid : uuids) {
- if (uuid.equals(BluetoothUuid.AVRCP_TARGET)) {
- return true;
- }
- }
- }
- return false;
- }
-
- /**
- * Gets the current codec status (configuration and capability).
- *
- * @param device the remote Bluetooth device.
- * @return the current codec status
- * @hide
- */
- @UnsupportedAppUsage(trackingBug = 181103983)
- @Nullable
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothCodecStatus getCodecStatus(@NonNull BluetoothDevice device) {
- if (DBG) Log.d(TAG, "getCodecStatus(" + device + ")");
- verifyDeviceNotNull(device, "getCodecStatus");
- final IBluetoothA2dp service = getService();
- final BluetoothCodecStatus defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<BluetoothCodecStatus> recv =
- new SynchronousResultReceiver();
- service.getCodecStatus(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Sets the codec configuration preference.
- *
- * @param device the remote Bluetooth device.
- * @param codecConfig the codec configuration preference
- * @hide
- */
- @UnsupportedAppUsage(trackingBug = 181103983)
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setCodecConfigPreference(@NonNull BluetoothDevice device,
- @NonNull BluetoothCodecConfig codecConfig) {
- if (DBG) Log.d(TAG, "setCodecConfigPreference(" + device + ")");
- verifyDeviceNotNull(device, "setCodecConfigPreference");
- if (codecConfig == null) {
- Log.e(TAG, "setCodecConfigPreference: Codec config can't be null");
- throw new IllegalArgumentException("codecConfig cannot be null");
- }
- final IBluetoothA2dp service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- service.setCodecConfigPreference(device, codecConfig, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Enables the optional codecs.
- *
- * @param device the remote Bluetooth device.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void enableOptionalCodecs(@NonNull BluetoothDevice device) {
- if (DBG) Log.d(TAG, "enableOptionalCodecs(" + device + ")");
- verifyDeviceNotNull(device, "enableOptionalCodecs");
- enableDisableOptionalCodecs(device, true);
- }
-
- /**
- * Disables the optional codecs.
- *
- * @param device the remote Bluetooth device.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void disableOptionalCodecs(@NonNull BluetoothDevice device) {
- if (DBG) Log.d(TAG, "disableOptionalCodecs(" + device + ")");
- verifyDeviceNotNull(device, "disableOptionalCodecs");
- enableDisableOptionalCodecs(device, false);
- }
-
- /**
- * Enables or disables the optional codecs.
- *
- * @param device the remote Bluetooth device.
- * @param enable if true, enable the optional codecs, other disable them
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private void enableDisableOptionalCodecs(BluetoothDevice device, boolean enable) {
- final IBluetoothA2dp service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- if (enable) {
- service.enableOptionalCodecs(device, mAttributionSource);
- } else {
- service.disableOptionalCodecs(device, mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Returns whether this device supports optional codecs.
- *
- * @param device The device to check
- * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or
- * OPTIONAL_CODECS_SUPPORTED.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @OptionalCodecsSupportStatus
- public int isOptionalCodecsSupported(@NonNull BluetoothDevice device) {
- if (DBG) log("isOptionalCodecsSupported(" + device + ")");
- verifyDeviceNotNull(device, "isOptionalCodecsSupported");
- final IBluetoothA2dp service = getService();
- final int defaultValue = OPTIONAL_CODECS_SUPPORT_UNKNOWN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.supportsOptionalCodecs(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns whether this device should have optional codecs enabled.
- *
- * @param device The device in question.
- * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
- * OPTIONAL_CODECS_PREF_DISABLED.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @OptionalCodecsPreferenceStatus
- public int isOptionalCodecsEnabled(@NonNull BluetoothDevice device) {
- if (DBG) log("isOptionalCodecsEnabled(" + device + ")");
- verifyDeviceNotNull(device, "isOptionalCodecsEnabled");
- final IBluetoothA2dp service = getService();
- final int defaultValue = OPTIONAL_CODECS_PREF_UNKNOWN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getOptionalCodecsEnabled(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Sets a persistent preference for whether a given device should have optional codecs enabled.
- *
- * @param device The device to set this preference for.
- * @param value Whether the optional codecs should be enabled for this device. This should be
- * one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
- * OPTIONAL_CODECS_PREF_DISABLED.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setOptionalCodecsEnabled(@NonNull BluetoothDevice device,
- @OptionalCodecsPreferenceStatus int value) {
- if (DBG) log("setOptionalCodecsEnabled(" + device + ")");
- verifyDeviceNotNull(device, "setOptionalCodecsEnabled");
- if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN
- && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED
- && value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
- Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
- return;
- }
- final IBluetoothA2dp service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- service.setOptionalCodecsEnabled(device, value, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Get the supported type of the Dynamic Audio Buffer.
- * <p>Possible return values are
- * {@link #DYNAMIC_BUFFER_SUPPORT_NONE},
- * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD},
- * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}.
- *
- * @return supported type of Dynamic Audio Buffer feature
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @Type int getDynamicBufferSupport() {
- if (VDBG) log("getDynamicBufferSupport()");
- final IBluetoothA2dp service = getService();
- final int defaultValue = DYNAMIC_BUFFER_SUPPORT_NONE;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getDynamicBufferSupport(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Return the record of {@link BufferConstraints} object that
- * has the default/maximum/minimum audio buffer. This can be used to inform what the controller
- * has support for the audio buffer.
- *
- * @return a record with {@link BufferConstraints} or null if report is unavailable
- * or unsupported
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @Nullable BufferConstraints getBufferConstraints() {
- if (VDBG) log("getBufferConstraints()");
- final IBluetoothA2dp service = getService();
- final BufferConstraints defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<BufferConstraints> recv =
- new SynchronousResultReceiver();
- service.getBufferConstraints(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set Dynamic Audio Buffer Size.
- *
- * @param codec audio codec
- * @param value buffer millis
- * @return true to indicate success, or false on immediate error
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setBufferLengthMillis(@BluetoothCodecConfig.SourceCodecType int codec,
- int value) {
- if (VDBG) log("setBufferLengthMillis(" + codec + ", " + value + ")");
- if (value < 0) {
- Log.e(TAG, "Trying to set audio buffer length to a negative value: " + value);
- return false;
- }
- final IBluetoothA2dp service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setBufferLengthMillis(codec, value, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Helper for converting a state to a string.
- *
- * For debug use only - strings are not internationalized.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public static String stateToString(int state) {
- switch (state) {
- case STATE_DISCONNECTED:
- return "disconnected";
- case STATE_CONNECTING:
- return "connecting";
- case STATE_CONNECTED:
- return "connected";
- case STATE_DISCONNECTING:
- return "disconnecting";
- case STATE_PLAYING:
- return "playing";
- case STATE_NOT_PLAYING:
- return "not playing";
- default:
- return "<unknown state " + state + ">";
- }
- }
-
- private boolean isEnabled() {
- if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
- return false;
- }
-
- private void verifyDeviceNotNull(BluetoothDevice device, String methodName) {
- if (device == null) {
- Log.e(TAG, methodName + ": device param is null");
- throw new IllegalArgumentException("Device cannot be null");
- }
- }
-
- private boolean isValidDevice(BluetoothDevice device) {
- if (device == null) return false;
-
- if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
- return false;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothA2dpSink.java b/core/java/android/bluetooth/BluetoothA2dpSink.java
deleted file mode 100755
index 5941681..0000000
--- a/core/java/android/bluetooth/BluetoothA2dpSink.java
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the public APIs to control the Bluetooth A2DP Sink
- * profile.
- *
- * <p>BluetoothA2dpSink is a proxy object for controlling the Bluetooth A2DP Sink
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothA2dpSink proxy object.
- *
- * @hide
- */
-@SystemApi
-public final class BluetoothA2dpSink implements BluetoothProfile {
- private static final String TAG = "BluetoothA2dpSink";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the A2DP Sink
- * profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * @hide
- */
- @SystemApi
- @SuppressLint("ActionValue")
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.a2dp-sink.profile.action.CONNECTION_STATE_CHANGED";
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothA2dpSink> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.A2DP_SINK,
- "BluetoothA2dpSink", IBluetoothA2dpSink.class.getName()) {
- @Override
- public IBluetoothA2dpSink getServiceInterface(IBinder service) {
- return IBluetoothA2dpSink.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothA2dp proxy object for interacting with the local
- * Bluetooth A2DP service.
- */
- /* package */ BluetoothA2dpSink(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- /*package*/ void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothA2dpSink getService() {
- return mProfileConnector.getService();
- }
-
- @Override
- public void finalize() {
- close();
- }
-
- /**
- * Initiate connection to a profile of the remote bluetooth device.
- *
- * <p> Currently, the system supports only 1 connection to the
- * A2DP profile. The API will automatically disconnect connected
- * devices before connecting.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is already connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that
- * connection state intent for the profile will be broadcasted with
- * the state. Users can get the connection state of the profile
- * from this intent.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- final IBluetoothA2dpSink service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnection from a profile
- *
- * <p> This API will return false in scenarios like the profile on the
- * Bluetooth device is not in connected state etc. When this API returns,
- * true, it is guaranteed that the connection state change
- * intent will be broadcasted with the state. Users can get the
- * disconnection state of the profile from this intent.
- *
- * <p> If the disconnection is initiated by a remote device, the state
- * will transition from {@link #STATE_CONNECTED} to
- * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
- * host (local) device the state will transition from
- * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
- * state {@link #STATE_DISCONNECTED}. The transition to
- * {@link #STATE_DISCONNECTING} can be used to distinguish between the
- * two scenarios.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothA2dpSink service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothA2dpSink service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothA2dpSink service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (VDBG) log("getConnectionState(" + device + ")");
- final IBluetoothA2dpSink service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the current audio configuration for the A2DP source device,
- * or null if the device has no audio configuration
- *
- * @param device Remote bluetooth device.
- * @return audio configuration for the device, or null
- *
- * {@see BluetoothAudioConfig}
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothAudioConfig getAudioConfig(BluetoothDevice device) {
- if (VDBG) log("getAudioConfig(" + device + ")");
- final IBluetoothA2dpSink service = getService();
- final BluetoothAudioConfig defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<BluetoothAudioConfig> recv =
- new SynchronousResultReceiver();
- service.getAudioConfig(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) log("setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothA2dpSink service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothA2dpSink service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Check if audio is playing on the bluetooth device (A2DP profile is streaming music).
- *
- * @param device BluetoothDevice device
- * @return true if audio is playing (A2dp is streaming music), false otherwise
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean isAudioPlaying(@NonNull BluetoothDevice device) {
- if (VDBG) log("isAudioPlaying(" + device + ")");
- final IBluetoothA2dpSink service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isA2dpPlaying(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Helper for converting a state to a string.
- *
- * For debug use only - strings are not internationalized.
- *
- * @hide
- */
- public static String stateToString(int state) {
- switch (state) {
- case STATE_DISCONNECTED:
- return "disconnected";
- case STATE_CONNECTING:
- return "connecting";
- case STATE_CONNECTED:
- return "connected";
- case STATE_DISCONNECTING:
- return "disconnecting";
- case BluetoothA2dp.STATE_PLAYING:
- return "playing";
- case BluetoothA2dp.STATE_NOT_PLAYING:
- return "not playing";
- default:
- return "<unknown state " + state + ">";
- }
- }
-
- private boolean isEnabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_ON;
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java b/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
deleted file mode 100644
index c17a7b4..0000000
--- a/core/java/android/bluetooth/BluetoothActivityEnergyInfo.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.ElapsedRealtimeLong;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Record of energy and activity information from controller and
- * underlying bt stack state.Timestamp the record with system
- * time.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
-public final class BluetoothActivityEnergyInfo implements Parcelable {
- private final long mTimestamp;
- private int mBluetoothStackState;
- private long mControllerTxTimeMs;
- private long mControllerRxTimeMs;
- private long mControllerIdleTimeMs;
- private long mControllerEnergyUsed;
- private List<UidTraffic> mUidTraffic;
-
- /** @hide */
- @IntDef(prefix = { "BT_STACK_STATE_" }, value = {
- BT_STACK_STATE_INVALID,
- BT_STACK_STATE_STATE_ACTIVE,
- BT_STACK_STATE_STATE_SCANNING,
- BT_STACK_STATE_STATE_IDLE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface BluetoothStackState {}
-
- public static final int BT_STACK_STATE_INVALID = 0;
- public static final int BT_STACK_STATE_STATE_ACTIVE = 1;
- public static final int BT_STACK_STATE_STATE_SCANNING = 2;
- public static final int BT_STACK_STATE_STATE_IDLE = 3;
-
- /** @hide */
- public BluetoothActivityEnergyInfo(long timestamp, int stackState,
- long txTime, long rxTime, long idleTime, long energyUsed) {
- mTimestamp = timestamp;
- mBluetoothStackState = stackState;
- mControllerTxTimeMs = txTime;
- mControllerRxTimeMs = rxTime;
- mControllerIdleTimeMs = idleTime;
- mControllerEnergyUsed = energyUsed;
- }
-
- /** @hide */
- private BluetoothActivityEnergyInfo(Parcel in) {
- mTimestamp = in.readLong();
- mBluetoothStackState = in.readInt();
- mControllerTxTimeMs = in.readLong();
- mControllerRxTimeMs = in.readLong();
- mControllerIdleTimeMs = in.readLong();
- mControllerEnergyUsed = in.readLong();
- mUidTraffic = in.createTypedArrayList(UidTraffic.CREATOR);
- }
-
- /** @hide */
- @Override
- public String toString() {
- return "BluetoothActivityEnergyInfo{"
- + " mTimestamp=" + mTimestamp
- + " mBluetoothStackState=" + mBluetoothStackState
- + " mControllerTxTimeMs=" + mControllerTxTimeMs
- + " mControllerRxTimeMs=" + mControllerRxTimeMs
- + " mControllerIdleTimeMs=" + mControllerIdleTimeMs
- + " mControllerEnergyUsed=" + mControllerEnergyUsed
- + " mUidTraffic=" + mUidTraffic
- + " }";
- }
-
- public static final @NonNull Parcelable.Creator<BluetoothActivityEnergyInfo> CREATOR =
- new Parcelable.Creator<BluetoothActivityEnergyInfo>() {
- public BluetoothActivityEnergyInfo createFromParcel(Parcel in) {
- return new BluetoothActivityEnergyInfo(in);
- }
-
- public BluetoothActivityEnergyInfo[] newArray(int size) {
- return new BluetoothActivityEnergyInfo[size];
- }
- };
-
- /** @hide */
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(mTimestamp);
- out.writeInt(mBluetoothStackState);
- out.writeLong(mControllerTxTimeMs);
- out.writeLong(mControllerRxTimeMs);
- out.writeLong(mControllerIdleTimeMs);
- out.writeLong(mControllerEnergyUsed);
- out.writeTypedList(mUidTraffic);
- }
-
- /** @hide */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Get the Bluetooth stack state associated with the energy info.
- *
- * @return one of {@link #BluetoothStackState} states
- */
- @BluetoothStackState
- public int getBluetoothStackState() {
- return mBluetoothStackState;
- }
-
- /**
- * @return tx time in ms
- */
- public long getControllerTxTimeMillis() {
- return mControllerTxTimeMs;
- }
-
- /**
- * @return rx time in ms
- */
- public long getControllerRxTimeMillis() {
- return mControllerRxTimeMs;
- }
-
- /**
- * @return idle time in ms
- */
- public long getControllerIdleTimeMillis() {
- return mControllerIdleTimeMs;
- }
-
- /**
- * Get the product of current (mA), voltage (V), and time (ms).
- *
- * @return energy used
- */
- public long getControllerEnergyUsed() {
- return mControllerEnergyUsed;
- }
-
- /**
- * @return timestamp (real time elapsed in milliseconds since boot) of record creation
- */
- public @ElapsedRealtimeLong long getTimestampMillis() {
- return mTimestamp;
- }
-
- /**
- * Get the {@link List} of each application {@link android.bluetooth.UidTraffic}.
- *
- * @return current {@link List} of {@link android.bluetooth.UidTraffic}
- */
- public @NonNull List<UidTraffic> getUidTraffic() {
- if (mUidTraffic == null) {
- return Collections.emptyList();
- }
- return mUidTraffic;
- }
-
- /** @hide */
- public void setUidTraffic(List<UidTraffic> traffic) {
- mUidTraffic = traffic;
- }
-
- /**
- * @return true if the record Tx time, Rx time, and Idle time are more than 0.
- */
- public boolean isValid() {
- return ((mControllerTxTimeMs >= 0) && (mControllerRxTimeMs >= 0)
- && (mControllerIdleTimeMs >= 0));
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
deleted file mode 100644
index 661291c..0000000
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ /dev/null
@@ -1,4413 +0,0 @@
-/*
- * Copyright 2009-2016 The Android Open Source Project
- * Copyright 2015 Samsung LSI
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.CallbackExecutor;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache;
-import android.bluetooth.BluetoothDevice.Transport;
-import android.bluetooth.BluetoothProfile.ConnectionPolicy;
-import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
-import android.bluetooth.annotations.RequiresBluetoothScanPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.bluetooth.le.BluetoothLeAdvertiser;
-import android.bluetooth.le.BluetoothLeScanner;
-import android.bluetooth.le.PeriodicAdvertisingManager;
-import android.bluetooth.le.ScanCallback;
-import android.bluetooth.le.ScanFilter;
-import android.bluetooth.le.ScanRecord;
-import android.bluetooth.le.ScanResult;
-import android.bluetooth.le.ScanSettings;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.ParcelUuid;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.sysprop.BluetoothProperties;
-import android.util.Log;
-import android.util.Pair;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.time.Duration;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.UUID;
-import java.util.WeakHashMap;
-import java.util.concurrent.Executor;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-/**
- * Represents the local device Bluetooth adapter. The {@link BluetoothAdapter}
- * lets you perform fundamental Bluetooth tasks, such as initiate
- * device discovery, query a list of bonded (paired) devices,
- * instantiate a {@link BluetoothDevice} using a known MAC address, and create
- * a {@link BluetoothServerSocket} to listen for connection requests from other
- * devices, and start a scan for Bluetooth LE devices.
- *
- * <p>To get a {@link BluetoothAdapter} representing the local Bluetooth
- * adapter, call the {@link BluetoothManager#getAdapter} function on {@link BluetoothManager}.
- * On JELLY_BEAN_MR1 and below you will need to use the static {@link #getDefaultAdapter}
- * method instead.
- * </p><p>
- * Fundamentally, this is your starting point for all
- * Bluetooth actions. Once you have the local adapter, you can get a set of
- * {@link BluetoothDevice} objects representing all paired devices with
- * {@link #getBondedDevices()}; start device discovery with
- * {@link #startDiscovery()}; or create a {@link BluetoothServerSocket} to
- * listen for incoming RFComm connection requests with {@link
- * #listenUsingRfcommWithServiceRecord(String, UUID)}; listen for incoming L2CAP Connection-oriented
- * Channels (CoC) connection requests with {@link #listenUsingL2capChannel()}; or start a scan for
- * Bluetooth LE devices with {@link #startLeScan(LeScanCallback callback)}.
- * </p>
- * <p>This class is thread safe.</p>
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>
- * For more information about using Bluetooth, read the <a href=
- * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
- * guide.
- * </p>
- * </div>
- *
- * {@see BluetoothDevice}
- * {@see BluetoothServerSocket}
- */
-public final class BluetoothAdapter {
- private static final String TAG = "BluetoothAdapter";
- private static final String DESCRIPTOR = "android.bluetooth.BluetoothAdapter";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Default MAC address reported to a client that does not have the
- * android.permission.LOCAL_MAC_ADDRESS permission.
- *
- * @hide
- */
- public static final String DEFAULT_MAC_ADDRESS = "02:00:00:00:00:00";
-
- /**
- * Sentinel error value for this class. Guaranteed to not equal any other
- * integer constant in this class. Provided as a convenience for functions
- * that require a sentinel error value, for example:
- * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
- * BluetoothAdapter.ERROR)</code>
- */
- public static final int ERROR = Integer.MIN_VALUE;
-
- /**
- * Broadcast Action: The state of the local Bluetooth adapter has been
- * changed.
- * <p>For example, Bluetooth has been turned on or off.
- * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
- * #EXTRA_PREVIOUS_STATE} containing the new and old states
- * respectively.
- */
- @RequiresLegacyBluetoothPermission
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
- ACTION_STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED";
-
- /**
- * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
- * intents to request the current power state. Possible values are:
- * {@link #STATE_OFF},
- * {@link #STATE_TURNING_ON},
- * {@link #STATE_ON},
- * {@link #STATE_TURNING_OFF},
- */
- public static final String EXTRA_STATE = "android.bluetooth.adapter.extra.STATE";
- /**
- * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
- * intents to request the previous power state. Possible values are:
- * {@link #STATE_OFF},
- * {@link #STATE_TURNING_ON},
- * {@link #STATE_ON},
- * {@link #STATE_TURNING_OFF}
- */
- public static final String EXTRA_PREVIOUS_STATE =
- "android.bluetooth.adapter.extra.PREVIOUS_STATE";
-
- /** @hide */
- @IntDef(prefix = { "STATE_" }, value = {
- STATE_OFF,
- STATE_TURNING_ON,
- STATE_ON,
- STATE_TURNING_OFF,
- STATE_BLE_TURNING_ON,
- STATE_BLE_ON,
- STATE_BLE_TURNING_OFF
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AdapterState {}
-
- /**
- * Indicates the local Bluetooth adapter is off.
- */
- public static final int STATE_OFF = 10;
- /**
- * Indicates the local Bluetooth adapter is turning on. However local
- * clients should wait for {@link #STATE_ON} before attempting to
- * use the adapter.
- */
- public static final int STATE_TURNING_ON = 11;
- /**
- * Indicates the local Bluetooth adapter is on, and ready for use.
- */
- public static final int STATE_ON = 12;
- /**
- * Indicates the local Bluetooth adapter is turning off. Local clients
- * should immediately attempt graceful disconnection of any remote links.
- */
- public static final int STATE_TURNING_OFF = 13;
-
- /**
- * Indicates the local Bluetooth adapter is turning Bluetooth LE mode on.
- *
- * @hide
- */
- public static final int STATE_BLE_TURNING_ON = 14;
-
- /**
- * Indicates the local Bluetooth adapter is in LE only mode.
- *
- * @hide
- */
- public static final int STATE_BLE_ON = 15;
-
- /**
- * Indicates the local Bluetooth adapter is turning off LE only mode.
- *
- * @hide
- */
- public static final int STATE_BLE_TURNING_OFF = 16;
-
- /**
- * UUID of the GATT Read Characteristics for LE_PSM value.
- *
- * @hide
- */
- public static final UUID LE_PSM_CHARACTERISTIC_UUID =
- UUID.fromString("2d410339-82b6-42aa-b34e-e2e01df8cc1a");
-
- /**
- * Human-readable string helper for AdapterState
- *
- * @hide
- */
- public static String nameForState(@AdapterState int state) {
- switch (state) {
- case STATE_OFF:
- return "OFF";
- case STATE_TURNING_ON:
- return "TURNING_ON";
- case STATE_ON:
- return "ON";
- case STATE_TURNING_OFF:
- return "TURNING_OFF";
- case STATE_BLE_TURNING_ON:
- return "BLE_TURNING_ON";
- case STATE_BLE_ON:
- return "BLE_ON";
- case STATE_BLE_TURNING_OFF:
- return "BLE_TURNING_OFF";
- default:
- return "?!?!? (" + state + ")";
- }
- }
-
- /**
- * Activity Action: Show a system activity that requests discoverable mode.
- * This activity will also request the user to turn on Bluetooth if it
- * is not currently enabled.
- * <p>Discoverable mode is equivalent to {@link
- * #SCAN_MODE_CONNECTABLE_DISCOVERABLE}. It allows remote devices to see
- * this Bluetooth adapter when they perform a discovery.
- * <p>For privacy, Android is not discoverable by default.
- * <p>The sender of this Intent can optionally use extra field {@link
- * #EXTRA_DISCOVERABLE_DURATION} to request the duration of
- * discoverability. Currently the default duration is 120 seconds, and
- * maximum duration is capped at 300 seconds for each request.
- * <p>Notification of the result of this activity is posted using the
- * {@link android.app.Activity#onActivityResult} callback. The
- * <code>resultCode</code>
- * will be the duration (in seconds) of discoverability or
- * {@link android.app.Activity#RESULT_CANCELED} if the user rejected
- * discoverability or an error has occurred.
- * <p>Applications can also listen for {@link #ACTION_SCAN_MODE_CHANGED}
- * for global notification whenever the scan mode changes. For example, an
- * application can be notified when the device has ended discoverability.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
- ACTION_REQUEST_DISCOVERABLE = "android.bluetooth.adapter.action.REQUEST_DISCOVERABLE";
-
- /**
- * Used as an optional int extra field in {@link
- * #ACTION_REQUEST_DISCOVERABLE} intents to request a specific duration
- * for discoverability in seconds. The current default is 120 seconds, and
- * requests over 300 seconds will be capped. These values could change.
- */
- public static final String EXTRA_DISCOVERABLE_DURATION =
- "android.bluetooth.adapter.extra.DISCOVERABLE_DURATION";
-
- /**
- * Activity Action: Show a system activity that allows the user to turn on
- * Bluetooth.
- * <p>This system activity will return once Bluetooth has completed turning
- * on, or the user has decided not to turn Bluetooth on.
- * <p>Notification of the result of this activity is posted using the
- * {@link android.app.Activity#onActivityResult} callback. The
- * <code>resultCode</code>
- * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
- * turned on or {@link android.app.Activity#RESULT_CANCELED} if the user
- * has rejected the request or an error has occurred.
- * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
- * for global notification whenever Bluetooth is turned on or off.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
- ACTION_REQUEST_ENABLE = "android.bluetooth.adapter.action.REQUEST_ENABLE";
-
- /**
- * Activity Action: Show a system activity that allows the user to turn off
- * Bluetooth. This is used only if permission review is enabled which is for
- * apps targeting API less than 23 require a permission review before any of
- * the app's components can run.
- * <p>This system activity will return once Bluetooth has completed turning
- * off, or the user has decided not to turn Bluetooth off.
- * <p>Notification of the result of this activity is posted using the
- * {@link android.app.Activity#onActivityResult} callback. The
- * <code>resultCode</code>
- * will be {@link android.app.Activity#RESULT_OK} if Bluetooth has been
- * turned off or {@link android.app.Activity#RESULT_CANCELED} if the user
- * has rejected the request or an error has occurred.
- * <p>Applications can also listen for {@link #ACTION_STATE_CHANGED}
- * for global notification whenever Bluetooth is turned on or off.
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String
- ACTION_REQUEST_DISABLE = "android.bluetooth.adapter.action.REQUEST_DISABLE";
-
- /**
- * Activity Action: Show a system activity that allows user to enable BLE scans even when
- * Bluetooth is turned off.<p>
- *
- * Notification of result of this activity is posted using
- * {@link android.app.Activity#onActivityResult}. The <code>resultCode</code> will be
- * {@link android.app.Activity#RESULT_OK} if BLE scan always available setting is turned on or
- * {@link android.app.Activity#RESULT_CANCELED} if the user has rejected the request or an
- * error occurred.
- *
- * @hide
- */
- @SystemApi
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE =
- "android.bluetooth.adapter.action.REQUEST_BLE_SCAN_ALWAYS_AVAILABLE";
-
- /**
- * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
- * has changed.
- * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
- * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
- * respectively.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
- ACTION_SCAN_MODE_CHANGED = "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
-
- /**
- * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
- * intents to request the current scan mode. Possible values are:
- * {@link #SCAN_MODE_NONE},
- * {@link #SCAN_MODE_CONNECTABLE},
- * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
- */
- public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
- /**
- * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
- * intents to request the previous scan mode. Possible values are:
- * {@link #SCAN_MODE_NONE},
- * {@link #SCAN_MODE_CONNECTABLE},
- * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
- */
- public static final String EXTRA_PREVIOUS_SCAN_MODE =
- "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
-
- /** @hide */
- @IntDef(prefix = { "SCAN_" }, value = {
- SCAN_MODE_NONE,
- SCAN_MODE_CONNECTABLE,
- SCAN_MODE_CONNECTABLE_DISCOVERABLE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ScanMode {}
-
- /** @hide */
- @IntDef(value = {
- BluetoothStatusCodes.SUCCESS,
- BluetoothStatusCodes.ERROR_UNKNOWN,
- BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
- BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ScanModeStatusCode {}
-
- /**
- * Indicates that both inquiry scan and page scan are disabled on the local
- * Bluetooth adapter. Therefore this device is neither discoverable
- * nor connectable from remote Bluetooth devices.
- */
- public static final int SCAN_MODE_NONE = 20;
- /**
- * Indicates that inquiry scan is disabled, but page scan is enabled on the
- * local Bluetooth adapter. Therefore this device is not discoverable from
- * remote Bluetooth devices, but is connectable from remote devices that
- * have previously discovered this device.
- */
- public static final int SCAN_MODE_CONNECTABLE = 21;
- /**
- * Indicates that both inquiry scan and page scan are enabled on the local
- * Bluetooth adapter. Therefore this device is both discoverable and
- * connectable from remote Bluetooth devices.
- */
- public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
-
- /**
- * Device only has a display.
- *
- * @hide
- */
- public static final int IO_CAPABILITY_OUT = 0;
-
- /**
- * Device has a display and the ability to input Yes/No.
- *
- * @hide
- */
- public static final int IO_CAPABILITY_IO = 1;
-
- /**
- * Device only has a keyboard for entry but no display.
- *
- * @hide
- */
- public static final int IO_CAPABILITY_IN = 2;
-
- /**
- * Device has no Input or Output capability.
- *
- * @hide
- */
- public static final int IO_CAPABILITY_NONE = 3;
-
- /**
- * Device has a display and a full keyboard.
- *
- * @hide
- */
- public static final int IO_CAPABILITY_KBDISP = 4;
-
- /**
- * Maximum range value for Input/Output capabilities.
- *
- * <p>This should be updated when adding a new Input/Output capability. Other code
- * like validation depends on this being accurate.
- *
- * @hide
- */
- public static final int IO_CAPABILITY_MAX = 5;
-
- /**
- * The Input/Output capability of the device is unknown.
- *
- * @hide
- */
- public static final int IO_CAPABILITY_UNKNOWN = 255;
-
- /** @hide */
- @IntDef({IO_CAPABILITY_OUT, IO_CAPABILITY_IO, IO_CAPABILITY_IN, IO_CAPABILITY_NONE,
- IO_CAPABILITY_KBDISP})
- @Retention(RetentionPolicy.SOURCE)
- public @interface IoCapability {}
-
- /** @hide */
- @IntDef(prefix = "ACTIVE_DEVICE_", value = {ACTIVE_DEVICE_AUDIO,
- ACTIVE_DEVICE_PHONE_CALL, ACTIVE_DEVICE_ALL})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ActiveDeviceUse {}
-
- /**
- * Use the specified device for audio (a2dp and hearing aid profile)
- *
- * @hide
- */
- @SystemApi
- public static final int ACTIVE_DEVICE_AUDIO = 0;
-
- /**
- * Use the specified device for phone calls (headset profile and hearing
- * aid profile)
- *
- * @hide
- */
- @SystemApi
- public static final int ACTIVE_DEVICE_PHONE_CALL = 1;
-
- /**
- * Use the specified device for a2dp, hearing aid profile, and headset profile
- *
- * @hide
- */
- @SystemApi
- public static final int ACTIVE_DEVICE_ALL = 2;
-
- /** @hide */
- @IntDef({BluetoothProfile.HEADSET, BluetoothProfile.A2DP,
- BluetoothProfile.HEARING_AID})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ActiveDeviceProfile {}
-
- /**
- * Broadcast Action: The local Bluetooth adapter has started the remote
- * device discovery process.
- * <p>This usually involves an inquiry scan of about 12 seconds, followed
- * by a page scan of each new device to retrieve its Bluetooth name.
- * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
- * remote Bluetooth devices are found.
- * <p>Device discovery is a heavyweight procedure. New connections to
- * remote Bluetooth devices should not be attempted while discovery is in
- * progress, and existing connections will experience limited bandwidth
- * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
- * discovery.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
- ACTION_DISCOVERY_STARTED = "android.bluetooth.adapter.action.DISCOVERY_STARTED";
- /**
- * Broadcast Action: The local Bluetooth adapter has finished the device
- * discovery process.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
- ACTION_DISCOVERY_FINISHED = "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
-
- /**
- * Broadcast Action: The local Bluetooth adapter has changed its friendly
- * Bluetooth name.
- * <p>This name is visible to remote Bluetooth devices.
- * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
- * the name.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
- ACTION_LOCAL_NAME_CHANGED = "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
- /**
- * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
- * intents to request the local Bluetooth name.
- */
- public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
-
- /**
- * Intent used to broadcast the change in connection state of the local
- * Bluetooth adapter to a profile of the remote device. When the adapter is
- * not connected to any profiles of any remote devices and it attempts a
- * connection to a profile this intent will be sent. Once connected, this intent
- * will not be sent for any more connection attempts to any profiles of any
- * remote device. When the adapter disconnects from the last profile its
- * connected to of any remote device, this intent will be sent.
- *
- * <p> This intent is useful for applications that are only concerned about
- * whether the local adapter is connected to any profile of any device and
- * are not really concerned about which profile. For example, an application
- * which displays an icon to display whether Bluetooth is connected or not
- * can use this intent.
- *
- * <p>This intent will have 3 extras:
- * {@link #EXTRA_CONNECTION_STATE} - The current connection state.
- * {@link #EXTRA_PREVIOUS_CONNECTION_STATE}- The previous connection state.
- * {@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
- *
- * {@link #EXTRA_CONNECTION_STATE} or {@link #EXTRA_PREVIOUS_CONNECTION_STATE}
- * can be any of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String
- ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED";
-
- /**
- * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
- *
- * This extra represents the current connection state.
- */
- public static final String EXTRA_CONNECTION_STATE =
- "android.bluetooth.adapter.extra.CONNECTION_STATE";
-
- /**
- * Extra used by {@link #ACTION_CONNECTION_STATE_CHANGED}
- *
- * This extra represents the previous connection state.
- */
- public static final String EXTRA_PREVIOUS_CONNECTION_STATE =
- "android.bluetooth.adapter.extra.PREVIOUS_CONNECTION_STATE";
-
- /**
- * Broadcast Action: The Bluetooth adapter state has changed in LE only mode.
- *
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @SystemApi public static final String ACTION_BLE_STATE_CHANGED =
- "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
-
- /**
- * Intent used to broadcast the change in the Bluetooth address
- * of the local Bluetooth adapter.
- * <p>Always contains the extra field {@link
- * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address.
- *
- * Note: only system level processes are allowed to send this
- * defined broadcast.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED =
- "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED";
-
- /**
- * Used as a String extra field in {@link
- * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local
- * Bluetooth address.
- *
- * @hide
- */
- public static final String EXTRA_BLUETOOTH_ADDRESS =
- "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS";
-
- /**
- * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
- * by BLE Always on enabled application to know the ACL_CONNECTED event
- * when Bluetooth state in STATE_BLE_ON. This denotes GATT connection
- * as Bluetooth LE is the only feature available in STATE_BLE_ON
- *
- * This is counterpart of {@link BluetoothDevice#ACTION_ACL_CONNECTED} which
- * works in Bluetooth state STATE_ON
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_BLE_ACL_CONNECTED =
- "android.bluetooth.adapter.action.BLE_ACL_CONNECTED";
-
- /**
- * Broadcast Action: The notifys Bluetooth ACL connected event. This will be
- * by BLE Always on enabled application to know the ACL_DISCONNECTED event
- * when Bluetooth state in STATE_BLE_ON. This denotes GATT disconnection as Bluetooth
- * LE is the only feature available in STATE_BLE_ON
- *
- * This is counterpart of {@link BluetoothDevice#ACTION_ACL_DISCONNECTED} which
- * works in Bluetooth state STATE_ON
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_BLE_ACL_DISCONNECTED =
- "android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED";
-
- /** The profile is in disconnected state */
- public static final int STATE_DISCONNECTED =
- 0; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTED;
- /** The profile is in connecting state */
- public static final int STATE_CONNECTING = 1; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTING;
- /** The profile is in connected state */
- public static final int STATE_CONNECTED = 2; //BluetoothProtoEnums.CONNECTION_STATE_CONNECTED;
- /** The profile is in disconnecting state */
- public static final int STATE_DISCONNECTING =
- 3; //BluetoothProtoEnums.CONNECTION_STATE_DISCONNECTING;
-
- /** @hide */
- public static final String BLUETOOTH_MANAGER_SERVICE = "bluetooth_manager";
- private final IBinder mToken;
-
-
- /**
- * When creating a ServerSocket using listenUsingRfcommOn() or
- * listenUsingL2capOn() use SOCKET_CHANNEL_AUTO_STATIC to create
- * a ServerSocket that auto assigns a channel number to the first
- * bluetooth socket.
- * The channel number assigned to this first Bluetooth Socket will
- * be stored in the ServerSocket, and reused for subsequent Bluetooth
- * sockets.
- *
- * @hide
- */
- public static final int SOCKET_CHANNEL_AUTO_STATIC_NO_SDP = -2;
-
-
- private static final int ADDRESS_LENGTH = 17;
-
- /**
- * Lazily initialized singleton. Guaranteed final after first object
- * constructed.
- */
- private static BluetoothAdapter sAdapter;
-
- private BluetoothLeScanner mBluetoothLeScanner;
- private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
- private PeriodicAdvertisingManager mPeriodicAdvertisingManager;
-
- private final IBluetoothManager mManagerService;
- private final AttributionSource mAttributionSource;
-
- // Yeah, keeping both mService and sService isn't pretty, but it's too late
- // in the current release for a major refactoring, so we leave them both
- // intact until this can be cleaned up in a future release
-
- @UnsupportedAppUsage
- @GuardedBy("mServiceLock")
- private IBluetooth mService;
- private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
-
- @GuardedBy("sServiceLock")
- private static boolean sServiceRegistered;
- @GuardedBy("sServiceLock")
- private static IBluetooth sService;
- private static final Object sServiceLock = new Object();
-
- private final Object mLock = new Object();
- private final Map<LeScanCallback, ScanCallback> mLeScanClients;
- private final Map<BluetoothDevice, List<Pair<OnMetadataChangedListener, Executor>>>
- mMetadataListeners = new HashMap<>();
- private final Map<BluetoothConnectionCallback, Executor>
- mBluetoothConnectionCallbackExecutorMap = new HashMap<>();
-
- /**
- * Bluetooth metadata listener. Overrides the default BluetoothMetadataListener
- * implementation.
- */
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothMetadataListener mBluetoothMetadataListener =
- new IBluetoothMetadataListener.Stub() {
- @Override
- public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) {
- Attributable.setAttributionSource(device, mAttributionSource);
- synchronized (mMetadataListeners) {
- if (mMetadataListeners.containsKey(device)) {
- List<Pair<OnMetadataChangedListener, Executor>> list =
- mMetadataListeners.get(device);
- for (Pair<OnMetadataChangedListener, Executor> pair : list) {
- OnMetadataChangedListener listener = pair.first;
- Executor executor = pair.second;
- executor.execute(() -> {
- listener.onMetadataChanged(device, key, value);
- });
- }
- }
- }
- return;
- }
- };
-
- /**
- * Get a handle to the default local Bluetooth adapter.
- * <p>
- * Currently Android only supports one Bluetooth adapter, but the API could
- * be extended to support more. This will always return the default adapter.
- * </p>
- *
- * @return the default local adapter, or null if Bluetooth is not supported
- * on this hardware platform
- * @deprecated this method will continue to work, but developers are
- * strongly encouraged to migrate to using
- * {@link BluetoothManager#getAdapter()}, since that approach
- * enables support for {@link Context#createAttributionContext}.
- */
- @Deprecated
- @RequiresNoPermission
- public static synchronized BluetoothAdapter getDefaultAdapter() {
- if (sAdapter == null) {
- sAdapter = createAdapter(AttributionSource.myAttributionSource());
- }
- return sAdapter;
- }
-
- /** {@hide} */
- public static BluetoothAdapter createAdapter(AttributionSource attributionSource) {
- IBinder binder = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
- if (binder != null) {
- return new BluetoothAdapter(IBluetoothManager.Stub.asInterface(binder),
- attributionSource);
- } else {
- Log.e(TAG, "Bluetooth binder is null");
- return null;
- }
- }
-
- /**
- * Use {@link #getDefaultAdapter} to get the BluetoothAdapter instance.
- */
- BluetoothAdapter(IBluetoothManager managerService, AttributionSource attributionSource) {
- mManagerService = Objects.requireNonNull(managerService);
- mAttributionSource = Objects.requireNonNull(attributionSource);
- synchronized (mServiceLock.writeLock()) {
- mService = getBluetoothService(mManagerCallback);
- }
- mLeScanClients = new HashMap<LeScanCallback, ScanCallback>();
- mToken = new Binder(DESCRIPTOR);
- }
-
- /**
- * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
- * address.
- * <p>Valid Bluetooth hardware addresses must be upper case, in a format
- * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
- * available to validate a Bluetooth address.
- * <p>A {@link BluetoothDevice} will always be returned for a valid
- * hardware address, even if this adapter has never seen that device.
- *
- * @param address valid Bluetooth MAC address
- * @throws IllegalArgumentException if address is invalid
- */
- @RequiresNoPermission
- public BluetoothDevice getRemoteDevice(String address) {
- final BluetoothDevice res = new BluetoothDevice(address);
- res.setAttributionSource(mAttributionSource);
- return res;
- }
-
- /**
- * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
- * address.
- * <p>Valid Bluetooth hardware addresses must be 6 bytes. This method
- * expects the address in network byte order (MSB first).
- * <p>A {@link BluetoothDevice} will always be returned for a valid
- * hardware address, even if this adapter has never seen that device.
- *
- * @param address Bluetooth MAC address (6 bytes)
- * @throws IllegalArgumentException if address is invalid
- */
- @RequiresNoPermission
- public BluetoothDevice getRemoteDevice(byte[] address) {
- if (address == null || address.length != 6) {
- throw new IllegalArgumentException("Bluetooth address must have 6 bytes");
- }
- final BluetoothDevice res = new BluetoothDevice(
- String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X", address[0], address[1],
- address[2], address[3], address[4], address[5]));
- res.setAttributionSource(mAttributionSource);
- return res;
- }
-
- /**
- * Returns a {@link BluetoothLeAdvertiser} object for Bluetooth LE Advertising operations.
- * Will return null if Bluetooth is turned off or if Bluetooth LE Advertising is not
- * supported on this device.
- * <p>
- * Use {@link #isMultipleAdvertisementSupported()} to check whether LE Advertising is supported
- * on this device before calling this method.
- */
- @RequiresNoPermission
- public BluetoothLeAdvertiser getBluetoothLeAdvertiser() {
- if (!getLeAccess()) {
- return null;
- }
- synchronized (mLock) {
- if (mBluetoothLeAdvertiser == null) {
- mBluetoothLeAdvertiser = new BluetoothLeAdvertiser(this);
- }
- return mBluetoothLeAdvertiser;
- }
- }
-
- /**
- * Returns a {@link PeriodicAdvertisingManager} object for Bluetooth LE Periodic Advertising
- * operations. Will return null if Bluetooth is turned off or if Bluetooth LE Periodic
- * Advertising is not supported on this device.
- * <p>
- * Use {@link #isLePeriodicAdvertisingSupported()} to check whether LE Periodic Advertising is
- * supported on this device before calling this method.
- *
- * @hide
- */
- @RequiresNoPermission
- public PeriodicAdvertisingManager getPeriodicAdvertisingManager() {
- if (!getLeAccess()) {
- return null;
- }
-
- if (!isLePeriodicAdvertisingSupported()) {
- return null;
- }
-
- synchronized (mLock) {
- if (mPeriodicAdvertisingManager == null) {
- mPeriodicAdvertisingManager = new PeriodicAdvertisingManager(this);
- }
- return mPeriodicAdvertisingManager;
- }
- }
-
- /**
- * Returns a {@link BluetoothLeScanner} object for Bluetooth LE scan operations.
- */
- @RequiresNoPermission
- public BluetoothLeScanner getBluetoothLeScanner() {
- if (!getLeAccess()) {
- return null;
- }
- synchronized (mLock) {
- if (mBluetoothLeScanner == null) {
- mBluetoothLeScanner = new BluetoothLeScanner(this);
- }
- return mBluetoothLeScanner;
- }
- }
-
- /**
- * Return true if Bluetooth is currently enabled and ready for use.
- * <p>Equivalent to:
- * <code>getBluetoothState() == STATE_ON</code>
- *
- * @return true if the local adapter is turned on
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public boolean isEnabled() {
- return getState() == BluetoothAdapter.STATE_ON;
- }
-
- /**
- * Return true if Bluetooth LE(Always BLE On feature) is currently
- * enabled and ready for use
- * <p>This returns true if current state is either STATE_ON or STATE_BLE_ON
- *
- * @return true if the local Bluetooth LE adapter is turned on
- * @hide
- */
- @SystemApi
- @RequiresNoPermission
- public boolean isLeEnabled() {
- final int state = getLeState();
- if (DBG) {
- Log.d(TAG, "isLeEnabled(): " + BluetoothAdapter.nameForState(state));
- }
- return (state == BluetoothAdapter.STATE_ON
- || state == BluetoothAdapter.STATE_BLE_ON
- || state == BluetoothAdapter.STATE_TURNING_ON
- || state == BluetoothAdapter.STATE_TURNING_OFF);
- }
-
- /**
- * Turns off Bluetooth LE which was earlier turned on by calling enableBLE().
- *
- * <p> If the internal Adapter state is STATE_BLE_ON, this would trigger the transition
- * to STATE_OFF and completely shut-down Bluetooth
- *
- * <p> If the Adapter state is STATE_ON, This would unregister the existance of
- * special Bluetooth LE application and hence the further turning off of Bluetooth
- * from UI would ensure the complete turn-off of Bluetooth rather than staying back
- * BLE only state
- *
- * <p>This is an asynchronous call: it will return immediately, and
- * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
- * to be notified of subsequent adapter state changes If this call returns
- * true, then the adapter state will immediately transition from {@link
- * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
- * later transition to either {@link #STATE_BLE_ON} or {@link
- * #STATE_OFF} based on the existance of the further Always BLE ON enabled applications
- * If this call returns false then there was an
- * immediate problem that will prevent the QAdapter from being turned off -
- * such as the QAadapter already being turned off.
- *
- * @return true to indicate success, or false on immediate error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disableBLE() {
- if (!isBleScanAlwaysAvailable()) {
- return false;
- }
- try {
- return mManagerService.disableBle(mAttributionSource, mToken);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Applications who want to only use Bluetooth Low Energy (BLE) can call enableBLE.
- *
- * enableBLE registers the existence of an app using only LE functions.
- *
- * enableBLE may enable Bluetooth to an LE only mode so that an app can use
- * LE related features (BluetoothGatt or BluetoothGattServer classes)
- *
- * If the user disables Bluetooth while an app is registered to use LE only features,
- * Bluetooth will remain on in LE only mode for the app.
- *
- * When Bluetooth is in LE only mode, it is not shown as ON to the UI.
- *
- * <p>This is an asynchronous call: it returns immediately, and
- * clients should listen for {@link #ACTION_BLE_STATE_CHANGED}
- * to be notified of adapter state changes.
- *
- * If this call returns * true, then the adapter state is either in a mode where
- * LE is available, or will transition from {@link #STATE_OFF} to {@link #STATE_BLE_TURNING_ON},
- * and some time later transition to either {@link #STATE_OFF} or {@link #STATE_BLE_ON}.
- *
- * If this call returns false then there was an immediate problem that prevents the
- * adapter from being turned on - such as Airplane mode.
- *
- * {@link #ACTION_BLE_STATE_CHANGED} returns the Bluetooth Adapter's various
- * states, It includes all the classic Bluetooth Adapter states along with
- * internal BLE only states
- *
- * @return true to indicate Bluetooth LE will be available, or false on immediate error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean enableBLE() {
- if (!isBleScanAlwaysAvailable()) {
- return false;
- }
- try {
- return mManagerService.enableBle(mAttributionSource, mToken);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
-
- return false;
- }
-
- /*
- private static final String BLUETOOTH_GET_STATE_CACHE_PROPERTY = "cache_key.bluetooth.get_state";
-
- private final PropertyInvalidatedCache<Void, Integer> mBluetoothGetStateCache =
- new PropertyInvalidatedCache<Void, Integer>(
- 8, BLUETOOTH_GET_STATE_CACHE_PROPERTY) {
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public Integer recompute(Void query) {
- try {
- return mService.getState();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- };
- */
-
- /** @hide */
- /*
- @RequiresNoPermission
- public void disableBluetoothGetStateCache() {
- mBluetoothGetStateCache.disableLocal();
- }
- */
-
- /** @hide */
- /*
- public static void invalidateBluetoothGetStateCache() {
- PropertyInvalidatedCache.invalidateCache(BLUETOOTH_GET_STATE_CACHE_PROPERTY);
- }
- */
-
- /**
- * Fetch the current bluetooth state. If the service is down, return
- * OFF.
- */
- @AdapterState
- private int getStateInternal() {
- int state = BluetoothAdapter.STATE_OFF;
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- //state = mBluetoothGetStateCache.query(null);
- state = mService.getState();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- e.rethrowFromSystemServer();
- } finally {
- mServiceLock.readLock().unlock();
- }
- return state;
- }
-
- /**
- * Get the current state of the local Bluetooth adapter.
- * <p>Possible return values are
- * {@link #STATE_OFF},
- * {@link #STATE_TURNING_ON},
- * {@link #STATE_ON},
- * {@link #STATE_TURNING_OFF}.
- *
- * @return current state of Bluetooth adapter
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- @AdapterState
- public int getState() {
- int state = getStateInternal();
-
- // Consider all internal states as OFF
- if (state == BluetoothAdapter.STATE_BLE_ON || state == BluetoothAdapter.STATE_BLE_TURNING_ON
- || state == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
- if (VDBG) {
- Log.d(TAG, "Consider " + BluetoothAdapter.nameForState(state) + " state as OFF");
- }
- state = BluetoothAdapter.STATE_OFF;
- }
- if (VDBG) {
- Log.d(TAG, "" + hashCode() + ": getState(). Returning " + BluetoothAdapter.nameForState(
- state));
- }
- return state;
- }
-
- /**
- * Get the current state of the local Bluetooth adapter
- * <p>This returns current internal state of Adapter including LE ON/OFF
- *
- * <p>Possible return values are
- * {@link #STATE_OFF},
- * {@link #STATE_BLE_TURNING_ON},
- * {@link #STATE_BLE_ON},
- * {@link #STATE_TURNING_ON},
- * {@link #STATE_ON},
- * {@link #STATE_TURNING_OFF},
- * {@link #STATE_BLE_TURNING_OFF}.
- *
- * @return current state of Bluetooth adapter
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- @AdapterState
- @UnsupportedAppUsage(publicAlternatives = "Use {@link #getState()} instead to determine "
- + "whether you can use BLE & BT classic.")
- public int getLeState() {
- int state = getStateInternal();
-
- if (VDBG) {
- Log.d(TAG, "getLeState() returning " + BluetoothAdapter.nameForState(state));
- }
- return state;
- }
-
- boolean getLeAccess() {
- if (getLeState() == STATE_ON) {
- return true;
- } else if (getLeState() == STATE_BLE_ON) {
- return true; // TODO: FILTER SYSTEM APPS HERE <--
- }
-
- return false;
- }
-
- /**
- * Turn on the local Bluetooth adapter—do not use without explicit
- * user action to turn on Bluetooth.
- * <p>This powers on the underlying Bluetooth hardware, and starts all
- * Bluetooth system services.
- * <p class="caution"><strong>Bluetooth should never be enabled without
- * direct user consent</strong>. If you want to turn on Bluetooth in order
- * to create a wireless connection, you should use the {@link
- * #ACTION_REQUEST_ENABLE} Intent, which will raise a dialog that requests
- * user permission to turn on Bluetooth. The {@link #enable()} method is
- * provided only for applications that include a user interface for changing
- * system settings, such as a "power manager" app.</p>
- * <p>This is an asynchronous call: it will return immediately, and
- * clients should listen for {@link #ACTION_STATE_CHANGED}
- * to be notified of subsequent adapter state changes. If this call returns
- * true, then the adapter state will immediately transition from {@link
- * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
- * later transition to either {@link #STATE_OFF} or {@link
- * #STATE_ON}. If this call returns false then there was an
- * immediate problem that will prevent the adapter from being turned on -
- * such as Airplane mode, or the adapter is already turned on.
- *
- * @return true to indicate adapter startup has begun, or false on immediate error
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean enable() {
- if (isEnabled()) {
- if (DBG) {
- Log.d(TAG, "enable(): BT already enabled!");
- }
- return true;
- }
- try {
- return mManagerService.enable(mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Turn off the local Bluetooth adapter—do not use without explicit
- * user action to turn off Bluetooth.
- * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
- * system services, and powers down the underlying Bluetooth hardware.
- * <p class="caution"><strong>Bluetooth should never be disabled without
- * direct user consent</strong>. The {@link #disable()} method is
- * provided only for applications that include a user interface for changing
- * system settings, such as a "power manager" app.</p>
- * <p>This is an asynchronous call: it will return immediately, and
- * clients should listen for {@link #ACTION_STATE_CHANGED}
- * to be notified of subsequent adapter state changes. If this call returns
- * true, then the adapter state will immediately transition from {@link
- * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
- * later transition to either {@link #STATE_OFF} or {@link
- * #STATE_ON}. If this call returns false then there was an
- * immediate problem that will prevent the adapter from being turned off -
- * such as the adapter already being turned off.
- *
- * @return true to indicate adapter shutdown has begun, or false on immediate error
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disable() {
- try {
- return mManagerService.disable(mAttributionSource, true);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Turn off the local Bluetooth adapter and don't persist the setting.
- *
- * @param persist Indicate whether the off state should be persisted following the next reboot
- * @return true to indicate adapter shutdown has begun, or false on immediate error
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean disable(boolean persist) {
-
- try {
- return mManagerService.disable(mAttributionSource, persist);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Returns the hardware address of the local Bluetooth adapter.
- * <p>For example, "00:11:22:AA:BB:CC".
- *
- * @return Bluetooth hardware address as string
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.LOCAL_MAC_ADDRESS,
- })
- public String getAddress() {
- try {
- return mManagerService.getAddress(mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return null;
- }
-
- /**
- * Get the friendly Bluetooth name of the local Bluetooth adapter.
- * <p>This name is visible to remote Bluetooth devices.
- *
- * @return the Bluetooth name, or null on error
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public String getName() {
- try {
- return mManagerService.getName(mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return null;
- }
-
- /** {@hide} */
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public int getNameLengthForAdvertise() {
- try {
- return mService.getNameLengthForAdvertise(mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return -1;
- }
-
- /**
- * Factory reset bluetooth settings.
- *
- * @return true to indicate that the config file was successfully cleared
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean factoryReset() {
- try {
- mServiceLock.readLock().lock();
- if (mService != null && mService.factoryReset(mAttributionSource)
- && mManagerService != null
- && mManagerService.onFactoryReset(mAttributionSource)) {
- return true;
- }
- Log.e(TAG, "factoryReset(): Setting persist.bluetooth.factoryreset to retry later");
- BluetoothProperties.factory_reset(true);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Get the UUIDs supported by the local Bluetooth adapter.
- *
- * @return the UUIDs supported by the local Bluetooth Adapter.
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @Nullable ParcelUuid[] getUuids() {
- if (getState() != STATE_ON) {
- return null;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getUuids(mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return null;
- }
-
- /**
- * Set the friendly Bluetooth name of the local Bluetooth adapter.
- * <p>This name is visible to remote Bluetooth devices.
- * <p>Valid Bluetooth names are a maximum of 248 bytes using UTF-8
- * encoding, although many remote devices can only display the first
- * 40 characters, and some may be limited to just 20.
- * <p>If Bluetooth state is not {@link #STATE_ON}, this API
- * will return false. After turning on Bluetooth,
- * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
- * to get the updated value.
- *
- * @param name a valid Bluetooth name
- * @return true if the name was set, false otherwise
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setName(String name) {
- if (getState() != STATE_ON) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.setName(name, mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Returns the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth
- * adapter.
- *
- * @return {@link BluetoothClass} Bluetooth CoD of local Bluetooth device.
- *
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothClass getBluetoothClass() {
- if (getState() != STATE_ON) {
- return null;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getBluetoothClass(mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return null;
- }
-
- /**
- * Sets the {@link BluetoothClass} Bluetooth Class of Device (CoD) of the local Bluetooth
- * adapter.
- *
- * <p>Note: This value persists across system reboot.
- *
- * @param bluetoothClass {@link BluetoothClass} to set the local Bluetooth adapter to.
- * @return true if successful, false if unsuccessful.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setBluetoothClass(BluetoothClass bluetoothClass) {
- if (getState() != STATE_ON) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.setBluetoothClass(bluetoothClass, mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Returns the Input/Output capability of the device for classic Bluetooth.
- *
- * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
- * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE},
- * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}.
- *
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @IoCapability
- public int getIoCapability() {
- if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
- try {
- mServiceLock.readLock().lock();
- if (mService != null) return mService.getIoCapability(mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage(), e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
- }
-
- /**
- * Sets the Input/Output capability of the device for classic Bluetooth.
- *
- * <p>Changing the Input/Output capability of a device only takes effect on restarting the
- * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()}
- * and {@link BluetoothAdapter#enable()} to see the changes.
- *
- * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
- * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN},
- * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setIoCapability(@IoCapability int capability) {
- if (getState() != STATE_ON) return false;
- try {
- mServiceLock.readLock().lock();
- if (mService != null) return mService.setIoCapability(capability, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage(), e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Returns the Input/Output capability of the device for BLE operations.
- *
- * @return Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
- * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN}, {@link #IO_CAPABILITY_NONE},
- * {@link #IO_CAPABILITY_KBDISP} or {@link #IO_CAPABILITY_UNKNOWN}.
- *
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @IoCapability
- public int getLeIoCapability() {
- if (getState() != STATE_ON) return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
- try {
- mServiceLock.readLock().lock();
- if (mService != null) return mService.getLeIoCapability(mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage(), e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothAdapter.IO_CAPABILITY_UNKNOWN;
- }
-
- /**
- * Sets the Input/Output capability of the device for BLE operations.
- *
- * <p>Changing the Input/Output capability of a device only takes effect on restarting the
- * Bluetooth stack. You would need to restart the stack using {@link BluetoothAdapter#disable()}
- * and {@link BluetoothAdapter#enable()} to see the changes.
- *
- * @param capability Input/Output capability of the device. One of {@link #IO_CAPABILITY_OUT},
- * {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_IN},
- * {@link #IO_CAPABILITY_NONE} or {@link #IO_CAPABILITY_KBDISP}.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setLeIoCapability(@IoCapability int capability) {
- if (getState() != STATE_ON) return false;
- try {
- mServiceLock.readLock().lock();
- if (mService != null) return mService.setLeIoCapability(capability, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.getMessage(), e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Get the current Bluetooth scan mode of the local Bluetooth adapter.
- * <p>The Bluetooth scan mode determines if the local adapter is
- * connectable and/or discoverable from remote Bluetooth devices.
- * <p>Possible values are:
- * {@link #SCAN_MODE_NONE},
- * {@link #SCAN_MODE_CONNECTABLE},
- * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
- * <p>If Bluetooth state is not {@link #STATE_ON}, this API
- * will return {@link #SCAN_MODE_NONE}. After turning on Bluetooth,
- * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
- * to get the updated value.
- *
- * @return scan mode
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- @ScanMode
- public int getScanMode() {
- if (getState() != STATE_ON) {
- return SCAN_MODE_NONE;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getScanMode(mAttributionSource);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } finally {
- mServiceLock.readLock().unlock();
- }
- return SCAN_MODE_NONE;
- }
-
- /**
- * Set the local Bluetooth adapter connectablility and discoverability.
- * <p>If the scan mode is set to {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
- * it will change to {@link #SCAN_MODE_CONNECTABLE} after the discoverable timeout.
- * The discoverable timeout can be set with {@link #setDiscoverableTimeout} and
- * checked with {@link #getDiscoverableTimeout}. By default, the timeout is usually
- * 120 seconds on phones which is enough for a remote device to initiate and complete
- * its discovery process.
- * <p>Applications cannot set the scan mode. They should use
- * {@link #ACTION_REQUEST_DISCOVERABLE} instead.
- *
- * @param mode represents the desired state of the local device scan mode
- *
- * @return status code indicating whether the scan mode was successfully set
- * @hide
- */
- @SystemApi
- @RequiresBluetoothScanPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_SCAN,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @ScanModeStatusCode
- public int setScanMode(@ScanMode int mode) {
- if (getState() != STATE_ON) {
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.setScanMode(mode, mAttributionSource);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothStatusCodes.ERROR_UNKNOWN;
- }
-
- /**
- * Get the timeout duration of the {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
- *
- * @return the duration of the discoverable timeout or null if an error has occurred
- */
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public @Nullable Duration getDiscoverableTimeout() {
- if (getState() != STATE_ON) {
- return null;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- long timeout = mService.getDiscoverableTimeout(mAttributionSource);
- return (timeout == -1) ? null : Duration.ofSeconds(timeout);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } finally {
- mServiceLock.readLock().unlock();
- }
- return null;
- }
-
- /**
- * Set the total time the Bluetooth local adapter will stay discoverable when
- * {@link #setScanMode} is called with {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE} mode.
- * After this timeout, the scan mode will fallback to {@link #SCAN_MODE_CONNECTABLE}.
- * <p>If <code>timeout</code> is set to 0, no timeout will occur and the scan mode will
- * be persisted until a subsequent call to {@link #setScanMode}.
- *
- * @param timeout represents the total duration the local Bluetooth adapter will remain
- * discoverable, or no timeout if set to 0
- * @return whether the timeout was successfully set
- * @throws IllegalArgumentException if <code>timeout</code> duration in seconds is more
- * than {@link Integer#MAX_VALUE}
- * @hide
- */
- @SystemApi
- @RequiresBluetoothScanPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_SCAN,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- @ScanModeStatusCode
- public int setDiscoverableTimeout(@NonNull Duration timeout) {
- if (getState() != STATE_ON) {
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- }
- if (timeout.toSeconds() > Integer.MAX_VALUE) {
- throw new IllegalArgumentException("Timeout in seconds must be less or equal to "
- + Integer.MAX_VALUE);
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.setDiscoverableTimeout(timeout.toSeconds(), mAttributionSource);
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothStatusCodes.ERROR_UNKNOWN;
- }
-
- /**
- * Get the end time of the latest remote device discovery process.
- *
- * @return the latest time that the bluetooth adapter was/will be in discovery mode, in
- * milliseconds since the epoch. This time can be in the future if {@link #startDiscovery()} has
- * been called recently.
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public long getDiscoveryEndMillis() {
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getDiscoveryEndMillis(mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return -1;
- }
-
- /**
- * Start the remote device discovery process.
- * <p>The discovery process usually involves an inquiry scan of about 12
- * seconds, followed by a page scan of each new device to retrieve its
- * Bluetooth name.
- * <p>This is an asynchronous call, it will return immediately. Register
- * for {@link #ACTION_DISCOVERY_STARTED} and {@link
- * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
- * discovery starts and completes. Register for {@link
- * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
- * are found.
- * <p>Device discovery is a heavyweight procedure. New connections to
- * remote Bluetooth devices should not be attempted while discovery is in
- * progress, and existing connections will experience limited bandwidth
- * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
- * discovery. Discovery is not managed by the Activity,
- * but is run as a system service, so an application should always call
- * {@link BluetoothAdapter#cancelDiscovery()} even if it
- * did not directly request a discovery, just to be sure.
- * <p>Device discovery will only find remote devices that are currently
- * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
- * not discoverable by default, and need to be entered into a special mode.
- * <p>If Bluetooth state is not {@link #STATE_ON}, this API
- * will return false. After turning on Bluetooth, wait for {@link #ACTION_STATE_CHANGED}
- * with {@link #STATE_ON} to get the updated value.
- * <p>If a device is currently bonding, this request will be queued and executed once that
- * device has finished bonding. If a request is already queued, this request will be ignored.
- *
- * @return true on success, false on error
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public boolean startDiscovery() {
- if (getState() != STATE_ON) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.startDiscovery(mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Cancel the current device discovery process.
- * <p>Because discovery is a heavyweight procedure for the Bluetooth
- * adapter, this method should always be called before attempting to connect
- * to a remote device with {@link
- * android.bluetooth.BluetoothSocket#connect()}. Discovery is not managed by
- * the Activity, but is run as a system service, so an application should
- * always call cancel discovery even if it did not directly request a
- * discovery, just to be sure.
- * <p>If Bluetooth state is not {@link #STATE_ON}, this API
- * will return false. After turning on Bluetooth,
- * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
- * to get the updated value.
- *
- * @return true on success, false on error
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public boolean cancelDiscovery() {
- if (getState() != STATE_ON) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.cancelDiscovery(mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Return true if the local Bluetooth adapter is currently in the device
- * discovery process.
- * <p>Device discovery is a heavyweight procedure. New connections to
- * remote Bluetooth devices should not be attempted while discovery is in
- * progress, and existing connections will experience limited bandwidth
- * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
- * discovery.
- * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
- * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
- * starts or completes.
- * <p>If Bluetooth state is not {@link #STATE_ON}, this API
- * will return false. After turning on Bluetooth,
- * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
- * to get the updated value.
- *
- * @return true if discovering
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public boolean isDiscovering() {
- if (getState() != STATE_ON) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isDiscovering(mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Removes the active device for the grouping of @ActiveDeviceUse specified
- *
- * @param profiles represents the purpose for which we are setting this as the active device.
- * Possible values are:
- * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO},
- * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL},
- * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
- * @return false on immediate error, true otherwise
- * @throws IllegalArgumentException if device is null or profiles is not one of
- * {@link ActiveDeviceUse}
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public boolean removeActiveDevice(@ActiveDeviceUse int profiles) {
- if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL
- && profiles != ACTIVE_DEVICE_ALL) {
- Log.e(TAG, "Invalid profiles param value in removeActiveDevice");
- throw new IllegalArgumentException("Profiles must be one of "
- + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, "
- + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or "
- + "BluetoothAdapter.ACTIVE_DEVICE_ALL");
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- if (DBG) Log.d(TAG, "removeActiveDevice, profiles: " + profiles);
- return mService.removeActiveDevice(profiles, mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
-
- return false;
- }
-
- /**
- * Sets device as the active devices for the profiles passed into the function
- *
- * @param device is the remote bluetooth device
- * @param profiles represents the purpose for which we are setting this as the active device.
- * Possible values are:
- * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO},
- * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL},
- * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
- * @return false on immediate error, true otherwise
- * @throws IllegalArgumentException if device is null or profiles is not one of
- * {@link ActiveDeviceUse}
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public boolean setActiveDevice(@NonNull BluetoothDevice device,
- @ActiveDeviceUse int profiles) {
- if (device == null) {
- Log.e(TAG, "setActiveDevice: Null device passed as parameter");
- throw new IllegalArgumentException("device cannot be null");
- }
- if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL
- && profiles != ACTIVE_DEVICE_ALL) {
- Log.e(TAG, "Invalid profiles param value in setActiveDevice");
- throw new IllegalArgumentException("Profiles must be one of "
- + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, "
- + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or "
- + "BluetoothAdapter.ACTIVE_DEVICE_ALL");
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- if (DBG) {
- Log.d(TAG, "setActiveDevice, device: " + device + ", profiles: " + profiles);
- }
- return mService.setActiveDevice(device, profiles, mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
-
- return false;
- }
-
- /**
- * Get the active devices for the BluetoothProfile specified
- *
- * @param profile is the profile from which we want the active devices.
- * Possible values are:
- * {@link BluetoothProfile#HEADSET},
- * {@link BluetoothProfile#A2DP},
- * {@link BluetoothProfile#HEARING_AID}
- * {@link BluetoothProfile#LE_AUDIO}
- * @return A list of active bluetooth devices
- * @throws IllegalArgumentException If profile is not one of {@link ActiveDeviceProfile}
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @NonNull List<BluetoothDevice> getActiveDevices(@ActiveDeviceProfile int profile) {
- if (profile != BluetoothProfile.HEADSET
- && profile != BluetoothProfile.A2DP
- && profile != BluetoothProfile.HEARING_AID
- && profile != BluetoothProfile.LE_AUDIO) {
- Log.e(TAG, "Invalid profile param value in getActiveDevices");
- throw new IllegalArgumentException("Profiles must be one of "
- + "BluetoothProfile.A2DP, "
- + "BluetoothProfile.HEARING_AID, or"
- + "BluetoothProfile.HEARING_AID"
- + "BluetoothProfile.LE_AUDIO");
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- if (DBG) {
- Log.d(TAG, "getActiveDevices(profile= "
- + BluetoothProfile.getProfileName(profile) + ")");
- }
- return mService.getActiveDevices(profile, mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
-
- return new ArrayList<>();
- }
-
- /**
- * Return true if the multi advertisement is supported by the chipset
- *
- * @return true if Multiple Advertisement feature is supported
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public boolean isMultipleAdvertisementSupported() {
- if (getState() != STATE_ON) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isMultiAdvertisementSupported();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get isMultipleAdvertisementSupported, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Returns {@code true} if BLE scan is always available, {@code false} otherwise. <p>
- *
- * If this returns {@code true}, application can issue {@link BluetoothLeScanner#startScan} and
- * fetch scan results even when Bluetooth is turned off.<p>
- *
- * To change this setting, use {@link #ACTION_REQUEST_BLE_SCAN_ALWAYS_AVAILABLE}.
- *
- * @hide
- */
- @SystemApi
- @RequiresNoPermission
- public boolean isBleScanAlwaysAvailable() {
- try {
- return mManagerService.isBleScanAlwaysAvailable();
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception when calling isBleScanAlwaysAvailable", e);
- return false;
- }
- }
-
- /*
- private static final String BLUETOOTH_FILTERING_CACHE_PROPERTY =
- "cache_key.bluetooth.is_offloaded_filtering_supported";
- private final PropertyInvalidatedCache<Void, Boolean> mBluetoothFilteringCache =
- new PropertyInvalidatedCache<Void, Boolean>(
- 8, BLUETOOTH_FILTERING_CACHE_PROPERTY) {
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public Boolean recompute(Void query) {
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isOffloadedFilteringSupported();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
-
- }
- };
- */
-
- /** @hide */
- /*
- @RequiresNoPermission
- public void disableIsOffloadedFilteringSupportedCache() {
- mBluetoothFilteringCache.disableLocal();
- }
- */
-
- /** @hide */
- /*
- public static void invalidateIsOffloadedFilteringSupportedCache() {
- PropertyInvalidatedCache.invalidateCache(BLUETOOTH_FILTERING_CACHE_PROPERTY);
- }
- */
-
- /**
- * Return true if offloaded filters are supported
- *
- * @return true if chipset supports on-chip filtering
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public boolean isOffloadedFilteringSupported() {
- if (!getLeAccess()) {
- return false;
- }
- //return mBluetoothFilteringCache.query(null);
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isOffloadedFilteringSupported();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get isOffloadedFilteringSupported, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Return true if offloaded scan batching is supported
- *
- * @return true if chipset supports on-chip scan batching
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public boolean isOffloadedScanBatchingSupported() {
- if (!getLeAccess()) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isOffloadedScanBatchingSupported();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get isOffloadedScanBatchingSupported, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Return true if LE 2M PHY feature is supported.
- *
- * @return true if chipset supports LE 2M PHY feature
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public boolean isLe2MPhySupported() {
- if (!getLeAccess()) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isLe2MPhySupported();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get isExtendedAdvertisingSupported, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Return true if LE Coded PHY feature is supported.
- *
- * @return true if chipset supports LE Coded PHY feature
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public boolean isLeCodedPhySupported() {
- if (!getLeAccess()) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isLeCodedPhySupported();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get isLeCodedPhySupported, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Return true if LE Extended Advertising feature is supported.
- *
- * @return true if chipset supports LE Extended Advertising feature
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public boolean isLeExtendedAdvertisingSupported() {
- if (!getLeAccess()) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isLeExtendedAdvertisingSupported();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get isLeExtendedAdvertisingSupported, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
- * Return true if LE Periodic Advertising feature is supported.
- *
- * @return true if chipset supports LE Periodic Advertising feature
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public boolean isLePeriodicAdvertisingSupported() {
- if (!getLeAccess()) {
- return false;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isLePeriodicAdvertisingSupported();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get isLePeriodicAdvertisingSupported, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothStatusCodes.FEATURE_SUPPORTED,
- BluetoothStatusCodes.ERROR_UNKNOWN,
- BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
- BluetoothStatusCodes.FEATURE_NOT_SUPPORTED,
- })
- public @interface LeFeatureReturnValues {}
-
- /**
- * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if the LE audio feature is
- * supported, {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is not
- * supported, or an error code.
- *
- * @return whether the LE audio is supported
- */
- @RequiresNoPermission
- public @LeFeatureReturnValues int isLeAudioSupported() {
- if (!getLeAccess()) {
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isLeAudioSupported();
- }
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothStatusCodes.ERROR_UNKNOWN;
- }
-
- /**
- * Returns {@link BluetoothStatusCodes#FEATURE_SUPPORTED} if LE Periodic Advertising Sync
- * Transfer Sender feature is supported,
- * {@link BluetoothStatusCodes#FEATURE_NOT_SUPPORTED} if the feature is not supported, or
- * an error code
- *
- * @return whether the chipset supports the LE Periodic Advertising Sync Transfer Sender feature
- */
- @RequiresNoPermission
- public @LeFeatureReturnValues int isLePeriodicAdvertisingSyncTransferSenderSupported() {
- if (!getLeAccess()) {
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.isLePeriodicAdvertisingSyncTransferSenderSupported();
- }
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothStatusCodes.ERROR_UNKNOWN;
- }
-
- /**
- * Return the maximum LE advertising data length in bytes,
- * if LE Extended Advertising feature is supported, 0 otherwise.
- *
- * @return the maximum LE advertising data length.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public int getLeMaximumAdvertisingDataLength() {
- if (!getLeAccess()) {
- return 0;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getLeMaximumAdvertisingDataLength();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get getLeMaximumAdvertisingDataLength, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return 0;
- }
-
- /**
- * Return true if Hearing Aid Profile is supported.
- *
- * @return true if phone supports Hearing Aid Profile
- */
- @RequiresNoPermission
- private boolean isHearingAidProfileSupported() {
- try {
- return mManagerService.isHearingAidProfileSupported();
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception when calling isHearingAidProfileSupported", e);
- return false;
- }
- }
-
- /**
- * Get the maximum number of connected audio devices.
- *
- * @return the maximum number of connected audio devices
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getMaxConnectedAudioDevices() {
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getMaxConnectedAudioDevices(mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "failed to get getMaxConnectedAudioDevices, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return 1;
- }
-
- /**
- * Return true if hardware has entries available for matching beacons
- *
- * @return true if there are hw entries available for matching beacons
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isHardwareTrackingFiltersAvailable() {
- if (!getLeAccess()) {
- return false;
- }
- try {
- IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
- if (iGatt == null) {
- // BLE is not supported
- return false;
- }
- return (iGatt.numHwTrackFiltersAvailable(mAttributionSource) != 0);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Request the record of {@link BluetoothActivityEnergyInfo} object that
- * has the activity and energy info. This can be used to ascertain what
- * the controller has been up to, since the last sample.
- *
- * A null value for the activity info object may be sent if the bluetooth service is
- * unreachable or the device does not support reporting such information.
- *
- * @param result The callback to which to send the activity info.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public void requestControllerActivityEnergyInfo(ResultReceiver result) {
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- mService.requestActivityInfo(result, mAttributionSource);
- result = null;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getControllerActivityEnergyInfoCallback: " + e);
- } finally {
- mServiceLock.readLock().unlock();
- if (result != null) {
- // Only send an immediate result if we failed.
- result.send(0, null);
- }
- }
- }
-
- /**
- * Fetches a list of the most recently connected bluetooth devices ordered by how recently they
- * were connected with most recently first and least recently last
- *
- * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were
- * connected
- *
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
- if (getState() != STATE_ON) {
- return new ArrayList<>();
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return Attributable.setAttributionSource(
- mService.getMostRecentlyConnectedDevices(mAttributionSource),
- mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return new ArrayList<>();
- }
-
- /**
- * Return the set of {@link BluetoothDevice} objects that are bonded
- * (paired) to the local adapter.
- * <p>If Bluetooth state is not {@link #STATE_ON}, this API
- * will return an empty set. After turning on Bluetooth,
- * wait for {@link #ACTION_STATE_CHANGED} with {@link #STATE_ON}
- * to get the updated value.
- *
- * @return unmodifiable set of {@link BluetoothDevice}, or null on error
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public Set<BluetoothDevice> getBondedDevices() {
- if (getState() != STATE_ON) {
- return toDeviceSet(Arrays.asList());
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return toDeviceSet(Attributable.setAttributionSource(
- Arrays.asList(mService.getBondedDevices(mAttributionSource)),
- mAttributionSource));
- }
- return toDeviceSet(Arrays.asList());
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return null;
- }
-
- /**
- * Gets the currently supported profiles by the adapter.
- *
- * <p> This can be used to check whether a profile is supported before attempting
- * to connect to its respective proxy.
- *
- * @return a list of integers indicating the ids of supported profiles as defined in {@link
- * BluetoothProfile}.
- * @hide
- */
- @RequiresNoPermission
- public @NonNull List<Integer> getSupportedProfiles() {
- final ArrayList<Integer> supportedProfiles = new ArrayList<Integer>();
-
- try {
- synchronized (mManagerCallback) {
- if (mService != null) {
- final long supportedProfilesBitMask = mService.getSupportedProfiles();
-
- for (int i = 0; i <= BluetoothProfile.MAX_PROFILE_ID; i++) {
- if ((supportedProfilesBitMask & (1 << i)) != 0) {
- supportedProfiles.add(i);
- }
- }
- } else {
- // Bluetooth is disabled. Just fill in known supported Profiles
- if (isHearingAidProfileSupported()) {
- supportedProfiles.add(BluetoothProfile.HEARING_AID);
- }
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getSupportedProfiles:", e);
- }
- return supportedProfiles;
- }
-
- /*
- private static final String BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY =
- "cache_key.bluetooth.get_adapter_connection_state";
- private final PropertyInvalidatedCache<Void, Integer>
- mBluetoothGetAdapterConnectionStateCache =
- new PropertyInvalidatedCache<Void, Integer> (
- 8, BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY) {
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public Integer recompute(Void query) {
- try {
- return mService.getAdapterConnectionState();
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
- }
- };
- */
-
- /** @hide */
- /*
- @RequiresNoPermission
- public void disableGetAdapterConnectionStateCache() {
- mBluetoothGetAdapterConnectionStateCache.disableLocal();
- }
- */
-
- /** @hide */
- /*
- public static void invalidateGetAdapterConnectionStateCache() {
- PropertyInvalidatedCache.invalidateCache(
- BLUETOOTH_GET_ADAPTER_CONNECTION_STATE_CACHE_PROPERTY);
- }
- */
-
- /**
- * Get the current connection state of the local Bluetooth adapter.
- * This can be used to check whether the local Bluetooth adapter is connected
- * to any profile of any other remote Bluetooth Device.
- *
- * <p> Use this function along with {@link #ACTION_CONNECTION_STATE_CHANGED}
- * intent to get the connection state of the adapter.
- *
- * @return One of {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTED}, {@link
- * #STATE_CONNECTING} or {@link #STATE_DISCONNECTED}
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public int getConnectionState() {
- if (getState() != STATE_ON) {
- return BluetoothAdapter.STATE_DISCONNECTED;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getAdapterConnectionState();
- }
- //return mBluetoothGetAdapterConnectionStateCache.query(null);
- } catch (RemoteException e) {
- Log.e(TAG, "failed to getConnectionState, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothAdapter.STATE_DISCONNECTED;
- }
-
- /*
- private static final String BLUETOOTH_PROFILE_CACHE_PROPERTY =
- "cache_key.bluetooth.get_profile_connection_state";
- private final PropertyInvalidatedCache<Integer, Integer>
- mGetProfileConnectionStateCache =
- new PropertyInvalidatedCache<Integer, Integer>(
- 8, BLUETOOTH_PROFILE_CACHE_PROPERTY) {
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public Integer recompute(Integer query) {
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.getProfileConnectionState(query);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "getProfileConnectionState:", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothProfile.STATE_DISCONNECTED;
- }
- @Override
- public String queryToString(Integer query) {
- return String.format("getProfileConnectionState(profile=\"%d\")",
- query);
- }
- };
- */
-
- /** @hide */
- /*
- @RequiresNoPermission
- public void disableGetProfileConnectionStateCache() {
- mGetProfileConnectionStateCache.disableLocal();
- }
- */
-
- /** @hide */
- /*
- public static void invalidateGetProfileConnectionStateCache() {
- PropertyInvalidatedCache.invalidateCache(BLUETOOTH_PROFILE_CACHE_PROPERTY);
- }
- */
-
- /**
- * Get the current connection state of a profile.
- * This function can be used to check whether the local Bluetooth adapter
- * is connected to any remote device for a specific profile.
- * Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP}.
- *
- * <p> Return value can be one of
- * {@link BluetoothProfile#STATE_DISCONNECTED},
- * {@link BluetoothProfile#STATE_CONNECTING},
- * {@link BluetoothProfile#STATE_CONNECTED},
- * {@link BluetoothProfile#STATE_DISCONNECTING}
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public int getProfileConnectionState(int profile) {
- if (getState() != STATE_ON) {
- return BluetoothProfile.STATE_DISCONNECTED;
- }
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- mService.getProfileConnectionState(profile);
- }
- //return mGetProfileConnectionStateCache.query(new Integer(profile));
- } catch (RemoteException e) {
- Log.e(TAG, "failed to getProfileConnectionState, error: ", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return BluetoothProfile.STATE_DISCONNECTED;
- }
-
- /**
- * Create a listening, secure RFCOMM Bluetooth socket.
- * <p>A remote device connecting to this socket will be authenticated and
- * communication on this socket will be encrypted.
- * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
- * connections from a listening {@link BluetoothServerSocket}.
- * <p>Valid RFCOMM channels are in range 1 to 30.
- *
- * @param channel RFCOMM channel to listen on
- * @return a listening RFCOMM BluetoothServerSocket
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions, or channel in use.
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingRfcommOn(int channel) throws IOException {
- return listenUsingRfcommOn(channel, false, false);
- }
-
- /**
- * Create a listening, secure RFCOMM Bluetooth socket.
- * <p>A remote device connecting to this socket will be authenticated and
- * communication on this socket will be encrypted.
- * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
- * connections from a listening {@link BluetoothServerSocket}.
- * <p>Valid RFCOMM channels are in range 1 to 30.
- * <p>To auto assign a channel without creating a SDP record use
- * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as channel number.
- *
- * @param channel RFCOMM channel to listen on
- * @param mitm enforce person-in-the-middle protection for authentication.
- * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2
- * connections.
- * @return a listening RFCOMM BluetoothServerSocket
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions, or channel in use.
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingRfcommOn(int channel, boolean mitm,
- boolean min16DigitPin) throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, true, true, channel, mitm,
- min16DigitPin);
- int errno = socket.mSocket.bindListen();
- if (channel == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- socket.setChannel(socket.mSocket.getPort());
- }
- if (errno != 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- throw new IOException("Error: " + errno);
- }
- return socket;
- }
-
- /**
- * Create a listening, secure RFCOMM Bluetooth socket with Service Record.
- * <p>A remote device connecting to this socket will be authenticated and
- * communication on this socket will be encrypted.
- * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
- * connections from a listening {@link BluetoothServerSocket}.
- * <p>The system will assign an unused RFCOMM channel to listen on.
- * <p>The system will also register a Service Discovery
- * Protocol (SDP) record with the local SDP server containing the specified
- * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
- * can use the same UUID to query our SDP server and discover which channel
- * to connect to. This SDP record will be removed when this socket is
- * closed, or if this application closes unexpectedly.
- * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
- * connect to this socket from another device using the same {@link UUID}.
- *
- * @param name service name for SDP record
- * @param uuid uuid for SDP record
- * @return a listening RFCOMM BluetoothServerSocket
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions, or channel in use.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
- throws IOException {
- return createNewRfcommSocketAndRecord(name, uuid, true, true);
- }
-
- /**
- * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
- * <p>The link key is not required to be authenticated, i.e the communication may be
- * vulnerable to Person In the Middle attacks. For Bluetooth 2.1 devices,
- * the link will be encrypted, as encryption is mandatory.
- * For legacy devices (pre Bluetooth 2.1 devices) the link will not
- * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
- * encrypted and authenticated communication channel is desired.
- * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
- * connections from a listening {@link BluetoothServerSocket}.
- * <p>The system will assign an unused RFCOMM channel to listen on.
- * <p>The system will also register a Service Discovery
- * Protocol (SDP) record with the local SDP server containing the specified
- * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
- * can use the same UUID to query our SDP server and discover which channel
- * to connect to. This SDP record will be removed when this socket is
- * closed, or if this application closes unexpectedly.
- * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
- * connect to this socket from another device using the same {@link UUID}.
- *
- * @param name service name for SDP record
- * @param uuid uuid for SDP record
- * @return a listening RFCOMM BluetoothServerSocket
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions, or channel in use.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
- throws IOException {
- return createNewRfcommSocketAndRecord(name, uuid, false, false);
- }
-
- /**
- * Create a listening, encrypted,
- * RFCOMM Bluetooth socket with Service Record.
- * <p>The link will be encrypted, but the link key is not required to be authenticated
- * i.e the communication is vulnerable to Person In the Middle attacks. Use
- * {@link #listenUsingRfcommWithServiceRecord}, to ensure an authenticated link key.
- * <p> Use this socket if authentication of link key is not possible.
- * For example, for Bluetooth 2.1 devices, if any of the devices does not have
- * an input and output capability or just has the ability to display a numeric key,
- * a secure socket connection is not possible and this socket can be used.
- * Use {@link #listenUsingInsecureRfcommWithServiceRecord}, if encryption is not required.
- * For Bluetooth 2.1 devices, the link will be encrypted, as encryption is mandatory.
- * For more details, refer to the Security Model section 5.2 (vol 3) of
- * Bluetooth Core Specification version 2.1 + EDR.
- * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
- * connections from a listening {@link BluetoothServerSocket}.
- * <p>The system will assign an unused RFCOMM channel to listen on.
- * <p>The system will also register a Service Discovery
- * Protocol (SDP) record with the local SDP server containing the specified
- * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
- * can use the same UUID to query our SDP server and discover which channel
- * to connect to. This SDP record will be removed when this socket is
- * closed, or if this application closes unexpectedly.
- * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
- * connect to this socket from another device using the same {@link UUID}.
- *
- * @param name service name for SDP record
- * @param uuid uuid for SDP record
- * @return a listening RFCOMM BluetoothServerSocket
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions, or channel in use.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingEncryptedRfcommWithServiceRecord(String name, UUID uuid)
- throws IOException {
- return createNewRfcommSocketAndRecord(name, uuid, false, true);
- }
-
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
- boolean auth, boolean encrypt) throws IOException {
- BluetoothServerSocket socket;
- socket = new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, auth, encrypt,
- new ParcelUuid(uuid));
- socket.setServiceName(name);
- int errno = socket.mSocket.bindListen();
- if (errno != 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- throw new IOException("Error: " + errno);
- }
- return socket;
- }
-
- /**
- * Construct an unencrypted, unauthenticated, RFCOMM server socket.
- * Call #accept to retrieve connections to this socket.
- *
- * @return An RFCOMM BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingInsecureRfcommOn(int port) throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_RFCOMM, false, false, port);
- int errno = socket.mSocket.bindListen();
- if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- socket.setChannel(socket.mSocket.getPort());
- }
- if (errno != 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- throw new IOException("Error: " + errno);
- }
- return socket;
- }
-
- /**
- * Construct an encrypted, authenticated, L2CAP server socket.
- * Call #accept to retrieve connections to this socket.
- * <p>To auto assign a port without creating a SDP record use
- * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
- *
- * @param port the PSM to listen on
- * @param mitm enforce person-in-the-middle protection for authentication.
- * @param min16DigitPin enforce a pin key length og minimum 16 digit for sec mode 2
- * connections.
- * @return An L2CAP BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingL2capOn(int port, boolean mitm, boolean min16DigitPin)
- throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, true, true, port, mitm,
- min16DigitPin);
- int errno = socket.mSocket.bindListen();
- if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- int assignedChannel = socket.mSocket.getPort();
- if (DBG) Log.d(TAG, "listenUsingL2capOn: set assigned channel to " + assignedChannel);
- socket.setChannel(assignedChannel);
- }
- if (errno != 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- throw new IOException("Error: " + errno);
- }
- return socket;
- }
-
- /**
- * Construct an encrypted, authenticated, L2CAP server socket.
- * Call #accept to retrieve connections to this socket.
- * <p>To auto assign a port without creating a SDP record use
- * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
- *
- * @param port the PSM to listen on
- * @return An L2CAP BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingL2capOn(int port) throws IOException {
- return listenUsingL2capOn(port, false, false);
- }
-
- /**
- * Construct an insecure L2CAP server socket.
- * Call #accept to retrieve connections to this socket.
- * <p>To auto assign a port without creating a SDP record use
- * {@link #SOCKET_CHANNEL_AUTO_STATIC_NO_SDP} as port number.
- *
- * @param port the PSM to listen on
- * @return An L2CAP BluetoothServerSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothServerSocket listenUsingInsecureL2capOn(int port) throws IOException {
- Log.d(TAG, "listenUsingInsecureL2capOn: port=" + port);
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP, false, false, port, false,
- false);
- int errno = socket.mSocket.bindListen();
- if (port == SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- int assignedChannel = socket.mSocket.getPort();
- if (DBG) {
- Log.d(TAG, "listenUsingInsecureL2capOn: set assigned channel to "
- + assignedChannel);
- }
- socket.setChannel(assignedChannel);
- }
- if (errno != 0) {
- //TODO(BT): Throw the same exception error code
- // that the previous code was using.
- //socket.mSocket.throwErrnoNative(errno);
- throw new IOException("Error: " + errno);
- }
- return socket;
-
- }
-
- /**
- * Read the local Out of Band Pairing Data
- *
- * @return Pair<byte[], byte[]> of Hash and Randomizer
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public Pair<byte[], byte[]> readOutOfBandData() {
- return null;
- }
-
- /**
- * Get the profile proxy object associated with the profile.
- *
- * <p>Profile can be one of {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#A2DP},
- * {@link BluetoothProfile#GATT}, {@link BluetoothProfile#HEARING_AID}, or {@link
- * BluetoothProfile#GATT_SERVER}. Clients must implement {@link
- * BluetoothProfile.ServiceListener} to get notified of the connection status and to get the
- * proxy object.
- *
- * @param context Context of the application
- * @param listener The service Listener for connection callbacks.
- * @param profile The Bluetooth profile; either {@link BluetoothProfile#HEADSET},
- * {@link BluetoothProfile#A2DP}, {@link BluetoothProfile#GATT}, {@link
- * BluetoothProfile#HEARING_AID} or {@link BluetoothProfile#GATT_SERVER}.
- * @return true on success, false on error
- */
- @SuppressLint({
- "AndroidFrameworkRequiresPermission",
- "AndroidFrameworkBluetoothPermission"
- })
- public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
- int profile) {
- if (context == null || listener == null) {
- return false;
- }
-
- if (profile == BluetoothProfile.HEADSET) {
- BluetoothHeadset headset = new BluetoothHeadset(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.A2DP) {
- BluetoothA2dp a2dp = new BluetoothA2dp(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.A2DP_SINK) {
- BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
- BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.HID_HOST) {
- BluetoothHidHost iDev = new BluetoothHidHost(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.PAN) {
- BluetoothPan pan = new BluetoothPan(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.PBAP) {
- BluetoothPbap pbap = new BluetoothPbap(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.HEALTH) {
- Log.e(TAG, "getProfileProxy(): BluetoothHealth is deprecated");
- return false;
- } else if (profile == BluetoothProfile.MAP) {
- BluetoothMap map = new BluetoothMap(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.HEADSET_CLIENT) {
- BluetoothHeadsetClient headsetClient =
- new BluetoothHeadsetClient(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.SAP) {
- BluetoothSap sap = new BluetoothSap(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.PBAP_CLIENT) {
- BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.MAP_CLIENT) {
- BluetoothMapClient mapClient = new BluetoothMapClient(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.HID_DEVICE) {
- BluetoothHidDevice hidDevice = new BluetoothHidDevice(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.HEARING_AID) {
- if (isHearingAidProfileSupported()) {
- BluetoothHearingAid hearingAid = new BluetoothHearingAid(context, listener, this);
- return true;
- }
- return false;
- } else if (profile == BluetoothProfile.LE_AUDIO) {
- BluetoothLeAudio leAudio = new BluetoothLeAudio(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.VOLUME_CONTROL) {
- BluetoothVolumeControl vcs = new BluetoothVolumeControl(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.CSIP_SET_COORDINATOR) {
- BluetoothCsipSetCoordinator csipSetCoordinator =
- new BluetoothCsipSetCoordinator(context, listener, this);
- return true;
- } else if (profile == BluetoothProfile.LE_CALL_CONTROL) {
- BluetoothLeCallControl tbs = new BluetoothLeCallControl(context, listener);
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Close the connection of the profile proxy to the Service.
- *
- * <p> Clients should call this when they are no longer using
- * the proxy obtained from {@link #getProfileProxy}.
- * Profile can be one of {@link BluetoothProfile#HEADSET} or {@link BluetoothProfile#A2DP}
- *
- * @param profile
- * @param proxy Profile proxy object
- */
- @SuppressLint({
- "AndroidFrameworkRequiresPermission",
- "AndroidFrameworkBluetoothPermission"
- })
- public void closeProfileProxy(int profile, BluetoothProfile proxy) {
- if (proxy == null) {
- return;
- }
-
- switch (profile) {
- case BluetoothProfile.HEADSET:
- BluetoothHeadset headset = (BluetoothHeadset) proxy;
- headset.close();
- break;
- case BluetoothProfile.A2DP:
- BluetoothA2dp a2dp = (BluetoothA2dp) proxy;
- a2dp.close();
- break;
- case BluetoothProfile.A2DP_SINK:
- BluetoothA2dpSink a2dpSink = (BluetoothA2dpSink) proxy;
- a2dpSink.close();
- break;
- case BluetoothProfile.AVRCP_CONTROLLER:
- BluetoothAvrcpController avrcp = (BluetoothAvrcpController) proxy;
- avrcp.close();
- break;
- case BluetoothProfile.HID_HOST:
- BluetoothHidHost iDev = (BluetoothHidHost) proxy;
- iDev.close();
- break;
- case BluetoothProfile.PAN:
- BluetoothPan pan = (BluetoothPan) proxy;
- pan.close();
- break;
- case BluetoothProfile.PBAP:
- BluetoothPbap pbap = (BluetoothPbap) proxy;
- pbap.close();
- break;
- case BluetoothProfile.GATT:
- BluetoothGatt gatt = (BluetoothGatt) proxy;
- gatt.close();
- break;
- case BluetoothProfile.GATT_SERVER:
- BluetoothGattServer gattServer = (BluetoothGattServer) proxy;
- gattServer.close();
- break;
- case BluetoothProfile.MAP:
- BluetoothMap map = (BluetoothMap) proxy;
- map.close();
- break;
- case BluetoothProfile.HEADSET_CLIENT:
- BluetoothHeadsetClient headsetClient = (BluetoothHeadsetClient) proxy;
- headsetClient.close();
- break;
- case BluetoothProfile.SAP:
- BluetoothSap sap = (BluetoothSap) proxy;
- sap.close();
- break;
- case BluetoothProfile.PBAP_CLIENT:
- BluetoothPbapClient pbapClient = (BluetoothPbapClient) proxy;
- pbapClient.close();
- break;
- case BluetoothProfile.MAP_CLIENT:
- BluetoothMapClient mapClient = (BluetoothMapClient) proxy;
- mapClient.close();
- break;
- case BluetoothProfile.HID_DEVICE:
- BluetoothHidDevice hidDevice = (BluetoothHidDevice) proxy;
- hidDevice.close();
- break;
- case BluetoothProfile.HEARING_AID:
- BluetoothHearingAid hearingAid = (BluetoothHearingAid) proxy;
- hearingAid.close();
- break;
- case BluetoothProfile.LE_AUDIO:
- BluetoothLeAudio leAudio = (BluetoothLeAudio) proxy;
- leAudio.close();
- break;
- case BluetoothProfile.VOLUME_CONTROL:
- BluetoothVolumeControl vcs = (BluetoothVolumeControl) proxy;
- vcs.close();
- break;
- case BluetoothProfile.CSIP_SET_COORDINATOR:
- BluetoothCsipSetCoordinator csipSetCoordinator =
- (BluetoothCsipSetCoordinator) proxy;
- csipSetCoordinator.close();
- break;
- case BluetoothProfile.LE_CALL_CONTROL:
- BluetoothLeCallControl tbs = (BluetoothLeCallControl) proxy;
- tbs.close();
- break;
- }
- }
-
- private static final IBluetoothManagerCallback sManagerCallback =
- new IBluetoothManagerCallback.Stub() {
- public void onBluetoothServiceUp(IBluetooth bluetoothService) {
- if (DBG) {
- Log.d(TAG, "onBluetoothServiceUp: " + bluetoothService);
- }
-
- synchronized (sServiceLock) {
- sService = bluetoothService;
- for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
- try {
- if (cb != null) {
- cb.onBluetoothServiceUp(bluetoothService);
- } else {
- Log.d(TAG, "onBluetoothServiceUp: cb is null!");
- }
- } catch (Exception e) {
- Log.e(TAG, "", e);
- }
- }
- }
- }
-
- public void onBluetoothServiceDown() {
- if (DBG) {
- Log.d(TAG, "onBluetoothServiceDown");
- }
-
- synchronized (sServiceLock) {
- sService = null;
- for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
- try {
- if (cb != null) {
- cb.onBluetoothServiceDown();
- } else {
- Log.d(TAG, "onBluetoothServiceDown: cb is null!");
- }
- } catch (Exception e) {
- Log.e(TAG, "", e);
- }
- }
- }
- }
-
- public void onBrEdrDown() {
- if (VDBG) {
- Log.i(TAG, "onBrEdrDown");
- }
-
- synchronized (sServiceLock) {
- for (IBluetoothManagerCallback cb : sProxyServiceStateCallbacks.keySet()) {
- try {
- if (cb != null) {
- cb.onBrEdrDown();
- } else {
- Log.d(TAG, "onBrEdrDown: cb is null!");
- }
- } catch (Exception e) {
- Log.e(TAG, "", e);
- }
- }
- }
- }
- };
-
- private final IBluetoothManagerCallback mManagerCallback =
- new IBluetoothManagerCallback.Stub() {
- public void onBluetoothServiceUp(IBluetooth bluetoothService) {
- synchronized (mServiceLock.writeLock()) {
- mService = bluetoothService;
- }
- synchronized (mMetadataListeners) {
- mMetadataListeners.forEach((device, pair) -> {
- try {
- mService.registerMetadataListener(mBluetoothMetadataListener,
- device, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to register metadata listener", e);
- }
- });
- }
- synchronized (mBluetoothConnectionCallbackExecutorMap) {
- if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
- try {
- mService.registerBluetoothConnectionCallback(mConnectionCallback,
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "onBluetoothServiceUp: Failed to register bluetooth"
- + "connection callback", e);
- }
- }
- }
- }
-
- public void onBluetoothServiceDown() {
- synchronized (mServiceLock.writeLock()) {
- mService = null;
- if (mLeScanClients != null) {
- mLeScanClients.clear();
- }
- if (mBluetoothLeAdvertiser != null) {
- mBluetoothLeAdvertiser.cleanup();
- }
- if (mBluetoothLeScanner != null) {
- mBluetoothLeScanner.cleanup();
- }
- }
- }
-
- public void onBrEdrDown() {
- }
- };
-
- /**
- * Enable the Bluetooth Adapter, but don't auto-connect devices
- * and don't persist state. Only for use by system applications.
- *
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean enableNoAutoConnect() {
- if (isEnabled()) {
- if (DBG) {
- Log.d(TAG, "enableNoAutoConnect(): BT already enabled!");
- }
- return true;
- }
- try {
- return mManagerService.enableNoAutoConnect(mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothStatusCodes.ERROR_UNKNOWN,
- BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
- BluetoothStatusCodes.ERROR_ANOTHER_ACTIVE_OOB_REQUEST,
- })
- public @interface OobError {}
-
- /**
- * Provides callback methods for receiving {@link OobData} from the host stack, as well as an
- * error interface in order to allow the caller to determine next steps based on the {@code
- * ErrorCode}.
- *
- * @hide
- */
- @SystemApi
- public interface OobDataCallback {
- /**
- * Handles the {@link OobData} received from the host stack.
- *
- * @param transport - whether the {@link OobData} is generated for LE or Classic.
- * @param oobData - data generated in the host stack(LE) or controller (Classic)
- */
- void onOobData(@Transport int transport, @NonNull OobData oobData);
-
- /**
- * Provides feedback when things don't go as expected.
- *
- * @param errorCode - the code describing the type of error that occurred.
- */
- void onError(@OobError int errorCode);
- }
-
- /**
- * Wraps an AIDL interface around an {@link OobDataCallback} interface.
- *
- * @see {@link IBluetoothOobDataCallback} for interface definition.
- *
- * @hide
- */
- public class WrappedOobDataCallback extends IBluetoothOobDataCallback.Stub {
- private final OobDataCallback mCallback;
- private final Executor mExecutor;
-
- /**
- * @param callback - object to receive {@link OobData} must be a non null argument
- *
- * @throws NullPointerException if the callback is null.
- */
- WrappedOobDataCallback(@NonNull OobDataCallback callback,
- @NonNull @CallbackExecutor Executor executor) {
- requireNonNull(callback);
- requireNonNull(executor);
- mCallback = callback;
- mExecutor = executor;
- }
- /**
- * Wrapper function to relay to the {@link OobDataCallback#onOobData}
- *
- * @param transport - whether the {@link OobData} is generated for LE or Classic.
- * @param oobData - data generated in the host stack(LE) or controller (Classic)
- *
- * @hide
- */
- public void onOobData(@Transport int transport, @NonNull OobData oobData) {
- mExecutor.execute(new Runnable() {
- public void run() {
- mCallback.onOobData(transport, oobData);
- }
- });
- }
- /**
- * Wrapper function to relay to the {@link OobDataCallback#onError}
- *
- * @param errorCode - the code descibing the type of error that occurred.
- *
- * @hide
- */
- public void onError(@OobError int errorCode) {
- mExecutor.execute(new Runnable() {
- public void run() {
- mCallback.onError(errorCode);
- }
- });
- }
- }
-
- /**
- * Fetches a secret data value that can be used for a secure and simple pairing experience.
- *
- * <p>This is the Local Out of Band data the comes from the
- *
- * <p>This secret is the local Out of Band data. This data is used to securely and quickly
- * pair two devices with minimal user interaction.
- *
- * <p>For example, this secret can be transferred to a remote device out of band (meaning any
- * other way besides using bluetooth). Once the remote device finds this device using the
- * information given in the data, such as the PUBLIC ADDRESS, the remote device could then
- * connect to this device using this secret when the pairing sequenece asks for the secret.
- * This device will respond by automatically accepting the pairing due to the secret being so
- * trustworthy.
- *
- * @param transport - provide type of transport (e.g. LE or Classic).
- * @param callback - target object to receive the {@link OobData} value.
- *
- * @throws NullPointerException if callback is null.
- * @throws IllegalArgumentException if the transport is not valid.
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public void generateLocalOobData(@Transport int transport,
- @NonNull @CallbackExecutor Executor executor, @NonNull OobDataCallback callback) {
- if (transport != BluetoothDevice.TRANSPORT_BREDR && transport
- != BluetoothDevice.TRANSPORT_LE) {
- throw new IllegalArgumentException("Invalid transport '" + transport + "'!");
- }
- requireNonNull(callback);
- if (!isEnabled()) {
- Log.w(TAG, "generateLocalOobData(): Adapter isn't enabled!");
- callback.onError(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED);
- } else {
- try {
- mService.generateLocalOobData(transport, new WrappedOobDataCallback(callback,
- executor), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- }
-
- /**
- * Enable control of the Bluetooth Adapter for a single application.
- *
- * <p>Some applications need to use Bluetooth for short periods of time to
- * transfer data but don't want all the associated implications like
- * automatic connection to headsets etc.
- *
- * <p> Multiple applications can call this. This is reference counted and
- * Bluetooth disabled only when no one else is using it. There will be no UI
- * shown to the user while bluetooth is being enabled. Any user action will
- * override this call. For example, if user wants Bluetooth on and the last
- * user of this API wanted to disable Bluetooth, Bluetooth will not be
- * turned off.
- *
- * <p> This API is only meant to be used by internal applications. Third
- * party applications but use {@link #enable} and {@link #disable} APIs.
- *
- * <p> If this API returns true, it means the callback will be called.
- * The callback will be called with the current state of Bluetooth.
- * If the state is not what was requested, an internal error would be the
- * reason. If Bluetooth is already on and if this function is called to turn
- * it on, the api will return true and a callback will be called.
- *
- * @param on True for on, false for off.
- * @param callback The callback to notify changes to the state.
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public boolean changeApplicationBluetoothState(boolean on,
- BluetoothStateChangeCallback callback) {
- return false;
- }
-
- /**
- * @hide
- */
- public interface BluetoothStateChangeCallback {
- /**
- * @hide
- */
- void onBluetoothStateChange(boolean on);
- }
-
- /**
- * @hide
- */
- public class StateChangeCallbackWrapper extends IBluetoothStateChangeCallback.Stub {
- private BluetoothStateChangeCallback mCallback;
-
- StateChangeCallbackWrapper(BluetoothStateChangeCallback callback) {
- mCallback = callback;
- }
-
- @Override
- public void onBluetoothStateChange(boolean on) {
- mCallback.onBluetoothStateChange(on);
- }
- }
-
- private Set<BluetoothDevice> toDeviceSet(List<BluetoothDevice> devices) {
- Set<BluetoothDevice> deviceSet = new HashSet<BluetoothDevice>(devices);
- return Collections.unmodifiableSet(deviceSet);
- }
-
- protected void finalize() throws Throwable {
- try {
- removeServiceStateCallback(mManagerCallback);
- } finally {
- super.finalize();
- }
- }
-
- /**
- * Validate a String Bluetooth address, such as "00:43:A8:23:10:F0"
- * <p>Alphabetic characters must be uppercase to be valid.
- *
- * @param address Bluetooth address as string
- * @return true if the address is valid, false otherwise
- */
- public static boolean checkBluetoothAddress(String address) {
- if (address == null || address.length() != ADDRESS_LENGTH) {
- return false;
- }
- for (int i = 0; i < ADDRESS_LENGTH; i++) {
- char c = address.charAt(i);
- switch (i % 3) {
- case 0:
- case 1:
- if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
- // hex character, OK
- break;
- }
- return false;
- case 2:
- if (c == ':') {
- break; // OK
- }
- return false;
- }
- }
- return true;
- }
-
- /**
- * Determines whether a String Bluetooth address, such as "F0:43:A8:23:10:00"
- * is a RANDOM STATIC address.
- *
- * RANDOM STATIC: (addr & 0xC0) == 0xC0
- * RANDOM RESOLVABLE: (addr & 0xC0) == 0x40
- * RANDOM non-RESOLVABLE: (addr & 0xC0) == 0x00
- *
- * @param address Bluetooth address as string
- * @return true if the 2 Most Significant Bits of the address equals 0xC0.
- *
- * @hide
- */
- public static boolean isAddressRandomStatic(@NonNull String address) {
- requireNonNull(address);
- return checkBluetoothAddress(address)
- && (Integer.parseInt(address.split(":")[0], 16) & 0xC0) == 0xC0;
- }
-
- /** {@hide} */
- @UnsupportedAppUsage
- @RequiresNoPermission
- public IBluetoothManager getBluetoothManager() {
- return mManagerService;
- }
-
- /** {@hide} */
- @RequiresNoPermission
- public AttributionSource getAttributionSource() {
- return mAttributionSource;
- }
-
- @GuardedBy("sServiceLock")
- private static final WeakHashMap<IBluetoothManagerCallback, Void> sProxyServiceStateCallbacks =
- new WeakHashMap<>();
-
- /*package*/ IBluetooth getBluetoothService() {
- synchronized (sServiceLock) {
- if (sProxyServiceStateCallbacks.isEmpty()) {
- throw new IllegalStateException(
- "Anonymous service access requires at least one lifecycle in process");
- }
- return sService;
- }
- }
-
- @UnsupportedAppUsage
- /*package*/ IBluetooth getBluetoothService(IBluetoothManagerCallback cb) {
- Objects.requireNonNull(cb);
- synchronized (sServiceLock) {
- sProxyServiceStateCallbacks.put(cb, null);
- registerOrUnregisterAdapterLocked();
- return sService;
- }
- }
-
- /*package*/ void removeServiceStateCallback(IBluetoothManagerCallback cb) {
- Objects.requireNonNull(cb);
- synchronized (sServiceLock) {
- sProxyServiceStateCallbacks.remove(cb);
- registerOrUnregisterAdapterLocked();
- }
- }
-
- /**
- * Handle registering (or unregistering) a single process-wide
- * {@link IBluetoothManagerCallback} based on the presence of local
- * {@link #sProxyServiceStateCallbacks} clients.
- */
- @GuardedBy("sServiceLock")
- private void registerOrUnregisterAdapterLocked() {
- final boolean isRegistered = sServiceRegistered;
- final boolean wantRegistered = !sProxyServiceStateCallbacks.isEmpty();
-
- if (isRegistered != wantRegistered) {
- if (wantRegistered) {
- try {
- sService = mManagerService.registerAdapter(sManagerCallback);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- } else {
- try {
- mManagerService.unregisterAdapter(sManagerCallback);
- sService = null;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
- sServiceRegistered = wantRegistered;
- }
- }
-
- /**
- * Callback interface used to deliver LE scan results.
- *
- * @see #startLeScan(LeScanCallback)
- * @see #startLeScan(UUID[], LeScanCallback)
- */
- public interface LeScanCallback {
- /**
- * Callback reporting an LE device found during a device scan initiated
- * by the {@link BluetoothAdapter#startLeScan} function.
- *
- * @param device Identifies the remote device
- * @param rssi The RSSI value for the remote device as reported by the Bluetooth hardware. 0
- * if no RSSI value is available.
- * @param scanRecord The content of the advertisement record offered by the remote device.
- */
- void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord);
- }
-
- /**
- * Register a callback to receive events whenever the bluetooth stack goes down and back up,
- * e.g. in the event the bluetooth is turned off/on via settings.
- *
- * If the bluetooth stack is currently up, there will not be an initial callback call.
- * You can use the return value as an indication of this being the case.
- *
- * Callbacks will be delivered on a binder thread.
- *
- * @return whether bluetooth is already up currently
- *
- * @hide
- */
- public boolean registerServiceLifecycleCallback(ServiceLifecycleCallback callback) {
- return getBluetoothService(callback.mRemote) != null;
- }
-
- /**
- * Unregister a callback registered via {@link #registerServiceLifecycleCallback}
- *
- * @hide
- */
- public void unregisterServiceLifecycleCallback(ServiceLifecycleCallback callback) {
- removeServiceStateCallback(callback.mRemote);
- }
-
- /**
- * A callback for {@link #registerServiceLifecycleCallback}
- *
- * @hide
- */
- public abstract static class ServiceLifecycleCallback {
-
- /** Called when the bluetooth stack is up */
- public abstract void onBluetoothServiceUp();
-
- /** Called when the bluetooth stack is down */
- public abstract void onBluetoothServiceDown();
-
- IBluetoothManagerCallback mRemote = new IBluetoothManagerCallback.Stub() {
- @Override
- public void onBluetoothServiceUp(IBluetooth bluetoothService) {
- ServiceLifecycleCallback.this.onBluetoothServiceUp();
- }
-
- @Override
- public void onBluetoothServiceDown() {
- ServiceLifecycleCallback.this.onBluetoothServiceDown();
- }
-
- @Override
- public void onBrEdrDown() {}
- };
- }
-
- /**
- * Starts a scan for Bluetooth LE devices.
- *
- * <p>Results of the scan are reported using the
- * {@link LeScanCallback#onLeScan} callback.
- *
- * @param callback the callback LE scan results are delivered
- * @return true, if the scan was started successfully
- * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
- * instead.
- */
- @Deprecated
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public boolean startLeScan(LeScanCallback callback) {
- return startLeScan(null, callback);
- }
-
- /**
- * Starts a scan for Bluetooth LE devices, looking for devices that
- * advertise given services.
- *
- * <p>Devices which advertise all specified services are reported using the
- * {@link LeScanCallback#onLeScan} callback.
- *
- * @param serviceUuids Array of services to look for
- * @param callback the callback LE scan results are delivered
- * @return true, if the scan was started successfully
- * @deprecated use {@link BluetoothLeScanner#startScan(List, ScanSettings, ScanCallback)}
- * instead.
- */
- @Deprecated
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public boolean startLeScan(final UUID[] serviceUuids, final LeScanCallback callback) {
- if (DBG) {
- Log.d(TAG, "startLeScan(): " + Arrays.toString(serviceUuids));
- }
- if (callback == null) {
- if (DBG) {
- Log.e(TAG, "startLeScan: null callback");
- }
- return false;
- }
- BluetoothLeScanner scanner = getBluetoothLeScanner();
- if (scanner == null) {
- if (DBG) {
- Log.e(TAG, "startLeScan: cannot get BluetoothLeScanner");
- }
- return false;
- }
-
- synchronized (mLeScanClients) {
- if (mLeScanClients.containsKey(callback)) {
- if (DBG) {
- Log.e(TAG, "LE Scan has already started");
- }
- return false;
- }
-
- try {
- IBluetoothGatt iGatt = mManagerService.getBluetoothGatt();
- if (iGatt == null) {
- // BLE is not supported
- return false;
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- ScanCallback scanCallback = new ScanCallback() {
- @Override
- public void onScanResult(int callbackType, ScanResult result) {
- if (callbackType != ScanSettings.CALLBACK_TYPE_ALL_MATCHES) {
- // Should not happen.
- Log.e(TAG, "LE Scan has already started");
- return;
- }
- ScanRecord scanRecord = result.getScanRecord();
- if (scanRecord == null) {
- return;
- }
- if (serviceUuids != null) {
- List<ParcelUuid> uuids = new ArrayList<ParcelUuid>();
- for (UUID uuid : serviceUuids) {
- uuids.add(new ParcelUuid(uuid));
- }
- List<ParcelUuid> scanServiceUuids = scanRecord.getServiceUuids();
- if (scanServiceUuids == null || !scanServiceUuids.containsAll(uuids)) {
- if (DBG) {
- Log.d(TAG, "uuids does not match");
- }
- return;
- }
- }
- callback.onLeScan(result.getDevice(), result.getRssi(),
- scanRecord.getBytes());
- }
- };
- ScanSettings settings = new ScanSettings.Builder().setCallbackType(
- ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
- .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
- .build();
-
- List<ScanFilter> filters = new ArrayList<ScanFilter>();
- if (serviceUuids != null && serviceUuids.length > 0) {
- // Note scan filter does not support matching an UUID array so we put one
- // UUID to hardware and match the whole array in callback.
- ScanFilter filter =
- new ScanFilter.Builder().setServiceUuid(new ParcelUuid(serviceUuids[0]))
- .build();
- filters.add(filter);
- }
- scanner.startScan(filters, settings, scanCallback);
-
- mLeScanClients.put(callback, scanCallback);
- return true;
-
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- return false;
- }
-
- /**
- * Stops an ongoing Bluetooth LE device scan.
- *
- * @param callback used to identify which scan to stop must be the same handle used to start the
- * scan
- * @deprecated Use {@link BluetoothLeScanner#stopScan(ScanCallback)} instead.
- */
- @Deprecated
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void stopLeScan(LeScanCallback callback) {
- if (DBG) {
- Log.d(TAG, "stopLeScan()");
- }
- BluetoothLeScanner scanner = getBluetoothLeScanner();
- if (scanner == null) {
- return;
- }
- synchronized (mLeScanClients) {
- ScanCallback scanCallback = mLeScanClients.remove(callback);
- if (scanCallback == null) {
- if (DBG) {
- Log.d(TAG, "scan not started yet");
- }
- return;
- }
- scanner.stopScan(scanCallback);
- }
- }
-
- /**
- * Create a secure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
- * assign a dynamic protocol/service multiplexer (PSM) value. This socket can be used to listen
- * for incoming connections. The supported Bluetooth transport is LE only.
- * <p>A remote device connecting to this socket will be authenticated and communication on this
- * socket will be encrypted.
- * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
- * {@link BluetoothServerSocket}.
- * <p>The system will assign a dynamic PSM value. This PSM value can be read from the {@link
- * BluetoothServerSocket#getPsm()} and this value will be released when this server socket is
- * closed, Bluetooth is turned off, or the application exits unexpectedly.
- * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
- * defined and performed by the application.
- * <p>Use {@link BluetoothDevice#createL2capChannel(int)} to connect to this server
- * socket from another Android device that is given the PSM value.
- *
- * @return an L2CAP CoC BluetoothServerSocket
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions, or unable to start this CoC
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull BluetoothServerSocket listenUsingL2capChannel()
- throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, true, true,
- SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
- int errno = socket.mSocket.bindListen();
- if (errno != 0) {
- throw new IOException("Error: " + errno);
- }
-
- int assignedPsm = socket.mSocket.getPort();
- if (assignedPsm == 0) {
- throw new IOException("Error: Unable to assign PSM value");
- }
- if (DBG) {
- Log.d(TAG, "listenUsingL2capChannel: set assigned PSM to "
- + assignedPsm);
- }
- socket.setChannel(assignedPsm);
-
- return socket;
- }
-
- /**
- * Create an insecure L2CAP Connection-oriented Channel (CoC) {@link BluetoothServerSocket} and
- * assign a dynamic PSM value. This socket can be used to listen for incoming connections. The
- * supported Bluetooth transport is LE only.
- * <p>The link key is not required to be authenticated, i.e the communication may be vulnerable
- * to person-in-the-middle attacks. Use {@link #listenUsingL2capChannel}, if an encrypted and
- * authenticated communication channel is desired.
- * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming connections from a listening
- * {@link BluetoothServerSocket}.
- * <p>The system will assign a dynamic protocol/service multiplexer (PSM) value. This PSM value
- * can be read from the {@link BluetoothServerSocket#getPsm()} and this value will be released
- * when this server socket is closed, Bluetooth is turned off, or the application exits
- * unexpectedly.
- * <p>The mechanism of disclosing the assigned dynamic PSM value to the initiating peer is
- * defined and performed by the application.
- * <p>Use {@link BluetoothDevice#createInsecureL2capChannel(int)} to connect to this server
- * socket from another Android device that is given the PSM value.
- *
- * @return an L2CAP CoC BluetoothServerSocket
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions, or unable to start this CoC
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull BluetoothServerSocket listenUsingInsecureL2capChannel()
- throws IOException {
- BluetoothServerSocket socket =
- new BluetoothServerSocket(BluetoothSocket.TYPE_L2CAP_LE, false, false,
- SOCKET_CHANNEL_AUTO_STATIC_NO_SDP, false, false);
- int errno = socket.mSocket.bindListen();
- if (errno != 0) {
- throw new IOException("Error: " + errno);
- }
-
- int assignedPsm = socket.mSocket.getPort();
- if (assignedPsm == 0) {
- throw new IOException("Error: Unable to assign PSM value");
- }
- if (DBG) {
- Log.d(TAG, "listenUsingInsecureL2capChannel: set assigned PSM to "
- + assignedPsm);
- }
- socket.setChannel(assignedPsm);
-
- return socket;
- }
-
- /**
- * Register a {@link #OnMetadataChangedListener} to receive update about metadata
- * changes for this {@link BluetoothDevice}.
- * Registration must be done when Bluetooth is ON and will last until
- * {@link #removeOnMetadataChangedListener(BluetoothDevice)} is called, even when Bluetooth
- * restarted in the middle.
- * All input parameters should not be null or {@link NullPointerException} will be triggered.
- * The same {@link BluetoothDevice} and {@link #OnMetadataChangedListener} pair can only be
- * registered once, double registration would cause {@link IllegalArgumentException}.
- *
- * @param device {@link BluetoothDevice} that will be registered
- * @param executor the executor for listener callback
- * @param listener {@link #OnMetadataChangedListener} that will receive asynchronous callbacks
- * @return true on success, false on error
- * @throws NullPointerException If one of {@code listener}, {@code device} or {@code executor}
- * is null.
- * @throws IllegalArgumentException The same {@link #OnMetadataChangedListener} and
- * {@link BluetoothDevice} are registered twice.
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean addOnMetadataChangedListener(@NonNull BluetoothDevice device,
- @NonNull Executor executor, @NonNull OnMetadataChangedListener listener) {
- if (DBG) Log.d(TAG, "addOnMetadataChangedListener()");
-
- final IBluetooth service = mService;
- if (service == null) {
- Log.e(TAG, "Bluetooth is not enabled. Cannot register metadata listener");
- return false;
- }
- if (listener == null) {
- throw new NullPointerException("listener is null");
- }
- if (device == null) {
- throw new NullPointerException("device is null");
- }
- if (executor == null) {
- throw new NullPointerException("executor is null");
- }
-
- synchronized (mMetadataListeners) {
- List<Pair<OnMetadataChangedListener, Executor>> listenerList =
- mMetadataListeners.get(device);
- if (listenerList == null) {
- // Create new listener/executor list for registeration
- listenerList = new ArrayList<>();
- mMetadataListeners.put(device, listenerList);
- } else {
- // Check whether this device was already registed by the lisenter
- if (listenerList.stream().anyMatch((pair) -> (pair.first.equals(listener)))) {
- throw new IllegalArgumentException("listener was already regestered"
- + " for the device");
- }
- }
-
- Pair<OnMetadataChangedListener, Executor> listenerPair = new Pair(listener, executor);
- listenerList.add(listenerPair);
-
- boolean ret = false;
- try {
- ret = service.registerMetadataListener(mBluetoothMetadataListener, device,
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "registerMetadataListener fail", e);
- } finally {
- if (!ret) {
- // Remove listener registered earlier when fail.
- listenerList.remove(listenerPair);
- if (listenerList.isEmpty()) {
- // Remove the device if its listener list is empty
- mMetadataListeners.remove(device);
- }
- }
- }
- return ret;
- }
- }
-
- /**
- * Unregister a {@link #OnMetadataChangedListener} from a registered {@link BluetoothDevice}.
- * Unregistration can be done when Bluetooth is either ON or OFF.
- * {@link #addOnMetadataChangedListener(OnMetadataChangedListener, BluetoothDevice, Executor)}
- * must be called before unregisteration.
- *
- * @param device {@link BluetoothDevice} that will be unregistered. It
- * should not be null or {@link NullPointerException} will be triggered.
- * @param listener {@link OnMetadataChangedListener} that will be unregistered. It
- * should not be null or {@link NullPointerException} will be triggered.
- * @return true on success, false on error
- * @throws NullPointerException If {@code listener} or {@code device} is null.
- * @throws IllegalArgumentException If {@code device} has not been registered before.
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean removeOnMetadataChangedListener(@NonNull BluetoothDevice device,
- @NonNull OnMetadataChangedListener listener) {
- if (DBG) Log.d(TAG, "removeOnMetadataChangedListener()");
- if (device == null) {
- throw new NullPointerException("device is null");
- }
- if (listener == null) {
- throw new NullPointerException("listener is null");
- }
-
- synchronized (mMetadataListeners) {
- if (!mMetadataListeners.containsKey(device)) {
- throw new IllegalArgumentException("device was not registered");
- }
- // Remove issued listener from the registered device
- mMetadataListeners.get(device).removeIf((pair) -> (pair.first.equals(listener)));
-
- if (mMetadataListeners.get(device).isEmpty()) {
- // Unregister to Bluetooth service if all listeners are removed from
- // the registered device
- mMetadataListeners.remove(device);
- final IBluetooth service = mService;
- if (service == null) {
- // Bluetooth is OFF, do nothing to Bluetooth service.
- return true;
- }
- try {
- return service.unregisterMetadataListener(device, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "unregisterMetadataListener fail", e);
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * This interface is used to implement {@link BluetoothAdapter} metadata listener.
- * @hide
- */
- @SystemApi
- public interface OnMetadataChangedListener {
- /**
- * Callback triggered if the metadata of {@link BluetoothDevice} registered in
- * {@link #addOnMetadataChangedListener}.
- *
- * @param device changed {@link BluetoothDevice}.
- * @param key changed metadata key, one of BluetoothDevice.METADATA_*.
- * @param value the new value of metadata as byte array.
- */
- void onMetadataChanged(@NonNull BluetoothDevice device, int key,
- @Nullable byte[] value);
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothConnectionCallback mConnectionCallback =
- new IBluetoothConnectionCallback.Stub() {
- @Override
- public void onDeviceConnected(BluetoothDevice device) {
- Attributable.setAttributionSource(device, mAttributionSource);
- for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry:
- mBluetoothConnectionCallbackExecutorMap.entrySet()) {
- BluetoothConnectionCallback callback = callbackExecutorEntry.getKey();
- Executor executor = callbackExecutorEntry.getValue();
- executor.execute(() -> callback.onDeviceConnected(device));
- }
- }
-
- @Override
- public void onDeviceDisconnected(BluetoothDevice device, int hciReason) {
- Attributable.setAttributionSource(device, mAttributionSource);
- for (Map.Entry<BluetoothConnectionCallback, Executor> callbackExecutorEntry:
- mBluetoothConnectionCallbackExecutorMap.entrySet()) {
- BluetoothConnectionCallback callback = callbackExecutorEntry.getKey();
- Executor executor = callbackExecutorEntry.getValue();
- executor.execute(() -> callback.onDeviceDisconnected(device, hciReason));
- }
- }
- };
-
- /**
- * Registers the BluetoothConnectionCallback to receive callback events when a bluetooth device
- * (classic or low energy) is connected or disconnected.
- *
- * @param executor is the callback executor
- * @param callback is the connection callback you wish to register
- * @return true if the callback was registered successfully, false otherwise
- * @throws IllegalArgumentException if the callback is already registered
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean registerBluetoothConnectionCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull BluetoothConnectionCallback callback) {
- if (DBG) Log.d(TAG, "registerBluetoothConnectionCallback()");
- if (callback == null) {
- return false;
- }
-
- synchronized (mBluetoothConnectionCallbackExecutorMap) {
- // If the callback map is empty, we register the service-to-app callback
- if (mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- if (!mService.registerBluetoothConnectionCallback(mConnectionCallback,
- mAttributionSource)) {
- return false;
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- mBluetoothConnectionCallbackExecutorMap.remove(callback);
- } finally {
- mServiceLock.readLock().unlock();
- }
- }
-
- // Adds the passed in callback to our map of callbacks to executors
- if (mBluetoothConnectionCallbackExecutorMap.containsKey(callback)) {
- throw new IllegalArgumentException("This callback has already been registered");
- }
- mBluetoothConnectionCallbackExecutorMap.put(callback, executor);
- }
-
- return true;
- }
-
- /**
- * Unregisters the BluetoothConnectionCallback that was previously registered by the application
- *
- * @param callback is the connection callback you wish to unregister
- * @return true if the callback was unregistered successfully, false otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean unregisterBluetoothConnectionCallback(
- @NonNull BluetoothConnectionCallback callback) {
- if (DBG) Log.d(TAG, "unregisterBluetoothConnectionCallback()");
- if (callback == null) {
- return false;
- }
-
- synchronized (mBluetoothConnectionCallbackExecutorMap) {
- if (mBluetoothConnectionCallbackExecutorMap.remove(callback) != null) {
- return false;
- }
- }
-
- if (!mBluetoothConnectionCallbackExecutorMap.isEmpty()) {
- return true;
- }
-
- // If the callback map is empty, we unregister the service-to-app callback
- try {
- mServiceLock.readLock().lock();
- if (mService != null) {
- return mService.unregisterBluetoothConnectionCallback(mConnectionCallback,
- mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
-
- return false;
- }
-
- /**
- * This abstract class is used to implement callbacks for when a bluetooth classic or Bluetooth
- * Low Energy (BLE) device is either connected or disconnected.
- *
- * @hide
- */
- public abstract static class BluetoothConnectionCallback {
- /**
- * Callback triggered when a bluetooth device (classic or BLE) is connected
- * @param device is the connected bluetooth device
- */
- public void onDeviceConnected(BluetoothDevice device) {}
-
- /**
- * Callback triggered when a bluetooth device (classic or BLE) is disconnected
- * @param device is the disconnected bluetooth device
- * @param reason is the disconnect reason
- */
- public void onDeviceDisconnected(BluetoothDevice device, @DisconnectReason int reason) {}
-
- /**
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(prefix = { "REASON_" }, value = {
- BluetoothStatusCodes.ERROR_UNKNOWN,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS,
- BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS})
- public @interface DisconnectReason {}
-
- /**
- * Returns human-readable strings corresponding to {@link DisconnectReason}.
- */
- public static String disconnectReasonText(@DisconnectReason int reason) {
- switch (reason) {
- case BluetoothStatusCodes.ERROR_UNKNOWN:
- return "Reason unknown";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL_REQUEST:
- return "Local request";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE_REQUEST:
- return "Remote request";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_LOCAL:
- return "Local error";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_REMOTE:
- return "Remote error";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_TIMEOUT:
- return "Timeout";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SECURITY:
- return "Security";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_SYSTEM_POLICY:
- return "System policy";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED:
- return "Resource constrained";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS:
- return "Connection already exists";
- case BluetoothStatusCodes.ERROR_DISCONNECT_REASON_BAD_PARAMETERS:
- return "Bad parameters";
- default:
- return "Unrecognized disconnect reason: " + reason;
- }
- }
- }
-
- /**
- * Converts old constant of priority to the new for connection policy
- *
- * @param priority is the priority to convert to connection policy
- * @return the equivalent connection policy constant to the priority
- *
- * @hide
- */
- public static @ConnectionPolicy int priorityToConnectionPolicy(int priority) {
- switch(priority) {
- case BluetoothProfile.PRIORITY_AUTO_CONNECT:
- return BluetoothProfile.CONNECTION_POLICY_ALLOWED;
- case BluetoothProfile.PRIORITY_ON:
- return BluetoothProfile.CONNECTION_POLICY_ALLOWED;
- case BluetoothProfile.PRIORITY_OFF:
- return BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- case BluetoothProfile.PRIORITY_UNDEFINED:
- return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
- default:
- Log.e(TAG, "setPriority: Invalid priority: " + priority);
- return BluetoothProfile.CONNECTION_POLICY_UNKNOWN;
- }
- }
-
- /**
- * Converts new constant of connection policy to the old for priority
- *
- * @param connectionPolicy is the connection policy to convert to priority
- * @return the equivalent priority constant to the connectionPolicy
- *
- * @hide
- */
- public static int connectionPolicyToPriority(@ConnectionPolicy int connectionPolicy) {
- switch(connectionPolicy) {
- case BluetoothProfile.CONNECTION_POLICY_ALLOWED:
- return BluetoothProfile.PRIORITY_ON;
- case BluetoothProfile.CONNECTION_POLICY_FORBIDDEN:
- return BluetoothProfile.PRIORITY_OFF;
- case BluetoothProfile.CONNECTION_POLICY_UNKNOWN:
- return BluetoothProfile.PRIORITY_UNDEFINED;
- }
- return BluetoothProfile.PRIORITY_UNDEFINED;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothAssignedNumbers.java b/core/java/android/bluetooth/BluetoothAssignedNumbers.java
deleted file mode 100644
index 41a34e0..0000000
--- a/core/java/android/bluetooth/BluetoothAssignedNumbers.java
+++ /dev/null
@@ -1,1171 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-/**
- * Bluetooth Assigned Numbers.
- * <p>
- * For now we only include Company ID values.
- *
- * @see <a href="https://www.bluetooth.org/technical/assignednumbers/identifiers.htm"> The Official
- * Bluetooth SIG Member Website | Company Identifiers</a>
- */
-public class BluetoothAssignedNumbers {
-
- // Bluetooth SIG Company ID values
- /*
- * Ericsson Technology Licensing.
- */
- public static final int ERICSSON_TECHNOLOGY = 0x0000;
-
- /*
- * Nokia Mobile Phones.
- */
- public static final int NOKIA_MOBILE_PHONES = 0x0001;
-
- /*
- * Intel Corp.
- */
- public static final int INTEL = 0x0002;
-
- /*
- * IBM Corp.
- */
- public static final int IBM = 0x0003;
-
- /*
- * Toshiba Corp.
- */
- public static final int TOSHIBA = 0x0004;
-
- /*
- * 3Com.
- */
- public static final int THREECOM = 0x0005;
-
- /*
- * Microsoft.
- */
- public static final int MICROSOFT = 0x0006;
-
- /*
- * Lucent.
- */
- public static final int LUCENT = 0x0007;
-
- /*
- * Motorola.
- */
- public static final int MOTOROLA = 0x0008;
-
- /*
- * Infineon Technologies AG.
- */
- public static final int INFINEON_TECHNOLOGIES = 0x0009;
-
- /*
- * Cambridge Silicon Radio.
- */
- public static final int CAMBRIDGE_SILICON_RADIO = 0x000A;
-
- /*
- * Silicon Wave.
- */
- public static final int SILICON_WAVE = 0x000B;
-
- /*
- * Digianswer A/S.
- */
- public static final int DIGIANSWER = 0x000C;
-
- /*
- * Texas Instruments Inc.
- */
- public static final int TEXAS_INSTRUMENTS = 0x000D;
-
- /*
- * Parthus Technologies Inc.
- */
- public static final int PARTHUS_TECHNOLOGIES = 0x000E;
-
- /*
- * Broadcom Corporation.
- */
- public static final int BROADCOM = 0x000F;
-
- /*
- * Mitel Semiconductor.
- */
- public static final int MITEL_SEMICONDUCTOR = 0x0010;
-
- /*
- * Widcomm, Inc.
- */
- public static final int WIDCOMM = 0x0011;
-
- /*
- * Zeevo, Inc.
- */
- public static final int ZEEVO = 0x0012;
-
- /*
- * Atmel Corporation.
- */
- public static final int ATMEL = 0x0013;
-
- /*
- * Mitsubishi Electric Corporation.
- */
- public static final int MITSUBISHI_ELECTRIC = 0x0014;
-
- /*
- * RTX Telecom A/S.
- */
- public static final int RTX_TELECOM = 0x0015;
-
- /*
- * KC Technology Inc.
- */
- public static final int KC_TECHNOLOGY = 0x0016;
-
- /*
- * Newlogic.
- */
- public static final int NEWLOGIC = 0x0017;
-
- /*
- * Transilica, Inc.
- */
- public static final int TRANSILICA = 0x0018;
-
- /*
- * Rohde & Schwarz GmbH & Co. KG.
- */
- public static final int ROHDE_AND_SCHWARZ = 0x0019;
-
- /*
- * TTPCom Limited.
- */
- public static final int TTPCOM = 0x001A;
-
- /*
- * Signia Technologies, Inc.
- */
- public static final int SIGNIA_TECHNOLOGIES = 0x001B;
-
- /*
- * Conexant Systems Inc.
- */
- public static final int CONEXANT_SYSTEMS = 0x001C;
-
- /*
- * Qualcomm.
- */
- public static final int QUALCOMM = 0x001D;
-
- /*
- * Inventel.
- */
- public static final int INVENTEL = 0x001E;
-
- /*
- * AVM Berlin.
- */
- public static final int AVM_BERLIN = 0x001F;
-
- /*
- * BandSpeed, Inc.
- */
- public static final int BANDSPEED = 0x0020;
-
- /*
- * Mansella Ltd.
- */
- public static final int MANSELLA = 0x0021;
-
- /*
- * NEC Corporation.
- */
- public static final int NEC = 0x0022;
-
- /*
- * WavePlus Technology Co., Ltd.
- */
- public static final int WAVEPLUS_TECHNOLOGY = 0x0023;
-
- /*
- * Alcatel.
- */
- public static final int ALCATEL = 0x0024;
-
- /*
- * Philips Semiconductors.
- */
- public static final int PHILIPS_SEMICONDUCTORS = 0x0025;
-
- /*
- * C Technologies.
- */
- public static final int C_TECHNOLOGIES = 0x0026;
-
- /*
- * Open Interface.
- */
- public static final int OPEN_INTERFACE = 0x0027;
-
- /*
- * R F Micro Devices.
- */
- public static final int RF_MICRO_DEVICES = 0x0028;
-
- /*
- * Hitachi Ltd.
- */
- public static final int HITACHI = 0x0029;
-
- /*
- * Symbol Technologies, Inc.
- */
- public static final int SYMBOL_TECHNOLOGIES = 0x002A;
-
- /*
- * Tenovis.
- */
- public static final int TENOVIS = 0x002B;
-
- /*
- * Macronix International Co. Ltd.
- */
- public static final int MACRONIX = 0x002C;
-
- /*
- * GCT Semiconductor.
- */
- public static final int GCT_SEMICONDUCTOR = 0x002D;
-
- /*
- * Norwood Systems.
- */
- public static final int NORWOOD_SYSTEMS = 0x002E;
-
- /*
- * MewTel Technology Inc.
- */
- public static final int MEWTEL_TECHNOLOGY = 0x002F;
-
- /*
- * ST Microelectronics.
- */
- public static final int ST_MICROELECTRONICS = 0x0030;
-
- /*
- * Synopsys.
- */
- public static final int SYNOPSYS = 0x0031;
-
- /*
- * Red-M (Communications) Ltd.
- */
- public static final int RED_M = 0x0032;
-
- /*
- * Commil Ltd.
- */
- public static final int COMMIL = 0x0033;
-
- /*
- * Computer Access Technology Corporation (CATC).
- */
- public static final int CATC = 0x0034;
-
- /*
- * Eclipse (HQ Espana) S.L.
- */
- public static final int ECLIPSE = 0x0035;
-
- /*
- * Renesas Technology Corp.
- */
- public static final int RENESAS_TECHNOLOGY = 0x0036;
-
- /*
- * Mobilian Corporation.
- */
- public static final int MOBILIAN_CORPORATION = 0x0037;
-
- /*
- * Terax.
- */
- public static final int TERAX = 0x0038;
-
- /*
- * Integrated System Solution Corp.
- */
- public static final int INTEGRATED_SYSTEM_SOLUTION = 0x0039;
-
- /*
- * Matsushita Electric Industrial Co., Ltd.
- */
- public static final int MATSUSHITA_ELECTRIC = 0x003A;
-
- /*
- * Gennum Corporation.
- */
- public static final int GENNUM = 0x003B;
-
- /*
- * Research In Motion.
- */
- public static final int RESEARCH_IN_MOTION = 0x003C;
-
- /*
- * IPextreme, Inc.
- */
- public static final int IPEXTREME = 0x003D;
-
- /*
- * Systems and Chips, Inc.
- */
- public static final int SYSTEMS_AND_CHIPS = 0x003E;
-
- /*
- * Bluetooth SIG, Inc.
- */
- public static final int BLUETOOTH_SIG = 0x003F;
-
- /*
- * Seiko Epson Corporation.
- */
- public static final int SEIKO_EPSON = 0x0040;
-
- /*
- * Integrated Silicon Solution Taiwan, Inc.
- */
- public static final int INTEGRATED_SILICON_SOLUTION = 0x0041;
-
- /*
- * CONWISE Technology Corporation Ltd.
- */
- public static final int CONWISE_TECHNOLOGY = 0x0042;
-
- /*
- * PARROT SA.
- */
- public static final int PARROT = 0x0043;
-
- /*
- * Socket Mobile.
- */
- public static final int SOCKET_MOBILE = 0x0044;
-
- /*
- * Atheros Communications, Inc.
- */
- public static final int ATHEROS_COMMUNICATIONS = 0x0045;
-
- /*
- * MediaTek, Inc.
- */
- public static final int MEDIATEK = 0x0046;
-
- /*
- * Bluegiga.
- */
- public static final int BLUEGIGA = 0x0047;
-
- /*
- * Marvell Technology Group Ltd.
- */
- public static final int MARVELL = 0x0048;
-
- /*
- * 3DSP Corporation.
- */
- public static final int THREE_DSP = 0x0049;
-
- /*
- * Accel Semiconductor Ltd.
- */
- public static final int ACCEL_SEMICONDUCTOR = 0x004A;
-
- /*
- * Continental Automotive Systems.
- */
- public static final int CONTINENTAL_AUTOMOTIVE = 0x004B;
-
- /*
- * Apple, Inc.
- */
- public static final int APPLE = 0x004C;
-
- /*
- * Staccato Communications, Inc.
- */
- public static final int STACCATO_COMMUNICATIONS = 0x004D;
-
- /*
- * Avago Technologies.
- */
- public static final int AVAGO = 0x004E;
-
- /*
- * APT Licensing Ltd.
- */
- public static final int APT_LICENSING = 0x004F;
-
- /*
- * SiRF Technology, Inc.
- */
- public static final int SIRF_TECHNOLOGY = 0x0050;
-
- /*
- * Tzero Technologies, Inc.
- */
- public static final int TZERO_TECHNOLOGIES = 0x0051;
-
- /*
- * J&M Corporation.
- */
- public static final int J_AND_M = 0x0052;
-
- /*
- * Free2move AB.
- */
- public static final int FREE2MOVE = 0x0053;
-
- /*
- * 3DiJoy Corporation.
- */
- public static final int THREE_DIJOY = 0x0054;
-
- /*
- * Plantronics, Inc.
- */
- public static final int PLANTRONICS = 0x0055;
-
- /*
- * Sony Ericsson Mobile Communications.
- */
- public static final int SONY_ERICSSON = 0x0056;
-
- /*
- * Harman International Industries, Inc.
- */
- public static final int HARMAN_INTERNATIONAL = 0x0057;
-
- /*
- * Vizio, Inc.
- */
- public static final int VIZIO = 0x0058;
-
- /*
- * Nordic Semiconductor ASA.
- */
- public static final int NORDIC_SEMICONDUCTOR = 0x0059;
-
- /*
- * EM Microelectronic-Marin SA.
- */
- public static final int EM_MICROELECTRONIC_MARIN = 0x005A;
-
- /*
- * Ralink Technology Corporation.
- */
- public static final int RALINK_TECHNOLOGY = 0x005B;
-
- /*
- * Belkin International, Inc.
- */
- public static final int BELKIN_INTERNATIONAL = 0x005C;
-
- /*
- * Realtek Semiconductor Corporation.
- */
- public static final int REALTEK_SEMICONDUCTOR = 0x005D;
-
- /*
- * Stonestreet One, LLC.
- */
- public static final int STONESTREET_ONE = 0x005E;
-
- /*
- * Wicentric, Inc.
- */
- public static final int WICENTRIC = 0x005F;
-
- /*
- * RivieraWaves S.A.S.
- */
- public static final int RIVIERAWAVES = 0x0060;
-
- /*
- * RDA Microelectronics.
- */
- public static final int RDA_MICROELECTRONICS = 0x0061;
-
- /*
- * Gibson Guitars.
- */
- public static final int GIBSON_GUITARS = 0x0062;
-
- /*
- * MiCommand Inc.
- */
- public static final int MICOMMAND = 0x0063;
-
- /*
- * Band XI International, LLC.
- */
- public static final int BAND_XI_INTERNATIONAL = 0x0064;
-
- /*
- * Hewlett-Packard Company.
- */
- public static final int HEWLETT_PACKARD = 0x0065;
-
- /*
- * 9Solutions Oy.
- */
- public static final int NINE_SOLUTIONS = 0x0066;
-
- /*
- * GN Netcom A/S.
- */
- public static final int GN_NETCOM = 0x0067;
-
- /*
- * General Motors.
- */
- public static final int GENERAL_MOTORS = 0x0068;
-
- /*
- * A&D Engineering, Inc.
- */
- public static final int A_AND_D_ENGINEERING = 0x0069;
-
- /*
- * MindTree Ltd.
- */
- public static final int MINDTREE = 0x006A;
-
- /*
- * Polar Electro OY.
- */
- public static final int POLAR_ELECTRO = 0x006B;
-
- /*
- * Beautiful Enterprise Co., Ltd.
- */
- public static final int BEAUTIFUL_ENTERPRISE = 0x006C;
-
- /*
- * BriarTek, Inc.
- */
- public static final int BRIARTEK = 0x006D;
-
- /*
- * Summit Data Communications, Inc.
- */
- public static final int SUMMIT_DATA_COMMUNICATIONS = 0x006E;
-
- /*
- * Sound ID.
- */
- public static final int SOUND_ID = 0x006F;
-
- /*
- * Monster, LLC.
- */
- public static final int MONSTER = 0x0070;
-
- /*
- * connectBlue AB.
- */
- public static final int CONNECTBLUE = 0x0071;
-
- /*
- * ShangHai Super Smart Electronics Co. Ltd.
- */
- public static final int SHANGHAI_SUPER_SMART_ELECTRONICS = 0x0072;
-
- /*
- * Group Sense Ltd.
- */
- public static final int GROUP_SENSE = 0x0073;
-
- /*
- * Zomm, LLC.
- */
- public static final int ZOMM = 0x0074;
-
- /*
- * Samsung Electronics Co. Ltd.
- */
- public static final int SAMSUNG_ELECTRONICS = 0x0075;
-
- /*
- * Creative Technology Ltd.
- */
- public static final int CREATIVE_TECHNOLOGY = 0x0076;
-
- /*
- * Laird Technologies.
- */
- public static final int LAIRD_TECHNOLOGIES = 0x0077;
-
- /*
- * Nike, Inc.
- */
- public static final int NIKE = 0x0078;
-
- /*
- * lesswire AG.
- */
- public static final int LESSWIRE = 0x0079;
-
- /*
- * MStar Semiconductor, Inc.
- */
- public static final int MSTAR_SEMICONDUCTOR = 0x007A;
-
- /*
- * Hanlynn Technologies.
- */
- public static final int HANLYNN_TECHNOLOGIES = 0x007B;
-
- /*
- * A & R Cambridge.
- */
- public static final int A_AND_R_CAMBRIDGE = 0x007C;
-
- /*
- * Seers Technology Co. Ltd.
- */
- public static final int SEERS_TECHNOLOGY = 0x007D;
-
- /*
- * Sports Tracking Technologies Ltd.
- */
- public static final int SPORTS_TRACKING_TECHNOLOGIES = 0x007E;
-
- /*
- * Autonet Mobile.
- */
- public static final int AUTONET_MOBILE = 0x007F;
-
- /*
- * DeLorme Publishing Company, Inc.
- */
- public static final int DELORME_PUBLISHING_COMPANY = 0x0080;
-
- /*
- * WuXi Vimicro.
- */
- public static final int WUXI_VIMICRO = 0x0081;
-
- /*
- * Sennheiser Communications A/S.
- */
- public static final int SENNHEISER_COMMUNICATIONS = 0x0082;
-
- /*
- * TimeKeeping Systems, Inc.
- */
- public static final int TIMEKEEPING_SYSTEMS = 0x0083;
-
- /*
- * Ludus Helsinki Ltd.
- */
- public static final int LUDUS_HELSINKI = 0x0084;
-
- /*
- * BlueRadios, Inc.
- */
- public static final int BLUERADIOS = 0x0085;
-
- /*
- * equinox AG.
- */
- public static final int EQUINOX_AG = 0x0086;
-
- /*
- * Garmin International, Inc.
- */
- public static final int GARMIN_INTERNATIONAL = 0x0087;
-
- /*
- * Ecotest.
- */
- public static final int ECOTEST = 0x0088;
-
- /*
- * GN ReSound A/S.
- */
- public static final int GN_RESOUND = 0x0089;
-
- /*
- * Jawbone.
- */
- public static final int JAWBONE = 0x008A;
-
- /*
- * Topcorn Positioning Systems, LLC.
- */
- public static final int TOPCORN_POSITIONING_SYSTEMS = 0x008B;
-
- /*
- * Qualcomm Labs, Inc.
- */
- public static final int QUALCOMM_LABS = 0x008C;
-
- /*
- * Zscan Software.
- */
- public static final int ZSCAN_SOFTWARE = 0x008D;
-
- /*
- * Quintic Corp.
- */
- public static final int QUINTIC = 0x008E;
-
- /*
- * Stollman E+V GmbH.
- */
- public static final int STOLLMAN_E_PLUS_V = 0x008F;
-
- /*
- * Funai Electric Co., Ltd.
- */
- public static final int FUNAI_ELECTRIC = 0x0090;
-
- /*
- * Advanced PANMOBIL Systems GmbH & Co. KG.
- */
- public static final int ADVANCED_PANMOBIL_SYSTEMS = 0x0091;
-
- /*
- * ThinkOptics, Inc.
- */
- public static final int THINKOPTICS = 0x0092;
-
- /*
- * Universal Electronics, Inc.
- */
- public static final int UNIVERSAL_ELECTRONICS = 0x0093;
-
- /*
- * Airoha Technology Corp.
- */
- public static final int AIROHA_TECHNOLOGY = 0x0094;
-
- /*
- * NEC Lighting, Ltd.
- */
- public static final int NEC_LIGHTING = 0x0095;
-
- /*
- * ODM Technology, Inc.
- */
- public static final int ODM_TECHNOLOGY = 0x0096;
-
- /*
- * Bluetrek Technologies Limited.
- */
- public static final int BLUETREK_TECHNOLOGIES = 0x0097;
-
- /*
- * zer01.tv GmbH.
- */
- public static final int ZER01_TV = 0x0098;
-
- /*
- * i.Tech Dynamic Global Distribution Ltd.
- */
- public static final int I_TECH_DYNAMIC_GLOBAL_DISTRIBUTION = 0x0099;
-
- /*
- * Alpwise.
- */
- public static final int ALPWISE = 0x009A;
-
- /*
- * Jiangsu Toppower Automotive Electronics Co., Ltd.
- */
- public static final int JIANGSU_TOPPOWER_AUTOMOTIVE_ELECTRONICS = 0x009B;
-
- /*
- * Colorfy, Inc.
- */
- public static final int COLORFY = 0x009C;
-
- /*
- * Geoforce Inc.
- */
- public static final int GEOFORCE = 0x009D;
-
- /*
- * Bose Corporation.
- */
- public static final int BOSE = 0x009E;
-
- /*
- * Suunto Oy.
- */
- public static final int SUUNTO = 0x009F;
-
- /*
- * Kensington Computer Products Group.
- */
- public static final int KENSINGTON_COMPUTER_PRODUCTS_GROUP = 0x00A0;
-
- /*
- * SR-Medizinelektronik.
- */
- public static final int SR_MEDIZINELEKTRONIK = 0x00A1;
-
- /*
- * Vertu Corporation Limited.
- */
- public static final int VERTU = 0x00A2;
-
- /*
- * Meta Watch Ltd.
- */
- public static final int META_WATCH = 0x00A3;
-
- /*
- * LINAK A/S.
- */
- public static final int LINAK = 0x00A4;
-
- /*
- * OTL Dynamics LLC.
- */
- public static final int OTL_DYNAMICS = 0x00A5;
-
- /*
- * Panda Ocean Inc.
- */
- public static final int PANDA_OCEAN = 0x00A6;
-
- /*
- * Visteon Corporation.
- */
- public static final int VISTEON = 0x00A7;
-
- /*
- * ARP Devices Limited.
- */
- public static final int ARP_DEVICES = 0x00A8;
-
- /*
- * Magneti Marelli S.p.A.
- */
- public static final int MAGNETI_MARELLI = 0x00A9;
-
- /*
- * CAEN RFID srl.
- */
- public static final int CAEN_RFID = 0x00AA;
-
- /*
- * Ingenieur-Systemgruppe Zahn GmbH.
- */
- public static final int INGENIEUR_SYSTEMGRUPPE_ZAHN = 0x00AB;
-
- /*
- * Green Throttle Games.
- */
- public static final int GREEN_THROTTLE_GAMES = 0x00AC;
-
- /*
- * Peter Systemtechnik GmbH.
- */
- public static final int PETER_SYSTEMTECHNIK = 0x00AD;
-
- /*
- * Omegawave Oy.
- */
- public static final int OMEGAWAVE = 0x00AE;
-
- /*
- * Cinetix.
- */
- public static final int CINETIX = 0x00AF;
-
- /*
- * Passif Semiconductor Corp.
- */
- public static final int PASSIF_SEMICONDUCTOR = 0x00B0;
-
- /*
- * Saris Cycling Group, Inc.
- */
- public static final int SARIS_CYCLING_GROUP = 0x00B1;
-
- /*
- * Bekey A/S.
- */
- public static final int BEKEY = 0x00B2;
-
- /*
- * Clarinox Technologies Pty. Ltd.
- */
- public static final int CLARINOX_TECHNOLOGIES = 0x00B3;
-
- /*
- * BDE Technology Co., Ltd.
- */
- public static final int BDE_TECHNOLOGY = 0x00B4;
-
- /*
- * Swirl Networks.
- */
- public static final int SWIRL_NETWORKS = 0x00B5;
-
- /*
- * Meso international.
- */
- public static final int MESO_INTERNATIONAL = 0x00B6;
-
- /*
- * TreLab Ltd.
- */
- public static final int TRELAB = 0x00B7;
-
- /*
- * Qualcomm Innovation Center, Inc. (QuIC).
- */
- public static final int QUALCOMM_INNOVATION_CENTER = 0x00B8;
-
- /*
- * Johnson Controls, Inc.
- */
- public static final int JOHNSON_CONTROLS = 0x00B9;
-
- /*
- * Starkey Laboratories Inc.
- */
- public static final int STARKEY_LABORATORIES = 0x00BA;
-
- /*
- * S-Power Electronics Limited.
- */
- public static final int S_POWER_ELECTRONICS = 0x00BB;
-
- /*
- * Ace Sensor Inc.
- */
- public static final int ACE_SENSOR = 0x00BC;
-
- /*
- * Aplix Corporation.
- */
- public static final int APLIX = 0x00BD;
-
- /*
- * AAMP of America.
- */
- public static final int AAMP_OF_AMERICA = 0x00BE;
-
- /*
- * Stalmart Technology Limited.
- */
- public static final int STALMART_TECHNOLOGY = 0x00BF;
-
- /*
- * AMICCOM Electronics Corporation.
- */
- public static final int AMICCOM_ELECTRONICS = 0x00C0;
-
- /*
- * Shenzhen Excelsecu Data Technology Co.,Ltd.
- */
- public static final int SHENZHEN_EXCELSECU_DATA_TECHNOLOGY = 0x00C1;
-
- /*
- * Geneq Inc.
- */
- public static final int GENEQ = 0x00C2;
-
- /*
- * adidas AG.
- */
- public static final int ADIDAS = 0x00C3;
-
- /*
- * LG Electronics.
- */
- public static final int LG_ELECTRONICS = 0x00C4;
-
- /*
- * Onset Computer Corporation.
- */
- public static final int ONSET_COMPUTER = 0x00C5;
-
- /*
- * Selfly BV.
- */
- public static final int SELFLY = 0x00C6;
-
- /*
- * Quuppa Oy.
- */
- public static final int QUUPPA = 0x00C7;
-
- /*
- * GeLo Inc.
- */
- public static final int GELO = 0x00C8;
-
- /*
- * Evluma.
- */
- public static final int EVLUMA = 0x00C9;
-
- /*
- * MC10.
- */
- public static final int MC10 = 0x00CA;
-
- /*
- * Binauric SE.
- */
- public static final int BINAURIC = 0x00CB;
-
- /*
- * Beats Electronics.
- */
- public static final int BEATS_ELECTRONICS = 0x00CC;
-
- /*
- * Microchip Technology Inc.
- */
- public static final int MICROCHIP_TECHNOLOGY = 0x00CD;
-
- /*
- * Elgato Systems GmbH.
- */
- public static final int ELGATO_SYSTEMS = 0x00CE;
-
- /*
- * ARCHOS SA.
- */
- public static final int ARCHOS = 0x00CF;
-
- /*
- * Dexcom, Inc.
- */
- public static final int DEXCOM = 0x00D0;
-
- /*
- * Polar Electro Europe B.V.
- */
- public static final int POLAR_ELECTRO_EUROPE = 0x00D1;
-
- /*
- * Dialog Semiconductor B.V.
- */
- public static final int DIALOG_SEMICONDUCTOR = 0x00D2;
-
- /*
- * Taixingbang Technology (HK) Co,. LTD.
- */
- public static final int TAIXINGBANG_TECHNOLOGY = 0x00D3;
-
- /*
- * Kawantech.
- */
- public static final int KAWANTECH = 0x00D4;
-
- /*
- * Austco Communication Systems.
- */
- public static final int AUSTCO_COMMUNICATION_SYSTEMS = 0x00D5;
-
- /*
- * Timex Group USA, Inc.
- */
- public static final int TIMEX_GROUP_USA = 0x00D6;
-
- /*
- * Qualcomm Technologies, Inc.
- */
- public static final int QUALCOMM_TECHNOLOGIES = 0x00D7;
-
- /*
- * Qualcomm Connected Experiences, Inc.
- */
- public static final int QUALCOMM_CONNECTED_EXPERIENCES = 0x00D8;
-
- /*
- * Voyetra Turtle Beach.
- */
- public static final int VOYETRA_TURTLE_BEACH = 0x00D9;
-
- /*
- * txtr GmbH.
- */
- public static final int TXTR = 0x00DA;
-
- /*
- * Biosentronics.
- */
- public static final int BIOSENTRONICS = 0x00DB;
-
- /*
- * Procter & Gamble.
- */
- public static final int PROCTER_AND_GAMBLE = 0x00DC;
-
- /*
- * Hosiden Corporation.
- */
- public static final int HOSIDEN = 0x00DD;
-
- /*
- * Muzik LLC.
- */
- public static final int MUZIK = 0x00DE;
-
- /*
- * Misfit Wearables Corp.
- */
- public static final int MISFIT_WEARABLES = 0x00DF;
-
- /*
- * Google.
- */
- public static final int GOOGLE = 0x00E0;
-
- /*
- * Danlers Ltd.
- */
- public static final int DANLERS = 0x00E1;
-
- /*
- * Semilink Inc.
- */
- public static final int SEMILINK = 0x00E2;
-
- /*
- * You can't instantiate one of these.
- */
- private BluetoothAssignedNumbers() {
- }
-
-}
diff --git a/core/java/android/bluetooth/BluetoothAudioConfig.java b/core/java/android/bluetooth/BluetoothAudioConfig.java
deleted file mode 100644
index 4c8b8c1..0000000
--- a/core/java/android/bluetooth/BluetoothAudioConfig.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents the audio configuration for a Bluetooth A2DP source device.
- *
- * {@see BluetoothA2dpSink}
- *
- * {@hide}
- */
-public final class BluetoothAudioConfig implements Parcelable {
-
- private final int mSampleRate;
- private final int mChannelConfig;
- private final int mAudioFormat;
-
- public BluetoothAudioConfig(int sampleRate, int channelConfig, int audioFormat) {
- mSampleRate = sampleRate;
- mChannelConfig = channelConfig;
- mAudioFormat = audioFormat;
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof BluetoothAudioConfig) {
- BluetoothAudioConfig bac = (BluetoothAudioConfig) o;
- return (bac.mSampleRate == mSampleRate && bac.mChannelConfig == mChannelConfig
- && bac.mAudioFormat == mAudioFormat);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return mSampleRate | (mChannelConfig << 24) | (mAudioFormat << 28);
- }
-
- @Override
- public String toString() {
- return "{mSampleRate:" + mSampleRate + ",mChannelConfig:" + mChannelConfig
- + ",mAudioFormat:" + mAudioFormat + "}";
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothAudioConfig> CREATOR =
- new Parcelable.Creator<BluetoothAudioConfig>() {
- public BluetoothAudioConfig createFromParcel(Parcel in) {
- int sampleRate = in.readInt();
- int channelConfig = in.readInt();
- int audioFormat = in.readInt();
- return new BluetoothAudioConfig(sampleRate, channelConfig, audioFormat);
- }
-
- public BluetoothAudioConfig[] newArray(int size) {
- return new BluetoothAudioConfig[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mSampleRate);
- out.writeInt(mChannelConfig);
- out.writeInt(mAudioFormat);
- }
-
- /**
- * Returns the sample rate in samples per second
- *
- * @return sample rate
- */
- public int getSampleRate() {
- return mSampleRate;
- }
-
- /**
- * Returns the channel configuration (either {@link android.media.AudioFormat#CHANNEL_IN_MONO}
- * or {@link android.media.AudioFormat#CHANNEL_IN_STEREO})
- *
- * @return channel configuration
- */
- public int getChannelConfig() {
- return mChannelConfig;
- }
-
- /**
- * Returns the channel audio format (either {@link android.media.AudioFormat#ENCODING_PCM_16BIT}
- * or {@link android.media.AudioFormat#ENCODING_PCM_8BIT}
- *
- * @return audio format
- */
- public int getAudioFormat() {
- return mAudioFormat;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothAvrcp.java b/core/java/android/bluetooth/BluetoothAvrcp.java
deleted file mode 100644
index 1a4c759..0000000
--- a/core/java/android/bluetooth/BluetoothAvrcp.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-/**
- * This class contains constants for Bluetooth AVRCP profile.
- *
- * {@hide}
- */
-public final class BluetoothAvrcp {
-
- /*
- * State flags for Passthrough commands
- */
- public static final int PASSTHROUGH_STATE_PRESS = 0;
- public static final int PASSTHROUGH_STATE_RELEASE = 1;
-
- /*
- * Operation IDs for Passthrough commands
- */
- public static final int PASSTHROUGH_ID_SELECT = 0x00; /* select */
- public static final int PASSTHROUGH_ID_UP = 0x01; /* up */
- public static final int PASSTHROUGH_ID_DOWN = 0x02; /* down */
- public static final int PASSTHROUGH_ID_LEFT = 0x03; /* left */
- public static final int PASSTHROUGH_ID_RIGHT = 0x04; /* right */
- public static final int PASSTHROUGH_ID_RIGHT_UP = 0x05; /* right-up */
- public static final int PASSTHROUGH_ID_RIGHT_DOWN = 0x06; /* right-down */
- public static final int PASSTHROUGH_ID_LEFT_UP = 0x07; /* left-up */
- public static final int PASSTHROUGH_ID_LEFT_DOWN = 0x08; /* left-down */
- public static final int PASSTHROUGH_ID_ROOT_MENU = 0x09; /* root menu */
- public static final int PASSTHROUGH_ID_SETUP_MENU = 0x0A; /* setup menu */
- public static final int PASSTHROUGH_ID_CONT_MENU = 0x0B; /* contents menu */
- public static final int PASSTHROUGH_ID_FAV_MENU = 0x0C; /* favorite menu */
- public static final int PASSTHROUGH_ID_EXIT = 0x0D; /* exit */
- public static final int PASSTHROUGH_ID_0 = 0x20; /* 0 */
- public static final int PASSTHROUGH_ID_1 = 0x21; /* 1 */
- public static final int PASSTHROUGH_ID_2 = 0x22; /* 2 */
- public static final int PASSTHROUGH_ID_3 = 0x23; /* 3 */
- public static final int PASSTHROUGH_ID_4 = 0x24; /* 4 */
- public static final int PASSTHROUGH_ID_5 = 0x25; /* 5 */
- public static final int PASSTHROUGH_ID_6 = 0x26; /* 6 */
- public static final int PASSTHROUGH_ID_7 = 0x27; /* 7 */
- public static final int PASSTHROUGH_ID_8 = 0x28; /* 8 */
- public static final int PASSTHROUGH_ID_9 = 0x29; /* 9 */
- public static final int PASSTHROUGH_ID_DOT = 0x2A; /* dot */
- public static final int PASSTHROUGH_ID_ENTER = 0x2B; /* enter */
- public static final int PASSTHROUGH_ID_CLEAR = 0x2C; /* clear */
- public static final int PASSTHROUGH_ID_CHAN_UP = 0x30; /* channel up */
- public static final int PASSTHROUGH_ID_CHAN_DOWN = 0x31; /* channel down */
- public static final int PASSTHROUGH_ID_PREV_CHAN = 0x32; /* previous channel */
- public static final int PASSTHROUGH_ID_SOUND_SEL = 0x33; /* sound select */
- public static final int PASSTHROUGH_ID_INPUT_SEL = 0x34; /* input select */
- public static final int PASSTHROUGH_ID_DISP_INFO = 0x35; /* display information */
- public static final int PASSTHROUGH_ID_HELP = 0x36; /* help */
- public static final int PASSTHROUGH_ID_PAGE_UP = 0x37; /* page up */
- public static final int PASSTHROUGH_ID_PAGE_DOWN = 0x38; /* page down */
- public static final int PASSTHROUGH_ID_POWER = 0x40; /* power */
- public static final int PASSTHROUGH_ID_VOL_UP = 0x41; /* volume up */
- public static final int PASSTHROUGH_ID_VOL_DOWN = 0x42; /* volume down */
- public static final int PASSTHROUGH_ID_MUTE = 0x43; /* mute */
- public static final int PASSTHROUGH_ID_PLAY = 0x44; /* play */
- public static final int PASSTHROUGH_ID_STOP = 0x45; /* stop */
- public static final int PASSTHROUGH_ID_PAUSE = 0x46; /* pause */
- public static final int PASSTHROUGH_ID_RECORD = 0x47; /* record */
- public static final int PASSTHROUGH_ID_REWIND = 0x48; /* rewind */
- public static final int PASSTHROUGH_ID_FAST_FOR = 0x49; /* fast forward */
- public static final int PASSTHROUGH_ID_EJECT = 0x4A; /* eject */
- public static final int PASSTHROUGH_ID_FORWARD = 0x4B; /* forward */
- public static final int PASSTHROUGH_ID_BACKWARD = 0x4C; /* backward */
- public static final int PASSTHROUGH_ID_ANGLE = 0x50; /* angle */
- public static final int PASSTHROUGH_ID_SUBPICT = 0x51; /* subpicture */
- public static final int PASSTHROUGH_ID_F1 = 0x71; /* F1 */
- public static final int PASSTHROUGH_ID_F2 = 0x72; /* F2 */
- public static final int PASSTHROUGH_ID_F3 = 0x73; /* F3 */
- public static final int PASSTHROUGH_ID_F4 = 0x74; /* F4 */
- public static final int PASSTHROUGH_ID_F5 = 0x75; /* F5 */
- public static final int PASSTHROUGH_ID_VENDOR = 0x7E; /* vendor unique */
- public static final int PASSTHROUGH_KEYPRESSED_RELEASE = 0x80;
-}
diff --git a/core/java/android/bluetooth/BluetoothAvrcpController.java b/core/java/android/bluetooth/BluetoothAvrcpController.java
deleted file mode 100644
index 81fc3e1..0000000
--- a/core/java/android/bluetooth/BluetoothAvrcpController.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the public APIs to control the Bluetooth AVRCP Controller. It currently
- * supports player information, playback support and track metadata.
- *
- * <p>BluetoothAvrcpController is a proxy object for controlling the Bluetooth AVRCP
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothAvrcpController proxy object.
- *
- * {@hide}
- */
-public final class BluetoothAvrcpController implements BluetoothProfile {
- private static final String TAG = "BluetoothAvrcpController";
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the AVRCP Controller
- * profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.avrcp-controller.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * Intent used to broadcast the change in player application setting state on AVRCP AG.
- *
- * <p>This intent will have the following extras:
- * <ul>
- * <li> {@link #EXTRA_PLAYER_SETTING} - {@link BluetoothAvrcpPlayerSettings} containing the
- * most recent player setting. </li>
- * </ul>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PLAYER_SETTING =
- "android.bluetooth.avrcp-controller.profile.action.PLAYER_SETTING";
-
- public static final String EXTRA_PLAYER_SETTING =
- "android.bluetooth.avrcp-controller.profile.extra.PLAYER_SETTING";
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothAvrcpController> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.AVRCP_CONTROLLER,
- "BluetoothAvrcpController", IBluetoothAvrcpController.class.getName()) {
- @Override
- public IBluetoothAvrcpController getServiceInterface(IBinder service) {
- return IBluetoothAvrcpController.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothAvrcpController proxy object for interacting with the local
- * Bluetooth AVRCP service.
- */
- /* package */ BluetoothAvrcpController(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- /*package*/ void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothAvrcpController getService() {
- return mProfileConnector.getService();
- }
-
- @Override
- public void finalize() {
- close();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothAvrcpController service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothAvrcpController service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (VDBG) log("getState(" + device + ")");
- final IBluetoothAvrcpController service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Gets the player application settings.
- *
- * @return the {@link BluetoothAvrcpPlayerSettings} or {@link null} if there is an error.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothAvrcpPlayerSettings getPlayerSettings(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "getPlayerSettings");
- BluetoothAvrcpPlayerSettings settings = null;
- final IBluetoothAvrcpController service = getService();
- final BluetoothAvrcpPlayerSettings defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<BluetoothAvrcpPlayerSettings> recv =
- new SynchronousResultReceiver();
- service.getPlayerSettings(device, mAttributionSource, recv);
- settings = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Sets the player app setting for current player.
- * returns true in case setting is supported by remote, false otherwise
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setPlayerApplicationSetting(BluetoothAvrcpPlayerSettings plAppSetting) {
- if (DBG) Log.d(TAG, "setPlayerApplicationSetting");
- final IBluetoothAvrcpController service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setPlayerApplicationSetting(plAppSetting, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send Group Navigation Command to Remote.
- * possible keycode values: next_grp, previous_grp defined above
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void sendGroupNavigationCmd(BluetoothDevice device, int keyCode, int keyState) {
- Log.d(TAG, "sendGroupNavigationCmd dev = " + device + " key " + keyCode + " State = "
- + keyState);
- final IBluetoothAvrcpController service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.sendGroupNavigationCmd(device, keyCode, keyState, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- return;
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- private boolean isEnabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_ON;
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java b/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java
deleted file mode 100644
index 30aea1a..0000000
--- a/core/java/android/bluetooth/BluetoothAvrcpPlayerSettings.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Class used to identify settings associated with the player on AG.
- *
- * {@hide}
- */
-public final class BluetoothAvrcpPlayerSettings implements Parcelable {
- public static final String TAG = "BluetoothAvrcpPlayerSettings";
-
- /**
- * Equalizer setting.
- */
- public static final int SETTING_EQUALIZER = 0x01;
-
- /**
- * Repeat setting.
- */
- public static final int SETTING_REPEAT = 0x02;
-
- /**
- * Shuffle setting.
- */
- public static final int SETTING_SHUFFLE = 0x04;
-
- /**
- * Scan mode setting.
- */
- public static final int SETTING_SCAN = 0x08;
-
- /**
- * Invalid state.
- *
- * Used for returning error codes.
- */
- public static final int STATE_INVALID = -1;
-
- /**
- * OFF state.
- *
- * Denotes a general OFF state. Applies to all settings.
- */
- public static final int STATE_OFF = 0x00;
-
- /**
- * ON state.
- *
- * Applies to {@link SETTING_EQUALIZER}.
- */
- public static final int STATE_ON = 0x01;
-
- /**
- * Single track repeat.
- *
- * Applies only to {@link SETTING_REPEAT}.
- */
- public static final int STATE_SINGLE_TRACK = 0x02;
-
- /**
- * All track repeat/shuffle.
- *
- * Applies to {@link #SETTING_REPEAT}, {@link #SETTING_SHUFFLE} and {@link #SETTING_SCAN}.
- */
- public static final int STATE_ALL_TRACK = 0x03;
-
- /**
- * Group repeat/shuffle.
- *
- * Applies to {@link #SETTING_REPEAT}, {@link #SETTING_SHUFFLE} and {@link #SETTING_SCAN}.
- */
- public static final int STATE_GROUP = 0x04;
-
- /**
- * List of supported settings ORed.
- */
- private int mSettings;
-
- /**
- * Hash map of current capability values.
- */
- private Map<Integer, Integer> mSettingsValue = new HashMap<Integer, Integer>();
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mSettings);
- out.writeInt(mSettingsValue.size());
- for (int k : mSettingsValue.keySet()) {
- out.writeInt(k);
- out.writeInt(mSettingsValue.get(k));
- }
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothAvrcpPlayerSettings> CREATOR =
- new Parcelable.Creator<BluetoothAvrcpPlayerSettings>() {
- public BluetoothAvrcpPlayerSettings createFromParcel(Parcel in) {
- return new BluetoothAvrcpPlayerSettings(in);
- }
-
- public BluetoothAvrcpPlayerSettings[] newArray(int size) {
- return new BluetoothAvrcpPlayerSettings[size];
- }
- };
-
- private BluetoothAvrcpPlayerSettings(Parcel in) {
- mSettings = in.readInt();
- int numSettings = in.readInt();
- for (int i = 0; i < numSettings; i++) {
- mSettingsValue.put(in.readInt(), in.readInt());
- }
- }
-
- /**
- * Create a new player settings object.
- *
- * @param settings a ORed value of SETTINGS_* defined above.
- */
- public BluetoothAvrcpPlayerSettings(int settings) {
- mSettings = settings;
- }
-
- /**
- * Get the supported settings.
- *
- * @return int ORed value of supported settings.
- */
- public int getSettings() {
- return mSettings;
- }
-
- /**
- * Add a setting value.
- *
- * The setting must be part of possible settings in {@link getSettings()}.
- *
- * @param setting setting config.
- * @param value value for the setting.
- * @throws IllegalStateException if the setting is not supported.
- */
- public void addSettingValue(int setting, int value) {
- if ((setting & mSettings) == 0) {
- Log.e(TAG, "Setting not supported: " + setting + " " + mSettings);
- throw new IllegalStateException("Setting not supported: " + setting);
- }
- mSettingsValue.put(setting, value);
- }
-
- /**
- * Get a setting value.
- *
- * The setting must be part of possible settings in {@link getSettings()}.
- *
- * @param setting setting config.
- * @return value value for the setting.
- * @throws IllegalStateException if the setting is not supported.
- */
- public int getSettingValue(int setting) {
- if ((setting & mSettings) == 0) {
- Log.e(TAG, "Setting not supported: " + setting + " " + mSettings);
- throw new IllegalStateException("Setting not supported: " + setting);
- }
- Integer i = mSettingsValue.get(setting);
- if (i == null) return -1;
- return i;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
deleted file mode 100755
index a3c45d0..0000000
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ /dev/null
@@ -1,445 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-
-/**
- * Represents a Bluetooth class, which describes general characteristics
- * and capabilities of a device. For example, a Bluetooth class will
- * specify the general device type such as a phone, a computer, or
- * headset, and whether it's capable of services such as audio or telephony.
- *
- * <p>Every Bluetooth class is composed of zero or more service classes, and
- * exactly one device class. The device class is further broken down into major
- * and minor device class components.
- *
- * <p>{@link BluetoothClass} is useful as a hint to roughly describe a device
- * (for example to show an icon in the UI), but does not reliably describe which
- * Bluetooth profiles or services are actually supported by a device. Accurate
- * service discovery is done through SDP requests, which are automatically
- * performed when creating an RFCOMM socket with {@link
- * BluetoothDevice#createRfcommSocketToServiceRecord} and {@link
- * BluetoothAdapter#listenUsingRfcommWithServiceRecord}</p>
- *
- * <p>Use {@link BluetoothDevice#getBluetoothClass} to retrieve the class for
- * a remote device.
- *
- * <!--
- * The Bluetooth class is a 32 bit field. The format of these bits is defined at
- * http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
- * (login required). This class contains that 32 bit field, and provides
- * constants and methods to determine which Service Class(es) and Device Class
- * are encoded in that field.
- * -->
- */
-public final class BluetoothClass implements Parcelable {
- /**
- * Legacy error value. Applications should use null instead.
- *
- * @hide
- */
- public static final int ERROR = 0xFF000000;
-
- private final int mClass;
-
- /** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public BluetoothClass(int classInt) {
- mClass = classInt;
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof BluetoothClass) {
- return mClass == ((BluetoothClass) o).mClass;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return mClass;
- }
-
- @Override
- public String toString() {
- return Integer.toHexString(mClass);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothClass> CREATOR =
- new Parcelable.Creator<BluetoothClass>() {
- public BluetoothClass createFromParcel(Parcel in) {
- return new BluetoothClass(in.readInt());
- }
-
- public BluetoothClass[] newArray(int size) {
- return new BluetoothClass[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mClass);
- }
-
- /**
- * Defines all service class constants.
- * <p>Each {@link BluetoothClass} encodes zero or more service classes.
- */
- public static final class Service {
- private static final int BITMASK = 0xFFE000;
-
- public static final int LIMITED_DISCOVERABILITY = 0x002000;
- public static final int LE_AUDIO = 0x004000;
- public static final int POSITIONING = 0x010000;
- public static final int NETWORKING = 0x020000;
- public static final int RENDER = 0x040000;
- public static final int CAPTURE = 0x080000;
- public static final int OBJECT_TRANSFER = 0x100000;
- public static final int AUDIO = 0x200000;
- public static final int TELEPHONY = 0x400000;
- public static final int INFORMATION = 0x800000;
- }
-
- /**
- * Return true if the specified service class is supported by this
- * {@link BluetoothClass}.
- * <p>Valid service classes are the public constants in
- * {@link BluetoothClass.Service}. For example, {@link
- * BluetoothClass.Service#AUDIO}.
- *
- * @param service valid service class
- * @return true if the service class is supported
- */
- public boolean hasService(int service) {
- return ((mClass & Service.BITMASK & service) != 0);
- }
-
- /**
- * Defines all device class constants.
- * <p>Each {@link BluetoothClass} encodes exactly one device class, with
- * major and minor components.
- * <p>The constants in {@link
- * BluetoothClass.Device} represent a combination of major and minor
- * device components (the complete device class). The constants in {@link
- * BluetoothClass.Device.Major} represent only major device classes.
- * <p>See {@link BluetoothClass.Service} for service class constants.
- */
- public static class Device {
- private static final int BITMASK = 0x1FFC;
-
- /**
- * Defines all major device class constants.
- * <p>See {@link BluetoothClass.Device} for minor classes.
- */
- public static class Major {
- private static final int BITMASK = 0x1F00;
-
- public static final int MISC = 0x0000;
- public static final int COMPUTER = 0x0100;
- public static final int PHONE = 0x0200;
- public static final int NETWORKING = 0x0300;
- public static final int AUDIO_VIDEO = 0x0400;
- public static final int PERIPHERAL = 0x0500;
- public static final int IMAGING = 0x0600;
- public static final int WEARABLE = 0x0700;
- public static final int TOY = 0x0800;
- public static final int HEALTH = 0x0900;
- public static final int UNCATEGORIZED = 0x1F00;
- }
-
- // Devices in the COMPUTER major class
- public static final int COMPUTER_UNCATEGORIZED = 0x0100;
- public static final int COMPUTER_DESKTOP = 0x0104;
- public static final int COMPUTER_SERVER = 0x0108;
- public static final int COMPUTER_LAPTOP = 0x010C;
- public static final int COMPUTER_HANDHELD_PC_PDA = 0x0110;
- public static final int COMPUTER_PALM_SIZE_PC_PDA = 0x0114;
- public static final int COMPUTER_WEARABLE = 0x0118;
-
- // Devices in the PHONE major class
- public static final int PHONE_UNCATEGORIZED = 0x0200;
- public static final int PHONE_CELLULAR = 0x0204;
- public static final int PHONE_CORDLESS = 0x0208;
- public static final int PHONE_SMART = 0x020C;
- public static final int PHONE_MODEM_OR_GATEWAY = 0x0210;
- public static final int PHONE_ISDN = 0x0214;
-
- // Minor classes for the AUDIO_VIDEO major class
- public static final int AUDIO_VIDEO_UNCATEGORIZED = 0x0400;
- public static final int AUDIO_VIDEO_WEARABLE_HEADSET = 0x0404;
- public static final int AUDIO_VIDEO_HANDSFREE = 0x0408;
- //public static final int AUDIO_VIDEO_RESERVED = 0x040C;
- public static final int AUDIO_VIDEO_MICROPHONE = 0x0410;
- public static final int AUDIO_VIDEO_LOUDSPEAKER = 0x0414;
- public static final int AUDIO_VIDEO_HEADPHONES = 0x0418;
- public static final int AUDIO_VIDEO_PORTABLE_AUDIO = 0x041C;
- public static final int AUDIO_VIDEO_CAR_AUDIO = 0x0420;
- public static final int AUDIO_VIDEO_SET_TOP_BOX = 0x0424;
- public static final int AUDIO_VIDEO_HIFI_AUDIO = 0x0428;
- public static final int AUDIO_VIDEO_VCR = 0x042C;
- public static final int AUDIO_VIDEO_VIDEO_CAMERA = 0x0430;
- public static final int AUDIO_VIDEO_CAMCORDER = 0x0434;
- public static final int AUDIO_VIDEO_VIDEO_MONITOR = 0x0438;
- public static final int AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER = 0x043C;
- public static final int AUDIO_VIDEO_VIDEO_CONFERENCING = 0x0440;
- //public static final int AUDIO_VIDEO_RESERVED = 0x0444;
- public static final int AUDIO_VIDEO_VIDEO_GAMING_TOY = 0x0448;
-
- // Devices in the WEARABLE major class
- public static final int WEARABLE_UNCATEGORIZED = 0x0700;
- public static final int WEARABLE_WRIST_WATCH = 0x0704;
- public static final int WEARABLE_PAGER = 0x0708;
- public static final int WEARABLE_JACKET = 0x070C;
- public static final int WEARABLE_HELMET = 0x0710;
- public static final int WEARABLE_GLASSES = 0x0714;
-
- // Devices in the TOY major class
- public static final int TOY_UNCATEGORIZED = 0x0800;
- public static final int TOY_ROBOT = 0x0804;
- public static final int TOY_VEHICLE = 0x0808;
- public static final int TOY_DOLL_ACTION_FIGURE = 0x080C;
- public static final int TOY_CONTROLLER = 0x0810;
- public static final int TOY_GAME = 0x0814;
-
- // Devices in the HEALTH major class
- public static final int HEALTH_UNCATEGORIZED = 0x0900;
- public static final int HEALTH_BLOOD_PRESSURE = 0x0904;
- public static final int HEALTH_THERMOMETER = 0x0908;
- public static final int HEALTH_WEIGHING = 0x090C;
- public static final int HEALTH_GLUCOSE = 0x0910;
- public static final int HEALTH_PULSE_OXIMETER = 0x0914;
- public static final int HEALTH_PULSE_RATE = 0x0918;
- public static final int HEALTH_DATA_DISPLAY = 0x091C;
-
- // Devices in PERIPHERAL major class
- /**
- * @hide
- */
- public static final int PERIPHERAL_NON_KEYBOARD_NON_POINTING = 0x0500;
- /**
- * @hide
- */
- public static final int PERIPHERAL_KEYBOARD = 0x0540;
- /**
- * @hide
- */
- public static final int PERIPHERAL_POINTING = 0x0580;
- /**
- * @hide
- */
- public static final int PERIPHERAL_KEYBOARD_POINTING = 0x05C0;
- }
-
- /**
- * Return the major device class component of this {@link BluetoothClass}.
- * <p>Values returned from this function can be compared with the
- * public constants in {@link BluetoothClass.Device.Major} to determine
- * which major class is encoded in this Bluetooth class.
- *
- * @return major device class component
- */
- public int getMajorDeviceClass() {
- return (mClass & Device.Major.BITMASK);
- }
-
- /**
- * Return the (major and minor) device class component of this
- * {@link BluetoothClass}.
- * <p>Values returned from this function can be compared with the
- * public constants in {@link BluetoothClass.Device} to determine which
- * device class is encoded in this Bluetooth class.
- *
- * @return device class component
- */
- public int getDeviceClass() {
- return (mClass & Device.BITMASK);
- }
-
- /**
- * Return the Bluetooth Class of Device (CoD) value including the
- * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and
- * minor device fields.
- *
- * <p>This value is an integer representation of Bluetooth CoD as in
- * Bluetooth specification.
- *
- * @see <a href="Bluetooth CoD">https://www.bluetooth.com/specifications/assigned-numbers/baseband</a>
- *
- * @hide
- */
- @TestApi
- public int getClassOfDevice() {
- return mClass;
- }
-
- /**
- * Return the Bluetooth Class of Device (CoD) value including the
- * {@link BluetoothClass.Service}, {@link BluetoothClass.Device.Major} and
- * minor device fields.
- *
- * <p>This value is a byte array representation of Bluetooth CoD as in
- * Bluetooth specification.
- *
- * <p>Bluetooth COD information is 3 bytes, but stored as an int. Hence the
- * MSB is useless and needs to be thrown away. The lower 3 bytes are
- * converted into a byte array MSB to LSB. Hence, using BIG_ENDIAN.
- *
- * @see <a href="Bluetooth CoD">https://www.bluetooth.com/specifications/assigned-numbers/baseband</a>
- *
- * @hide
- */
- public byte[] getClassOfDeviceBytes() {
- byte[] bytes = ByteBuffer.allocate(4)
- .order(ByteOrder.BIG_ENDIAN)
- .putInt(mClass)
- .array();
-
- // Discard the top byte
- return Arrays.copyOfRange(bytes, 1, bytes.length);
- }
-
- public static final int PROFILE_HEADSET = 0;
-
- public static final int PROFILE_A2DP = 1;
-
- /** @hide */
- @SystemApi
- public static final int PROFILE_OPP = 2;
-
- public static final int PROFILE_HID = 3;
-
- /** @hide */
- @SystemApi
- public static final int PROFILE_PANU = 4;
-
- /** @hide */
- @SystemApi
- public static final int PROFILE_NAP = 5;
-
- /** @hide */
- @SystemApi
- public static final int PROFILE_A2DP_SINK = 6;
-
- /**
- * Check class bits for possible bluetooth profile support.
- * This is a simple heuristic that tries to guess if a device with the
- * given class bits might support specified profile. It is not accurate for all
- * devices. It tries to err on the side of false positives.
- *
- * @param profile the profile to be checked
- * @return whether this device supports specified profile
- */
- public boolean doesClassMatch(int profile) {
- if (profile == PROFILE_A2DP) {
- if (hasService(Service.RENDER)) {
- return true;
- }
- // By the A2DP spec, sinks must indicate the RENDER service.
- // However we found some that do not (Chordette). So lets also
- // match on some other class bits.
- switch (getDeviceClass()) {
- case Device.AUDIO_VIDEO_HIFI_AUDIO:
- case Device.AUDIO_VIDEO_HEADPHONES:
- case Device.AUDIO_VIDEO_LOUDSPEAKER:
- case Device.AUDIO_VIDEO_CAR_AUDIO:
- return true;
- default:
- return false;
- }
- } else if (profile == PROFILE_A2DP_SINK) {
- if (hasService(Service.CAPTURE)) {
- return true;
- }
- // By the A2DP spec, srcs must indicate the CAPTURE service.
- // However if some device that do not, we try to
- // match on some other class bits.
- switch (getDeviceClass()) {
- case Device.AUDIO_VIDEO_HIFI_AUDIO:
- case Device.AUDIO_VIDEO_SET_TOP_BOX:
- case Device.AUDIO_VIDEO_VCR:
- return true;
- default:
- return false;
- }
- } else if (profile == PROFILE_HEADSET) {
- // The render service class is required by the spec for HFP, so is a
- // pretty good signal
- if (hasService(Service.RENDER)) {
- return true;
- }
- // Just in case they forgot the render service class
- switch (getDeviceClass()) {
- case Device.AUDIO_VIDEO_HANDSFREE:
- case Device.AUDIO_VIDEO_WEARABLE_HEADSET:
- case Device.AUDIO_VIDEO_CAR_AUDIO:
- return true;
- default:
- return false;
- }
- } else if (profile == PROFILE_OPP) {
- if (hasService(Service.OBJECT_TRANSFER)) {
- return true;
- }
-
- switch (getDeviceClass()) {
- case Device.COMPUTER_UNCATEGORIZED:
- case Device.COMPUTER_DESKTOP:
- case Device.COMPUTER_SERVER:
- case Device.COMPUTER_LAPTOP:
- case Device.COMPUTER_HANDHELD_PC_PDA:
- case Device.COMPUTER_PALM_SIZE_PC_PDA:
- case Device.COMPUTER_WEARABLE:
- case Device.PHONE_UNCATEGORIZED:
- case Device.PHONE_CELLULAR:
- case Device.PHONE_CORDLESS:
- case Device.PHONE_SMART:
- case Device.PHONE_MODEM_OR_GATEWAY:
- case Device.PHONE_ISDN:
- return true;
- default:
- return false;
- }
- } else if (profile == PROFILE_HID) {
- return getMajorDeviceClass() == Device.Major.PERIPHERAL;
- } else if (profile == PROFILE_PANU || profile == PROFILE_NAP) {
- // No good way to distinguish between the two, based on class bits.
- if (hasService(Service.NETWORKING)) {
- return true;
- }
- return getMajorDeviceClass() == Device.Major.NETWORKING;
- } else {
- return false;
- }
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothCodecConfig.java b/core/java/android/bluetooth/BluetoothCodecConfig.java
deleted file mode 100644
index 9a4151a..0000000
--- a/core/java/android/bluetooth/BluetoothCodecConfig.java
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Represents the codec configuration for a Bluetooth A2DP source device.
- * <p>Contains the source codec type, the codec priority, the codec sample
- * rate, the codec bits per sample, and the codec channel mode.
- * <p>The source codec type values are the same as those supported by the
- * device hardware.
- *
- * {@see BluetoothA2dp}
- */
-public final class BluetoothCodecConfig implements Parcelable {
- /** @hide */
- @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = {
- SOURCE_CODEC_TYPE_SBC,
- SOURCE_CODEC_TYPE_AAC,
- SOURCE_CODEC_TYPE_APTX,
- SOURCE_CODEC_TYPE_APTX_HD,
- SOURCE_CODEC_TYPE_LDAC,
- SOURCE_CODEC_TYPE_INVALID
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface SourceCodecType {}
-
- /**
- * Source codec type SBC. This is the mandatory source codec
- * type.
- */
- public static final int SOURCE_CODEC_TYPE_SBC = 0;
-
- /**
- * Source codec type AAC.
- */
- public static final int SOURCE_CODEC_TYPE_AAC = 1;
-
- /**
- * Source codec type APTX.
- */
- public static final int SOURCE_CODEC_TYPE_APTX = 2;
-
- /**
- * Source codec type APTX HD.
- */
- public static final int SOURCE_CODEC_TYPE_APTX_HD = 3;
-
- /**
- * Source codec type LDAC.
- */
- public static final int SOURCE_CODEC_TYPE_LDAC = 4;
-
- /**
- * Source codec type invalid. This is the default value used for codec
- * type.
- */
- public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
-
- /**
- * Represents the count of valid source codec types. Can be accessed via
- * {@link #getMaxCodecType}.
- */
- private static final int SOURCE_CODEC_TYPE_MAX = 5;
-
- /** @hide */
- @IntDef(prefix = "CODEC_PRIORITY_", value = {
- CODEC_PRIORITY_DISABLED,
- CODEC_PRIORITY_DEFAULT,
- CODEC_PRIORITY_HIGHEST
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CodecPriority {}
-
- /**
- * Codec priority disabled.
- * Used to indicate that this codec is disabled and should not be used.
- */
- public static final int CODEC_PRIORITY_DISABLED = -1;
-
- /**
- * Codec priority default.
- * Default value used for codec priority.
- */
- public static final int CODEC_PRIORITY_DEFAULT = 0;
-
- /**
- * Codec priority highest.
- * Used to indicate the highest priority a codec can have.
- */
- public static final int CODEC_PRIORITY_HIGHEST = 1000 * 1000;
-
- /** @hide */
- @IntDef(prefix = "SAMPLE_RATE_", value = {
- SAMPLE_RATE_NONE,
- SAMPLE_RATE_44100,
- SAMPLE_RATE_48000,
- SAMPLE_RATE_88200,
- SAMPLE_RATE_96000,
- SAMPLE_RATE_176400,
- SAMPLE_RATE_192000
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface SampleRate {}
-
- /**
- * Codec sample rate 0 Hz. Default value used for
- * codec sample rate.
- */
- public static final int SAMPLE_RATE_NONE = 0;
-
- /**
- * Codec sample rate 44100 Hz.
- */
- public static final int SAMPLE_RATE_44100 = 0x1 << 0;
-
- /**
- * Codec sample rate 48000 Hz.
- */
- public static final int SAMPLE_RATE_48000 = 0x1 << 1;
-
- /**
- * Codec sample rate 88200 Hz.
- */
- public static final int SAMPLE_RATE_88200 = 0x1 << 2;
-
- /**
- * Codec sample rate 96000 Hz.
- */
- public static final int SAMPLE_RATE_96000 = 0x1 << 3;
-
- /**
- * Codec sample rate 176400 Hz.
- */
- public static final int SAMPLE_RATE_176400 = 0x1 << 4;
-
- /**
- * Codec sample rate 192000 Hz.
- */
- public static final int SAMPLE_RATE_192000 = 0x1 << 5;
-
- /** @hide */
- @IntDef(prefix = "BITS_PER_SAMPLE_", value = {
- BITS_PER_SAMPLE_NONE,
- BITS_PER_SAMPLE_16,
- BITS_PER_SAMPLE_24,
- BITS_PER_SAMPLE_32
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface BitsPerSample {}
-
- /**
- * Codec bits per sample 0. Default value of the codec
- * bits per sample.
- */
- public static final int BITS_PER_SAMPLE_NONE = 0;
-
- /**
- * Codec bits per sample 16.
- */
- public static final int BITS_PER_SAMPLE_16 = 0x1 << 0;
-
- /**
- * Codec bits per sample 24.
- */
- public static final int BITS_PER_SAMPLE_24 = 0x1 << 1;
-
- /**
- * Codec bits per sample 32.
- */
- public static final int BITS_PER_SAMPLE_32 = 0x1 << 2;
-
- /** @hide */
- @IntDef(prefix = "CHANNEL_MODE_", value = {
- CHANNEL_MODE_NONE,
- CHANNEL_MODE_MONO,
- CHANNEL_MODE_STEREO
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ChannelMode {}
-
- /**
- * Codec channel mode NONE. Default value of the
- * codec channel mode.
- */
- public static final int CHANNEL_MODE_NONE = 0;
-
- /**
- * Codec channel mode MONO.
- */
- public static final int CHANNEL_MODE_MONO = 0x1 << 0;
-
- /**
- * Codec channel mode STEREO.
- */
- public static final int CHANNEL_MODE_STEREO = 0x1 << 1;
-
- private final @SourceCodecType int mCodecType;
- private @CodecPriority int mCodecPriority;
- private final @SampleRate int mSampleRate;
- private final @BitsPerSample int mBitsPerSample;
- private final @ChannelMode int mChannelMode;
- private final long mCodecSpecific1;
- private final long mCodecSpecific2;
- private final long mCodecSpecific3;
- private final long mCodecSpecific4;
-
- /**
- * Creates a new BluetoothCodecConfig.
- *
- * @param codecType the source codec type
- * @param codecPriority the priority of this codec
- * @param sampleRate the codec sample rate
- * @param bitsPerSample the bits per sample of this codec
- * @param channelMode the channel mode of this codec
- * @param codecSpecific1 the specific value 1
- * @param codecSpecific2 the specific value 2
- * @param codecSpecific3 the specific value 3
- * @param codecSpecific4 the specific value 4
- * values to 0.
- * @hide
- */
- @UnsupportedAppUsage
- public BluetoothCodecConfig(@SourceCodecType int codecType, @CodecPriority int codecPriority,
- @SampleRate int sampleRate, @BitsPerSample int bitsPerSample,
- @ChannelMode int channelMode, long codecSpecific1,
- long codecSpecific2, long codecSpecific3,
- long codecSpecific4) {
- mCodecType = codecType;
- mCodecPriority = codecPriority;
- mSampleRate = sampleRate;
- mBitsPerSample = bitsPerSample;
- mChannelMode = channelMode;
- mCodecSpecific1 = codecSpecific1;
- mCodecSpecific2 = codecSpecific2;
- mCodecSpecific3 = codecSpecific3;
- mCodecSpecific4 = codecSpecific4;
- }
-
- /**
- * Creates a new BluetoothCodecConfig.
- * <p> By default, the codec priority will be set
- * to {@link BluetoothCodecConfig#CODEC_PRIORITY_DEFAULT}, the sample rate to
- * {@link BluetoothCodecConfig#SAMPLE_RATE_NONE}, the bits per sample to
- * {@link BluetoothCodecConfig#BITS_PER_SAMPLE_NONE}, the channel mode to
- * {@link BluetoothCodecConfig#CHANNEL_MODE_NONE}, and all the codec specific
- * values to 0.
- *
- * @param codecType the source codec type
- */
- public BluetoothCodecConfig(@SourceCodecType int codecType) {
- this(codecType, BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_NONE,
- BluetoothCodecConfig.BITS_PER_SAMPLE_NONE,
- BluetoothCodecConfig.CHANNEL_MODE_NONE, 0, 0, 0, 0);
- }
-
- private BluetoothCodecConfig(Parcel in) {
- mCodecType = in.readInt();
- mCodecPriority = in.readInt();
- mSampleRate = in.readInt();
- mBitsPerSample = in.readInt();
- mChannelMode = in.readInt();
- mCodecSpecific1 = in.readLong();
- mCodecSpecific2 = in.readLong();
- mCodecSpecific3 = in.readLong();
- mCodecSpecific4 = in.readLong();
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof BluetoothCodecConfig) {
- BluetoothCodecConfig other = (BluetoothCodecConfig) o;
- return (other.mCodecType == mCodecType
- && other.mCodecPriority == mCodecPriority
- && other.mSampleRate == mSampleRate
- && other.mBitsPerSample == mBitsPerSample
- && other.mChannelMode == mChannelMode
- && other.mCodecSpecific1 == mCodecSpecific1
- && other.mCodecSpecific2 == mCodecSpecific2
- && other.mCodecSpecific3 == mCodecSpecific3
- && other.mCodecSpecific4 == mCodecSpecific4);
- }
- return false;
- }
-
- /**
- * Returns a hash representation of this BluetoothCodecConfig
- * based on all the config values.
- */
- @Override
- public int hashCode() {
- return Objects.hash(mCodecType, mCodecPriority, mSampleRate,
- mBitsPerSample, mChannelMode, mCodecSpecific1,
- mCodecSpecific2, mCodecSpecific3, mCodecSpecific4);
- }
-
- /**
- * Adds capability string to an existing string.
- *
- * @param prevStr the previous string with the capabilities. Can be a {@code null} pointer
- * @param capStr the capability string to append to prevStr argument
- * @return the result string in the form "prevStr|capStr"
- */
- private static String appendCapabilityToString(@Nullable String prevStr,
- @NonNull String capStr) {
- if (prevStr == null) {
- return capStr;
- }
- return prevStr + "|" + capStr;
- }
-
- /**
- * Returns a {@link String} that describes each BluetoothCodecConfig parameter
- * current value.
- */
- @Override
- public String toString() {
- String sampleRateStr = null;
- if (mSampleRate == SAMPLE_RATE_NONE) {
- sampleRateStr = appendCapabilityToString(sampleRateStr, "NONE");
- }
- if ((mSampleRate & SAMPLE_RATE_44100) != 0) {
- sampleRateStr = appendCapabilityToString(sampleRateStr, "44100");
- }
- if ((mSampleRate & SAMPLE_RATE_48000) != 0) {
- sampleRateStr = appendCapabilityToString(sampleRateStr, "48000");
- }
- if ((mSampleRate & SAMPLE_RATE_88200) != 0) {
- sampleRateStr = appendCapabilityToString(sampleRateStr, "88200");
- }
- if ((mSampleRate & SAMPLE_RATE_96000) != 0) {
- sampleRateStr = appendCapabilityToString(sampleRateStr, "96000");
- }
- if ((mSampleRate & SAMPLE_RATE_176400) != 0) {
- sampleRateStr = appendCapabilityToString(sampleRateStr, "176400");
- }
- if ((mSampleRate & SAMPLE_RATE_192000) != 0) {
- sampleRateStr = appendCapabilityToString(sampleRateStr, "192000");
- }
-
- String bitsPerSampleStr = null;
- if (mBitsPerSample == BITS_PER_SAMPLE_NONE) {
- bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "NONE");
- }
- if ((mBitsPerSample & BITS_PER_SAMPLE_16) != 0) {
- bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "16");
- }
- if ((mBitsPerSample & BITS_PER_SAMPLE_24) != 0) {
- bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "24");
- }
- if ((mBitsPerSample & BITS_PER_SAMPLE_32) != 0) {
- bitsPerSampleStr = appendCapabilityToString(bitsPerSampleStr, "32");
- }
-
- String channelModeStr = null;
- if (mChannelMode == CHANNEL_MODE_NONE) {
- channelModeStr = appendCapabilityToString(channelModeStr, "NONE");
- }
- if ((mChannelMode & CHANNEL_MODE_MONO) != 0) {
- channelModeStr = appendCapabilityToString(channelModeStr, "MONO");
- }
- if ((mChannelMode & CHANNEL_MODE_STEREO) != 0) {
- channelModeStr = appendCapabilityToString(channelModeStr, "STEREO");
- }
-
- return "{codecName:" + getCodecName()
- + ",mCodecType:" + mCodecType
- + ",mCodecPriority:" + mCodecPriority
- + ",mSampleRate:" + String.format("0x%x", mSampleRate)
- + "(" + sampleRateStr + ")"
- + ",mBitsPerSample:" + String.format("0x%x", mBitsPerSample)
- + "(" + bitsPerSampleStr + ")"
- + ",mChannelMode:" + String.format("0x%x", mChannelMode)
- + "(" + channelModeStr + ")"
- + ",mCodecSpecific1:" + mCodecSpecific1
- + ",mCodecSpecific2:" + mCodecSpecific2
- + ",mCodecSpecific3:" + mCodecSpecific3
- + ",mCodecSpecific4:" + mCodecSpecific4 + "}";
- }
-
- /**
- * @return 0
- * @hide
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecConfig> CREATOR =
- new Parcelable.Creator<BluetoothCodecConfig>() {
- public BluetoothCodecConfig createFromParcel(Parcel in) {
- return new BluetoothCodecConfig(in);
- }
-
- public BluetoothCodecConfig[] newArray(int size) {
- return new BluetoothCodecConfig[size];
- }
- };
-
- /**
- * Flattens the object to a parcel
- *
- * @param out The Parcel in which the object should be written
- * @param flags Additional flags about how the object should be written
- *
- * @hide
- */
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mCodecType);
- out.writeInt(mCodecPriority);
- out.writeInt(mSampleRate);
- out.writeInt(mBitsPerSample);
- out.writeInt(mChannelMode);
- out.writeLong(mCodecSpecific1);
- out.writeLong(mCodecSpecific2);
- out.writeLong(mCodecSpecific3);
- out.writeLong(mCodecSpecific4);
- }
-
- /**
- * Returns the codec name converted to {@link String}.
- * @hide
- */
- public @NonNull String getCodecName() {
- switch (mCodecType) {
- case SOURCE_CODEC_TYPE_SBC:
- return "SBC";
- case SOURCE_CODEC_TYPE_AAC:
- return "AAC";
- case SOURCE_CODEC_TYPE_APTX:
- return "aptX";
- case SOURCE_CODEC_TYPE_APTX_HD:
- return "aptX HD";
- case SOURCE_CODEC_TYPE_LDAC:
- return "LDAC";
- case SOURCE_CODEC_TYPE_INVALID:
- return "INVALID CODEC";
- default:
- break;
- }
- return "UNKNOWN CODEC(" + mCodecType + ")";
- }
-
- /**
- * Returns the source codec type of this config.
- */
- public @SourceCodecType int getCodecType() {
- return mCodecType;
- }
-
- /**
- * Returns the valid codec types count.
- */
- public static int getMaxCodecType() {
- return SOURCE_CODEC_TYPE_MAX;
- }
-
- /**
- * Checks whether the codec is mandatory.
- * <p> The actual mandatory codec type for Android Bluetooth audio is SBC.
- * See {@link #SOURCE_CODEC_TYPE_SBC}.
- *
- * @return {@code true} if the codec is mandatory, {@code false} otherwise
- * @hide
- */
- public boolean isMandatoryCodec() {
- return mCodecType == SOURCE_CODEC_TYPE_SBC;
- }
-
- /**
- * Returns the codec selection priority.
- * <p>The codec selection priority is relative to other codecs: larger value
- * means higher priority.
- */
- public @CodecPriority int getCodecPriority() {
- return mCodecPriority;
- }
-
- /**
- * Sets the codec selection priority.
- * <p>The codec selection priority is relative to other codecs: larger value
- * means higher priority.
- *
- * @param codecPriority the priority this codec should have
- * @hide
- */
- public void setCodecPriority(@CodecPriority int codecPriority) {
- mCodecPriority = codecPriority;
- }
-
- /**
- * Returns the codec sample rate. The value can be a bitmask with all
- * supported sample rates.
- */
- public @SampleRate int getSampleRate() {
- return mSampleRate;
- }
-
- /**
- * Returns the codec bits per sample. The value can be a bitmask with all
- * bits per sample supported.
- */
- public @BitsPerSample int getBitsPerSample() {
- return mBitsPerSample;
- }
-
- /**
- * Returns the codec channel mode. The value can be a bitmask with all
- * supported channel modes.
- */
- public @ChannelMode int getChannelMode() {
- return mChannelMode;
- }
-
- /**
- * Returns the codec specific value1.
- */
- public long getCodecSpecific1() {
- return mCodecSpecific1;
- }
-
- /**
- * Returns the codec specific value2.
- */
- public long getCodecSpecific2() {
- return mCodecSpecific2;
- }
-
- /**
- * Returns the codec specific value3.
- */
- public long getCodecSpecific3() {
- return mCodecSpecific3;
- }
-
- /**
- * Returns the codec specific value4.
- */
- public long getCodecSpecific4() {
- return mCodecSpecific4;
- }
-
- /**
- * Checks whether a value set presented by a bitmask has zero or single bit
- *
- * @param valueSet the value set presented by a bitmask
- * @return {@code true} if the valueSet contains zero or single bit, {@code false} otherwise
- * @hide
- */
- private static boolean hasSingleBit(int valueSet) {
- return (valueSet == 0 || (valueSet & (valueSet - 1)) == 0);
- }
-
- /**
- * Returns whether the object contains none or single sample rate.
- * @hide
- */
- public boolean hasSingleSampleRate() {
- return hasSingleBit(mSampleRate);
- }
-
- /**
- * Returns whether the object contains none or single bits per sample.
- * @hide
- */
- public boolean hasSingleBitsPerSample() {
- return hasSingleBit(mBitsPerSample);
- }
-
- /**
- * Returns whether the object contains none or single channel mode.
- * @hide
- */
- public boolean hasSingleChannelMode() {
- return hasSingleBit(mChannelMode);
- }
-
- /**
- * Checks whether the audio feeding parameters are the same.
- *
- * @param other the codec config to compare against
- * @return {@code true} if the audio feeding parameters are same, {@code false} otherwise
- * @hide
- */
- public boolean sameAudioFeedingParameters(BluetoothCodecConfig other) {
- return (other != null && other.mSampleRate == mSampleRate
- && other.mBitsPerSample == mBitsPerSample
- && other.mChannelMode == mChannelMode);
- }
-
- /**
- * Checks whether another codec config has the similar feeding parameters.
- * Any parameters with NONE value will be considered to be a wildcard matching.
- *
- * @param other the codec config to compare against
- * @return {@code true} if the audio feeding parameters are similar, {@code false} otherwise
- * @hide
- */
- public boolean similarCodecFeedingParameters(BluetoothCodecConfig other) {
- if (other == null || mCodecType != other.mCodecType) {
- return false;
- }
- int sampleRate = other.mSampleRate;
- if (mSampleRate == SAMPLE_RATE_NONE
- || sampleRate == SAMPLE_RATE_NONE) {
- sampleRate = mSampleRate;
- }
- int bitsPerSample = other.mBitsPerSample;
- if (mBitsPerSample == BITS_PER_SAMPLE_NONE
- || bitsPerSample == BITS_PER_SAMPLE_NONE) {
- bitsPerSample = mBitsPerSample;
- }
- int channelMode = other.mChannelMode;
- if (mChannelMode == CHANNEL_MODE_NONE
- || channelMode == CHANNEL_MODE_NONE) {
- channelMode = mChannelMode;
- }
- return sameAudioFeedingParameters(new BluetoothCodecConfig(
- mCodecType, /* priority */ 0, sampleRate, bitsPerSample, channelMode,
- /* specific1 */ 0, /* specific2 */ 0, /* specific3 */ 0,
- /* specific4 */ 0));
- }
-
- /**
- * Checks whether the codec specific parameters are the same.
- * <p> Currently, only AAC VBR and LDAC Playback Quality on CodecSpecific1
- * are compared.
- *
- * @param other the codec config to compare against
- * @return {@code true} if the codec specific parameters are the same, {@code false} otherwise
- * @hide
- */
- public boolean sameCodecSpecificParameters(BluetoothCodecConfig other) {
- if (other == null && mCodecType != other.mCodecType) {
- return false;
- }
- switch (mCodecType) {
- case SOURCE_CODEC_TYPE_AAC:
- case SOURCE_CODEC_TYPE_LDAC:
- if (mCodecSpecific1 != other.mCodecSpecific1) {
- return false;
- }
- default:
- return true;
- }
- }
-
- /**
- * Builder for {@link BluetoothCodecConfig}.
- * <p> By default, the codec type will be set to
- * {@link BluetoothCodecConfig#SOURCE_CODEC_TYPE_INVALID}, the codec priority
- * to {@link BluetoothCodecConfig#CODEC_PRIORITY_DEFAULT}, the sample rate to
- * {@link BluetoothCodecConfig#SAMPLE_RATE_NONE}, the bits per sample to
- * {@link BluetoothCodecConfig#BITS_PER_SAMPLE_NONE}, the channel mode to
- * {@link BluetoothCodecConfig#CHANNEL_MODE_NONE}, and all the codec specific
- * values to 0.
- */
- public static final class Builder {
- private int mCodecType = BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID;
- private int mCodecPriority = BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT;
- private int mSampleRate = BluetoothCodecConfig.SAMPLE_RATE_NONE;
- private int mBitsPerSample = BluetoothCodecConfig.BITS_PER_SAMPLE_NONE;
- private int mChannelMode = BluetoothCodecConfig.CHANNEL_MODE_NONE;
- private long mCodecSpecific1 = 0;
- private long mCodecSpecific2 = 0;
- private long mCodecSpecific3 = 0;
- private long mCodecSpecific4 = 0;
-
- /**
- * Set codec type for Bluetooth codec config.
- *
- * @param codecType of this codec
- * @return the same Builder instance
- */
- public @NonNull Builder setCodecType(@SourceCodecType int codecType) {
- mCodecType = codecType;
- return this;
- }
-
- /**
- * Set codec priority for Bluetooth codec config.
- *
- * @param codecPriority of this codec
- * @return the same Builder instance
- */
- public @NonNull Builder setCodecPriority(@CodecPriority int codecPriority) {
- mCodecPriority = codecPriority;
- return this;
- }
-
- /**
- * Set sample rate for Bluetooth codec config.
- *
- * @param sampleRate of this codec
- * @return the same Builder instance
- */
- public @NonNull Builder setSampleRate(@SampleRate int sampleRate) {
- mSampleRate = sampleRate;
- return this;
- }
-
- /**
- * Set the bits per sample for Bluetooth codec config.
- *
- * @param bitsPerSample of this codec
- * @return the same Builder instance
- */
- public @NonNull Builder setBitsPerSample(@BitsPerSample int bitsPerSample) {
- mBitsPerSample = bitsPerSample;
- return this;
- }
-
- /**
- * Set the channel mode for Bluetooth codec config.
- *
- * @param channelMode of this codec
- * @return the same Builder instance
- */
- public @NonNull Builder setChannelMode(@ChannelMode int channelMode) {
- mChannelMode = channelMode;
- return this;
- }
-
- /**
- * Set the first codec specific values for Bluetooth codec config.
- *
- * @param codecSpecific1 codec specific value or 0 if default
- * @return the same Builder instance
- */
- public @NonNull Builder setCodecSpecific1(long codecSpecific1) {
- mCodecSpecific1 = codecSpecific1;
- return this;
- }
-
- /**
- * Set the second codec specific values for Bluetooth codec config.
- *
- * @param codecSpecific2 codec specific value or 0 if default
- * @return the same Builder instance
- */
- public @NonNull Builder setCodecSpecific2(long codecSpecific2) {
- mCodecSpecific2 = codecSpecific2;
- return this;
- }
-
- /**
- * Set the third codec specific values for Bluetooth codec config.
- *
- * @param codecSpecific3 codec specific value or 0 if default
- * @return the same Builder instance
- */
- public @NonNull Builder setCodecSpecific3(long codecSpecific3) {
- mCodecSpecific3 = codecSpecific3;
- return this;
- }
-
- /**
- * Set the fourth codec specific values for Bluetooth codec config.
- *
- * @param codecSpecific4 codec specific value or 0 if default
- * @return the same Builder instance
- */
- public @NonNull Builder setCodecSpecific4(long codecSpecific4) {
- mCodecSpecific4 = codecSpecific4;
- return this;
- }
-
- /**
- * Build {@link BluetoothCodecConfig}.
- * @return new BluetoothCodecConfig built
- */
- public @NonNull BluetoothCodecConfig build() {
- return new BluetoothCodecConfig(mCodecType, mCodecPriority,
- mSampleRate, mBitsPerSample,
- mChannelMode, mCodecSpecific1,
- mCodecSpecific2, mCodecSpecific3,
- mCodecSpecific4);
- }
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothCodecStatus.java b/core/java/android/bluetooth/BluetoothCodecStatus.java
deleted file mode 100644
index 02606fe..0000000
--- a/core/java/android/bluetooth/BluetoothCodecStatus.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Represents the codec status (configuration and capability) for a Bluetooth
- * A2DP source device.
- *
- * {@see BluetoothA2dp}
- */
-public final class BluetoothCodecStatus implements Parcelable {
- /**
- * Extra for the codec configuration intents of the individual profiles.
- *
- * This extra represents the current codec status of the A2DP
- * profile.
- */
- public static final String EXTRA_CODEC_STATUS =
- "android.bluetooth.extra.CODEC_STATUS";
-
- private final @Nullable BluetoothCodecConfig mCodecConfig;
- private final @Nullable List<BluetoothCodecConfig> mCodecsLocalCapabilities;
- private final @Nullable List<BluetoothCodecConfig> mCodecsSelectableCapabilities;
-
- public BluetoothCodecStatus(@Nullable BluetoothCodecConfig codecConfig,
- @Nullable List<BluetoothCodecConfig> codecsLocalCapabilities,
- @Nullable List<BluetoothCodecConfig> codecsSelectableCapabilities) {
- mCodecConfig = codecConfig;
- mCodecsLocalCapabilities = codecsLocalCapabilities;
- mCodecsSelectableCapabilities = codecsSelectableCapabilities;
- }
-
- private BluetoothCodecStatus(Parcel in) {
- mCodecConfig = in.readTypedObject(BluetoothCodecConfig.CREATOR);
- mCodecsLocalCapabilities = in.createTypedArrayList(BluetoothCodecConfig.CREATOR);
- mCodecsSelectableCapabilities = in.createTypedArrayList(BluetoothCodecConfig.CREATOR);
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof BluetoothCodecStatus) {
- BluetoothCodecStatus other = (BluetoothCodecStatus) o;
- return (Objects.equals(other.mCodecConfig, mCodecConfig)
- && sameCapabilities(other.mCodecsLocalCapabilities, mCodecsLocalCapabilities)
- && sameCapabilities(other.mCodecsSelectableCapabilities,
- mCodecsSelectableCapabilities));
- }
- return false;
- }
-
- /**
- * Checks whether two lists of capabilities contain same capabilities.
- * The order of the capabilities in each list is ignored.
- *
- * @param c1 the first list of capabilities to compare
- * @param c2 the second list of capabilities to compare
- * @return {@code true} if both lists contain same capabilities
- */
- private static boolean sameCapabilities(@Nullable List<BluetoothCodecConfig> c1,
- @Nullable List<BluetoothCodecConfig> c2) {
- if (c1 == null) {
- return (c2 == null);
- }
- if (c2 == null) {
- return false;
- }
- if (c1.size() != c2.size()) {
- return false;
- }
- return c1.containsAll(c2);
- }
-
- /**
- * Checks whether the codec config matches the selectable capabilities.
- * Any parameters of the codec config with NONE value will be considered a wildcard matching.
- *
- * @param codecConfig the codec config to compare against
- * @return {@code true} if the codec config matches, {@code false} otherwise
- */
- public boolean isCodecConfigSelectable(@Nullable BluetoothCodecConfig codecConfig) {
- if (codecConfig == null || !codecConfig.hasSingleSampleRate()
- || !codecConfig.hasSingleBitsPerSample() || !codecConfig.hasSingleChannelMode()) {
- return false;
- }
- for (BluetoothCodecConfig selectableConfig : mCodecsSelectableCapabilities) {
- if (codecConfig.getCodecType() != selectableConfig.getCodecType()) {
- continue;
- }
- int sampleRate = codecConfig.getSampleRate();
- if ((sampleRate & selectableConfig.getSampleRate()) == 0
- && sampleRate != BluetoothCodecConfig.SAMPLE_RATE_NONE) {
- continue;
- }
- int bitsPerSample = codecConfig.getBitsPerSample();
- if ((bitsPerSample & selectableConfig.getBitsPerSample()) == 0
- && bitsPerSample != BluetoothCodecConfig.BITS_PER_SAMPLE_NONE) {
- continue;
- }
- int channelMode = codecConfig.getChannelMode();
- if ((channelMode & selectableConfig.getChannelMode()) == 0
- && channelMode != BluetoothCodecConfig.CHANNEL_MODE_NONE) {
- continue;
- }
- return true;
- }
- return false;
- }
-
- /**
- * Returns a hash based on the codec config and local capabilities.
- */
- @Override
- public int hashCode() {
- return Objects.hash(mCodecConfig, mCodecsLocalCapabilities,
- mCodecsLocalCapabilities);
- }
-
- /**
- * Returns a {@link String} that describes each BluetoothCodecStatus parameter
- * current value.
- */
- @Override
- public String toString() {
- return "{mCodecConfig:" + mCodecConfig
- + ",mCodecsLocalCapabilities:" + mCodecsLocalCapabilities
- + ",mCodecsSelectableCapabilities:" + mCodecsSelectableCapabilities
- + "}";
- }
-
- /**
- * @return 0
- * @hide
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothCodecStatus> CREATOR =
- new Parcelable.Creator<BluetoothCodecStatus>() {
- public BluetoothCodecStatus createFromParcel(Parcel in) {
- return new BluetoothCodecStatus(in);
- }
-
- public BluetoothCodecStatus[] newArray(int size) {
- return new BluetoothCodecStatus[size];
- }
- };
-
- /**
- * Flattens the object to a parcel.
- *
- * @param out The Parcel in which the object should be written
- * @param flags Additional flags about how the object should be written
- */
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeTypedObject(mCodecConfig, 0);
- out.writeTypedList(mCodecsLocalCapabilities);
- out.writeTypedList(mCodecsSelectableCapabilities);
- }
-
- /**
- * Returns the current codec configuration.
- */
- public @Nullable BluetoothCodecConfig getCodecConfig() {
- return mCodecConfig;
- }
-
- /**
- * Returns the codecs local capabilities.
- */
- public @NonNull List<BluetoothCodecConfig> getCodecsLocalCapabilities() {
- return (mCodecsLocalCapabilities == null)
- ? Collections.emptyList() : mCodecsLocalCapabilities;
- }
-
- /**
- * Returns the codecs selectable capabilities.
- */
- public @NonNull List<BluetoothCodecConfig> getCodecsSelectableCapabilities() {
- return (mCodecsSelectableCapabilities == null)
- ? Collections.emptyList() : mCodecsSelectableCapabilities;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java b/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java
deleted file mode 100644
index ba57ec4..0000000
--- a/core/java/android/bluetooth/BluetoothCsipSetCoordinator.java
+++ /dev/null
@@ -1,555 +0,0 @@
-/*
- * Copyright 2021 HIMSA II K/S - www.himsa.com.
- * Represented by EHIMA - www.ehima.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.CallbackExecutor;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.ParcelUuid;
-import android.os.RemoteException;
-import android.util.CloseGuard;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the public APIs to control the Bluetooth CSIP set coordinator.
- *
- * <p>BluetoothCsipSetCoordinator is a proxy object for controlling the Bluetooth VC
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothCsipSetCoordinator proxy object.
- *
- */
-public final class BluetoothCsipSetCoordinator implements BluetoothProfile, AutoCloseable {
- private static final String TAG = "BluetoothCsipSetCoordinator";
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
-
- private CloseGuard mCloseGuard;
-
- /**
- * @hide
- */
- @SystemApi
- public interface ClientLockCallback {
- /**
- * @hide
- */
- @SystemApi void onGroupLockSet(int groupId, int opStatus, boolean isLocked);
- }
-
- private static class BluetoothCsipSetCoordinatorLockCallbackDelegate
- extends IBluetoothCsipSetCoordinatorLockCallback.Stub {
- private final ClientLockCallback mCallback;
- private final Executor mExecutor;
-
- BluetoothCsipSetCoordinatorLockCallbackDelegate(
- Executor executor, ClientLockCallback callback) {
- mExecutor = executor;
- mCallback = callback;
- }
-
- @Override
- public void onGroupLockSet(int groupId, int opStatus, boolean isLocked) {
- mExecutor.execute(() -> mCallback.onGroupLockSet(groupId, opStatus, isLocked));
- }
- };
-
- /**
- * Intent used to broadcast the change in connection state of the CSIS
- * Client.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CSIS_CONNECTION_STATE_CHANGED =
- "android.bluetooth.action.CSIS_CONNECTION_STATE_CHANGED";
-
- /**
- * Intent used to expose broadcast receiving device.
- *
- * <p>This intent will have 2 extras:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote Broadcast receiver device. </li>
- * <li> {@link #EXTRA_CSIS_GROUP_ID} - Group identifier. </li>
- * <li> {@link #EXTRA_CSIS_GROUP_SIZE} - Group size. </li>
- * <li> {@link #EXTRA_CSIS_GROUP_TYPE_UUID} - Group type UUID. </li>
- * </ul>
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CSIS_DEVICE_AVAILABLE =
- "android.bluetooth.action.CSIS_DEVICE_AVAILABLE";
-
- /**
- * Used as an extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
- * Contains the group id.
- *
- * @hide
- */
- public static final String EXTRA_CSIS_GROUP_ID = "android.bluetooth.extra.CSIS_GROUP_ID";
-
- /**
- * Group size as int extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
- *
- * @hide
- */
- public static final String EXTRA_CSIS_GROUP_SIZE = "android.bluetooth.extra.CSIS_GROUP_SIZE";
-
- /**
- * Group type uuid extra field in {@link #ACTION_CSIS_DEVICE_AVAILABLE} intent.
- *
- * @hide
- */
- public static final String EXTRA_CSIS_GROUP_TYPE_UUID =
- "android.bluetooth.extra.CSIS_GROUP_TYPE_UUID";
-
- /**
- * Intent used to broadcast information about identified set member
- * ready to connect.
- *
- * <p>This intent will have one extra:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
- * be null if no device is active. </li>
- * <li> {@link #EXTRA_CSIS_GROUP_ID} - Group identifier. </li>
- * </ul>
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CSIS_SET_MEMBER_AVAILABLE =
- "android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE";
-
- /**
- * This represents an invalid group ID.
- *
- * @hide
- */
- public static final int GROUP_ID_INVALID = IBluetoothCsipSetCoordinator.CSIS_GROUP_ID_INVALID;
-
- /**
- * Indicating that group was locked with success.
- *
- * @hide
- */
- public static final int GROUP_LOCK_SUCCESS = 0;
-
- /**
- * Indicating that group locked failed due to invalid group ID.
- *
- * @hide
- */
- public static final int GROUP_LOCK_FAILED_INVALID_GROUP = 1;
-
- /**
- * Indicating that group locked failed due to empty group.
- *
- * @hide
- */
- public static final int GROUP_LOCK_FAILED_GROUP_EMPTY = 2;
-
- /**
- * Indicating that group locked failed due to group members being disconnected.
- *
- * @hide
- */
- public static final int GROUP_LOCK_FAILED_GROUP_NOT_CONNECTED = 3;
-
- /**
- * Indicating that group locked failed due to group member being already locked.
- *
- * @hide
- */
- public static final int GROUP_LOCK_FAILED_LOCKED_BY_OTHER = 4;
-
- /**
- * Indicating that group locked failed due to other reason.
- *
- * @hide
- */
- public static final int GROUP_LOCK_FAILED_OTHER_REASON = 5;
-
- /**
- * Indicating that group member in locked state was lost.
- *
- * @hide
- */
- public static final int LOCKED_GROUP_MEMBER_LOST = 6;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothCsipSetCoordinator> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.CSIP_SET_COORDINATOR, TAG,
- IBluetoothCsipSetCoordinator.class.getName()) {
- @Override
- public IBluetoothCsipSetCoordinator getServiceInterface(IBinder service) {
- return IBluetoothCsipSetCoordinator.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothCsipSetCoordinator proxy object for interacting with the local
- * Bluetooth CSIS service.
- */
- /*package*/ BluetoothCsipSetCoordinator(Context context, ServiceListener listener, BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- mCloseGuard = new CloseGuard();
- mCloseGuard.open("close");
- }
-
- /**
- * @hide
- */
- protected void finalize() {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- close();
- }
-
- /**
- * @hide
- */
- public void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothCsipSetCoordinator getService() {
- return mProfileConnector.getService();
- }
-
- /**
- * Lock the set.
- * @param groupId group ID to lock,
- * @param executor callback executor,
- * @param cb callback to report lock and unlock events - stays valid until the app unlocks
- * using the returned lock identifier or the lock timeouts on the remote side,
- * as per CSIS specification,
- * @return unique lock identifier used for unlocking or null if lock has failed.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public
- @Nullable UUID groupLock(int groupId, @Nullable @CallbackExecutor Executor executor,
- @Nullable ClientLockCallback cb) {
- if (VDBG) log("groupLockSet()");
- final IBluetoothCsipSetCoordinator service = getService();
- final UUID defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- IBluetoothCsipSetCoordinatorLockCallback delegate = null;
- if ((executor != null) && (cb != null)) {
- delegate = new BluetoothCsipSetCoordinatorLockCallbackDelegate(executor, cb);
- }
- try {
- final SynchronousResultReceiver<ParcelUuid> recv = new SynchronousResultReceiver();
- service.groupLock(groupId, delegate, mAttributionSource, recv);
- final ParcelUuid ret = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- return ret == null ? defaultValue : ret.getUuid();
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Unlock the set.
- * @param lockUuid unique lock identifier
- * @return true if unlocked, false on error
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean groupUnlock(@NonNull UUID lockUuid) {
- if (VDBG) log("groupLockSet()");
- if (lockUuid == null) {
- return false;
- }
- final IBluetoothCsipSetCoordinator service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.groupUnlock(new ParcelUuid(lockUuid), mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- return true;
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get device's groups.
- * @param device the active device
- * @return Map of groups ids and related UUIDs
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public @NonNull Map getGroupUuidMapByDevice(@Nullable BluetoothDevice device) {
- if (VDBG) log("getGroupUuidMapByDevice()");
- final IBluetoothCsipSetCoordinator service = getService();
- final Map defaultValue = new HashMap<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Map> recv = new SynchronousResultReceiver();
- service.getGroupUuidMapByDevice(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get group id for the given UUID
- * @param uuid
- * @return list of group IDs
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public @NonNull List<Integer> getAllGroupIds(@Nullable ParcelUuid uuid) {
- if (VDBG) log("getAllGroupIds()");
- final IBluetoothCsipSetCoordinator service = getService();
- final List<Integer> defaultValue = new ArrayList<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<Integer>> recv =
- new SynchronousResultReceiver();
- service.getAllGroupIds(uuid, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public @NonNull List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothCsipSetCoordinator service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public
- @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(@NonNull int[] states) {
- if (VDBG) log("getDevicesMatchingStates(states=" + Arrays.toString(states) + ")");
- final IBluetoothCsipSetCoordinator service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public
- @BluetoothProfile.BtProfileState int getConnectionState(@Nullable BluetoothDevice device) {
- if (VDBG) log("getState(" + device + ")");
- final IBluetoothCsipSetCoordinator service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean setConnectionPolicy(
- @Nullable BluetoothDevice device, @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothCsipSetCoordinator service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothCsipSetCoordinator service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private boolean isEnabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_ON;
- }
-
- private static boolean isValidDevice(@Nullable BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
deleted file mode 100644
index 984166d..0000000
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ /dev/null
@@ -1,2831 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi; //import android.app.PropertyInvalidatedCache;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
-import android.bluetooth.annotations.RequiresBluetoothScanPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.companion.AssociationRequest;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.os.Parcelable;
-import android.os.Process;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.UUID;
-
-/**
- * Represents a remote Bluetooth device. A {@link BluetoothDevice} lets you
- * create a connection with the respective device or query information about
- * it, such as the name, address, class, and bonding state.
- *
- * <p>This class is really just a thin wrapper for a Bluetooth hardware
- * address. Objects of this class are immutable. Operations on this class
- * are performed on the remote Bluetooth hardware address, using the
- * {@link BluetoothAdapter} that was used to create this {@link
- * BluetoothDevice}.
- *
- * <p>To get a {@link BluetoothDevice}, use
- * {@link BluetoothAdapter#getRemoteDevice(String)
- * BluetoothAdapter.getRemoteDevice(String)} to create one representing a device
- * of a known MAC address (which you can get through device discovery with
- * {@link BluetoothAdapter}) or get one from the set of bonded devices
- * returned by {@link BluetoothAdapter#getBondedDevices()
- * BluetoothAdapter.getBondedDevices()}. You can then open a
- * {@link BluetoothSocket} for communication with the remote device, using
- * {@link #createRfcommSocketToServiceRecord(UUID)} over Bluetooth BR/EDR or using
- * {@link #createL2capChannel(int)} over Bluetooth LE.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>
- * For more information about using Bluetooth, read the <a href=
- * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
- * guide.
- * </p>
- * </div>
- *
- * {@see BluetoothAdapter}
- * {@see BluetoothSocket}
- */
-public final class BluetoothDevice implements Parcelable, Attributable {
- private static final String TAG = "BluetoothDevice";
- private static final boolean DBG = false;
-
- /**
- * Connection state bitmask as returned by getConnectionState.
- */
- private static final int CONNECTION_STATE_DISCONNECTED = 0;
- private static final int CONNECTION_STATE_CONNECTED = 1;
- private static final int CONNECTION_STATE_ENCRYPTED_BREDR = 2;
- private static final int CONNECTION_STATE_ENCRYPTED_LE = 4;
-
- /**
- * Sentinel error value for this class. Guaranteed to not equal any other
- * integer constant in this class. Provided as a convenience for functions
- * that require a sentinel error value, for example:
- * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
- * BluetoothDevice.ERROR)</code>
- */
- public static final int ERROR = Integer.MIN_VALUE;
-
- /**
- * Broadcast Action: Remote device discovered.
- * <p>Sent when a remote device is found during discovery.
- * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
- * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
- * {@link #EXTRA_RSSI} and/or {@link #EXTRA_IS_COORDINATED_SET_MEMBER} if they are available.
- */
- // TODO: Change API to not broadcast RSSI if not available (incoming connection)
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_FOUND =
- "android.bluetooth.device.action.FOUND";
-
- /**
- * Broadcast Action: Bluetooth class of a remote device has changed.
- * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
- * #EXTRA_CLASS}.
- * {@see BluetoothClass}
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CLASS_CHANGED =
- "android.bluetooth.device.action.CLASS_CHANGED";
-
- /**
- * Broadcast Action: Indicates a low level (ACL) connection has been
- * established with a remote device.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>ACL connections are managed automatically by the Android Bluetooth
- * stack.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_ACL_CONNECTED =
- "android.bluetooth.device.action.ACL_CONNECTED";
-
- /**
- * Broadcast Action: Indicates that a low level (ACL) disconnection has
- * been requested for a remote device, and it will soon be disconnected.
- * <p>This is useful for graceful disconnection. Applications should use
- * this intent as a hint to immediately terminate higher level connections
- * (RFCOMM, L2CAP, or profile connections) to the remote device.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_ACL_DISCONNECT_REQUESTED =
- "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
-
- /**
- * Broadcast Action: Indicates a low level (ACL) disconnection from a
- * remote device.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- * <p>ACL connections are managed automatically by the Android Bluetooth
- * stack.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_ACL_DISCONNECTED =
- "android.bluetooth.device.action.ACL_DISCONNECTED";
-
- /**
- * Broadcast Action: Indicates the friendly name of a remote device has
- * been retrieved for the first time, or changed since the last retrieval.
- * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
- * #EXTRA_NAME}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_NAME_CHANGED =
- "android.bluetooth.device.action.NAME_CHANGED";
-
- /**
- * Broadcast Action: Indicates the alias of a remote device has been
- * changed.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- */
- @SuppressLint("ActionValue")
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_ALIAS_CHANGED =
- "android.bluetooth.device.action.ALIAS_CHANGED";
-
- /**
- * Broadcast Action: Indicates a change in the bond state of a remote
- * device. For example, if a device is bonded (paired).
- * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
- * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
- */
- // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
- // contain a hidden extra field EXTRA_REASON with the result code.
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_BOND_STATE_CHANGED =
- "android.bluetooth.device.action.BOND_STATE_CHANGED";
-
- /**
- * Broadcast Action: Indicates the battery level of a remote device has
- * been retrieved for the first time, or changed since the last retrieval
- * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
- * #EXTRA_BATTERY_LEVEL}.
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_BATTERY_LEVEL_CHANGED =
- "android.bluetooth.device.action.BATTERY_LEVEL_CHANGED";
-
- /**
- * Used as an Integer extra field in {@link #ACTION_BATTERY_LEVEL_CHANGED}
- * intent. It contains the most recently retrieved battery level information
- * ranging from 0% to 100% for a remote device, {@link #BATTERY_LEVEL_UNKNOWN}
- * when the valid is unknown or there is an error
- *
- * @hide
- */
- public static final String EXTRA_BATTERY_LEVEL =
- "android.bluetooth.device.extra.BATTERY_LEVEL";
-
- /**
- * Used as the unknown value for {@link #EXTRA_BATTERY_LEVEL} and {@link #getBatteryLevel()}
- *
- * @hide
- */
- public static final int BATTERY_LEVEL_UNKNOWN = -1;
-
- /**
- * Used as an error value for {@link #getBatteryLevel()} to represent bluetooth is off
- *
- * @hide
- */
- public static final int BATTERY_LEVEL_BLUETOOTH_OFF = -100;
-
- /**
- * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
- * broadcast by this class. It contains the {@link BluetoothDevice} that
- * the intent applies to.
- */
- public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
-
- /**
- * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
- * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
- */
- public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
-
- /**
- * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
- * Contains the RSSI value of the remote device as reported by the
- * Bluetooth hardware.
- */
- public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
-
- /**
- * Used as an bool extra field in {@link #ACTION_FOUND} intents.
- * It contains the information if device is discovered as member of a coordinated set or not.
- * Pairing with device that belongs to a set would trigger pairing with the rest of set members.
- * See Bluetooth CSIP specification for more details.
- */
- public static final String EXTRA_IS_COORDINATED_SET_MEMBER =
- "android.bluetooth.extra.IS_COORDINATED_SET_MEMBER";
-
- /**
- * Used as a Parcelable {@link BluetoothClass} extra field in {@link
- * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
- */
- public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
-
- /**
- * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
- * Contains the bond state of the remote device.
- * <p>Possible values are:
- * {@link #BOND_NONE},
- * {@link #BOND_BONDING},
- * {@link #BOND_BONDED}.
- */
- public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
- /**
- * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
- * Contains the previous bond state of the remote device.
- * <p>Possible values are:
- * {@link #BOND_NONE},
- * {@link #BOND_BONDING},
- * {@link #BOND_BONDED}.
- */
- public static final String EXTRA_PREVIOUS_BOND_STATE =
- "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
- /**
- * Indicates the remote device is not bonded (paired).
- * <p>There is no shared link key with the remote device, so communication
- * (if it is allowed at all) will be unauthenticated and unencrypted.
- */
- public static final int BOND_NONE = 10;
- /**
- * Indicates bonding (pairing) is in progress with the remote device.
- */
- public static final int BOND_BONDING = 11;
- /**
- * Indicates the remote device is bonded (paired).
- * <p>A shared link keys exists locally for the remote device, so
- * communication can be authenticated and encrypted.
- * <p><i>Being bonded (paired) with a remote device does not necessarily
- * mean the device is currently connected. It just means that the pending
- * procedure was completed at some earlier time, and the link key is still
- * stored locally, ready to use on the next connection.
- * </i>
- */
- public static final int BOND_BONDED = 12;
-
- /**
- * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
- * intents for unbond reason.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
-
- /**
- * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
- * intents to indicate pairing method used. Possible values are:
- * {@link #PAIRING_VARIANT_PIN},
- * {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION},
- */
- public static final String EXTRA_PAIRING_VARIANT =
- "android.bluetooth.device.extra.PAIRING_VARIANT";
-
- /**
- * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
- * intents as the value of passkey.
- */
- public static final String EXTRA_PAIRING_KEY = "android.bluetooth.device.extra.PAIRING_KEY";
-
- /**
- * Used as an int extra field in {@link #ACTION_PAIRING_REQUEST}
- * intents as the value of passkey.
- * @hide
- */
- public static final String EXTRA_PAIRING_INITIATOR =
- "android.bluetooth.device.extra.PAIRING_INITIATOR";
-
- /**
- * Bluetooth pairing initiator, Foreground App
- * @hide
- */
- public static final int EXTRA_PAIRING_INITIATOR_FOREGROUND = 1;
-
- /**
- * Bluetooth pairing initiator, Background
- * @hide
- */
- public static final int EXTRA_PAIRING_INITIATOR_BACKGROUND = 2;
-
- /**
- * Bluetooth device type, Unknown
- */
- public static final int DEVICE_TYPE_UNKNOWN = 0;
-
- /**
- * Bluetooth device type, Classic - BR/EDR devices
- */
- public static final int DEVICE_TYPE_CLASSIC = 1;
-
- /**
- * Bluetooth device type, Low Energy - LE-only
- */
- public static final int DEVICE_TYPE_LE = 2;
-
- /**
- * Bluetooth device type, Dual Mode - BR/EDR/LE
- */
- public static final int DEVICE_TYPE_DUAL = 3;
-
-
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String ACTION_SDP_RECORD =
- "android.bluetooth.device.action.SDP_RECORD";
-
- /** @hide */
- @IntDef(prefix = "METADATA_", value = {
- METADATA_MANUFACTURER_NAME,
- METADATA_MODEL_NAME,
- METADATA_SOFTWARE_VERSION,
- METADATA_HARDWARE_VERSION,
- METADATA_COMPANION_APP,
- METADATA_MAIN_ICON,
- METADATA_IS_UNTETHERED_HEADSET,
- METADATA_UNTETHERED_LEFT_ICON,
- METADATA_UNTETHERED_RIGHT_ICON,
- METADATA_UNTETHERED_CASE_ICON,
- METADATA_UNTETHERED_LEFT_BATTERY,
- METADATA_UNTETHERED_RIGHT_BATTERY,
- METADATA_UNTETHERED_CASE_BATTERY,
- METADATA_UNTETHERED_LEFT_CHARGING,
- METADATA_UNTETHERED_RIGHT_CHARGING,
- METADATA_UNTETHERED_CASE_CHARGING,
- METADATA_ENHANCED_SETTINGS_UI_URI,
- METADATA_DEVICE_TYPE,
- METADATA_MAIN_BATTERY,
- METADATA_MAIN_CHARGING,
- METADATA_MAIN_LOW_BATTERY_THRESHOLD,
- METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD,
- METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD,
- METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD})
- @Retention(RetentionPolicy.SOURCE)
- public @interface MetadataKey{}
-
- /**
- * Maximum length of a metadata entry, this is to avoid exploding Bluetooth
- * disk usage
- * @hide
- */
- @SystemApi
- public static final int METADATA_MAX_LENGTH = 2048;
-
- /**
- * Manufacturer name of this Bluetooth device
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_MANUFACTURER_NAME = 0;
-
- /**
- * Model name of this Bluetooth device
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_MODEL_NAME = 1;
-
- /**
- * Software version of this Bluetooth device
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_SOFTWARE_VERSION = 2;
-
- /**
- * Hardware version of this Bluetooth device
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_HARDWARE_VERSION = 3;
-
- /**
- * Package name of the companion app, if any
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_COMPANION_APP = 4;
-
- /**
- * URI to the main icon shown on the settings UI
- * Data type should be {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_MAIN_ICON = 5;
-
- /**
- * Whether this device is an untethered headset with left, right and case
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_IS_UNTETHERED_HEADSET = 6;
-
- /**
- * URI to icon of the left headset
- * Data type should be {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_LEFT_ICON = 7;
-
- /**
- * URI to icon of the right headset
- * Data type should be {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_RIGHT_ICON = 8;
-
- /**
- * URI to icon of the headset charging case
- * Data type should be {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_CASE_ICON = 9;
-
- /**
- * Battery level of left headset
- * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
- * as invalid.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_LEFT_BATTERY = 10;
-
- /**
- * Battery level of rigth headset
- * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
- * as invalid.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_RIGHT_BATTERY = 11;
-
- /**
- * Battery level of the headset charging case
- * Data type should be {@String} 0-100 as {@link Byte} array, otherwise
- * as invalid.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_CASE_BATTERY = 12;
-
- /**
- * Whether the left headset is charging
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_LEFT_CHARGING = 13;
-
- /**
- * Whether the right headset is charging
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_RIGHT_CHARGING = 14;
-
- /**
- * Whether the headset charging case is charging
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_CASE_CHARGING = 15;
-
- /**
- * URI to the enhanced settings UI slice
- * Data type should be {@String} as {@link Byte} array, null means
- * the UI does not exist.
- * @hide
- */
- @SystemApi
- public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16;
-
- /**
- * Type of the Bluetooth device, must be within the list of
- * BluetoothDevice.DEVICE_TYPE_*
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_DEVICE_TYPE = 17;
-
- /**
- * Battery level of the Bluetooth device, use when the Bluetooth device
- * does not support HFP battery indicator.
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_MAIN_BATTERY = 18;
-
- /**
- * Whether the device is charging.
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_MAIN_CHARGING = 19;
-
- /**
- * The battery threshold of the Bluetooth device to show low battery icon.
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_MAIN_LOW_BATTERY_THRESHOLD = 20;
-
- /**
- * The battery threshold of the left headset to show low battery icon.
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_LEFT_LOW_BATTERY_THRESHOLD = 21;
-
- /**
- * The battery threshold of the right headset to show low battery icon.
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_RIGHT_LOW_BATTERY_THRESHOLD = 22;
-
- /**
- * The battery threshold of the case to show low battery icon.
- * Data type should be {@String} as {@link Byte} array.
- * @hide
- */
- @SystemApi
- public static final int METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD = 23;
-
- /**
- * Device type which is used in METADATA_DEVICE_TYPE
- * Indicates this Bluetooth device is a standard Bluetooth accessory or
- * not listed in METADATA_DEVICE_TYPE_*.
- * @hide
- */
- @SystemApi
- public static final String DEVICE_TYPE_DEFAULT = "Default";
-
- /**
- * Device type which is used in METADATA_DEVICE_TYPE
- * Indicates this Bluetooth device is a watch.
- * @hide
- */
- @SystemApi
- public static final String DEVICE_TYPE_WATCH = "Watch";
-
- /**
- * Device type which is used in METADATA_DEVICE_TYPE
- * Indicates this Bluetooth device is an untethered headset.
- * @hide
- */
- @SystemApi
- public static final String DEVICE_TYPE_UNTETHERED_HEADSET = "Untethered Headset";
-
- /**
- * Broadcast Action: This intent is used to broadcast the {@link UUID}
- * wrapped as a {@link android.os.ParcelUuid} of the remote device after it
- * has been fetched. This intent is sent only when the UUIDs of the remote
- * device are requested to be fetched using Service Discovery Protocol
- * <p> Always contains the extra field {@link #EXTRA_DEVICE}
- * <p> Always contains the extra field {@link #EXTRA_UUID}
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_UUID =
- "android.bluetooth.device.action.UUID";
-
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_MAS_INSTANCE =
- "android.bluetooth.device.action.MAS_INSTANCE";
-
- /**
- * Broadcast Action: Indicates a failure to retrieve the name of a remote
- * device.
- * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
- *
- * @hide
- */
- //TODO: is this actually useful?
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_NAME_FAILED =
- "android.bluetooth.device.action.NAME_FAILED";
-
- /**
- * Broadcast Action: This intent is used to broadcast PAIRING REQUEST
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PAIRING_REQUEST =
- "android.bluetooth.device.action.PAIRING_REQUEST";
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage
- public static final String ACTION_PAIRING_CANCEL =
- "android.bluetooth.device.action.PAIRING_CANCEL";
-
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_ACCESS_REQUEST =
- "android.bluetooth.device.action.CONNECTION_ACCESS_REQUEST";
-
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_ACCESS_REPLY =
- "android.bluetooth.device.action.CONNECTION_ACCESS_REPLY";
-
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_ACCESS_CANCEL =
- "android.bluetooth.device.action.CONNECTION_ACCESS_CANCEL";
-
- /**
- * Intent to broadcast silence mode changed.
- * Alway contains the extra field {@link #EXTRA_DEVICE}
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @SystemApi
- public static final String ACTION_SILENCE_MODE_CHANGED =
- "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
-
- /**
- * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
- *
- * @hide
- */
- public static final String EXTRA_ACCESS_REQUEST_TYPE =
- "android.bluetooth.device.extra.ACCESS_REQUEST_TYPE";
-
- /** @hide */
- public static final int REQUEST_TYPE_PROFILE_CONNECTION = 1;
-
- /** @hide */
- public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
-
- /** @hide */
- public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;
-
- /** @hide */
- public static final int REQUEST_TYPE_SIM_ACCESS = 4;
-
- /**
- * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
- * Contains package name to return reply intent to.
- *
- * @hide
- */
- public static final String EXTRA_PACKAGE_NAME = "android.bluetooth.device.extra.PACKAGE_NAME";
-
- /**
- * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
- * Contains class name to return reply intent to.
- *
- * @hide
- */
- public static final String EXTRA_CLASS_NAME = "android.bluetooth.device.extra.CLASS_NAME";
-
- /**
- * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intent.
- *
- * @hide
- */
- public static final String EXTRA_CONNECTION_ACCESS_RESULT =
- "android.bluetooth.device.extra.CONNECTION_ACCESS_RESULT";
-
- /** @hide */
- public static final int CONNECTION_ACCESS_YES = 1;
-
- /** @hide */
- public static final int CONNECTION_ACCESS_NO = 2;
-
- /**
- * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REPLY} intents,
- * Contains boolean to indicate if the allowed response is once-for-all so that
- * next request will be granted without asking user again.
- *
- * @hide
- */
- public static final String EXTRA_ALWAYS_ALLOWED =
- "android.bluetooth.device.extra.ALWAYS_ALLOWED";
-
- /**
- * A bond attempt succeeded
- *
- * @hide
- */
- public static final int BOND_SUCCESS = 0;
-
- /**
- * A bond attempt failed because pins did not match, or remote device did
- * not respond to pin request in time
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int UNBOND_REASON_AUTH_FAILED = 1;
-
- /**
- * A bond attempt failed because the other side explicitly rejected
- * bonding
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int UNBOND_REASON_AUTH_REJECTED = 2;
-
- /**
- * A bond attempt failed because we canceled the bonding process
- *
- * @hide
- */
- public static final int UNBOND_REASON_AUTH_CANCELED = 3;
-
- /**
- * A bond attempt failed because we could not contact the remote device
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
-
- /**
- * A bond attempt failed because a discovery is in progress
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
-
- /**
- * A bond attempt failed because of authentication timeout
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
-
- /**
- * A bond attempt failed because of repeated attempts
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
-
- /**
- * A bond attempt failed because we received an Authentication Cancel
- * by remote end
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final int UNBOND_REASON_REMOTE_AUTH_CANCELED = 8;
-
- /**
- * An existing bond was explicitly revoked
- *
- * @hide
- */
- public static final int UNBOND_REASON_REMOVED = 9;
-
- /**
- * The user will be prompted to enter a pin or
- * an app will enter a pin for user.
- */
- public static final int PAIRING_VARIANT_PIN = 0;
-
- /**
- * The user will be prompted to enter a passkey
- *
- * @hide
- */
- public static final int PAIRING_VARIANT_PASSKEY = 1;
-
- /**
- * The user will be prompted to confirm the passkey displayed on the screen or
- * an app will confirm the passkey for the user.
- */
- public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
-
- /**
- * The user will be prompted to accept or deny the incoming pairing request
- *
- * @hide
- */
- public static final int PAIRING_VARIANT_CONSENT = 3;
-
- /**
- * The user will be prompted to enter the passkey displayed on remote device
- * This is used for Bluetooth 2.1 pairing.
- *
- * @hide
- */
- public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
-
- /**
- * The user will be prompted to enter the PIN displayed on remote device.
- * This is used for Bluetooth 2.0 pairing.
- *
- * @hide
- */
- public static final int PAIRING_VARIANT_DISPLAY_PIN = 5;
-
- /**
- * The user will be prompted to accept or deny the OOB pairing request
- *
- * @hide
- */
- public static final int PAIRING_VARIANT_OOB_CONSENT = 6;
-
- /**
- * The user will be prompted to enter a 16 digit pin or
- * an app will enter a 16 digit pin for user.
- *
- * @hide
- */
- public static final int PAIRING_VARIANT_PIN_16_DIGITS = 7;
-
- /**
- * Used as an extra field in {@link #ACTION_UUID} intents,
- * Contains the {@link android.os.ParcelUuid}s of the remote device which
- * is a parcelable version of {@link UUID}.
- */
- public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
-
- /** @hide */
- public static final String EXTRA_SDP_RECORD =
- "android.bluetooth.device.extra.SDP_RECORD";
-
- /** @hide */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public static final String EXTRA_SDP_SEARCH_STATUS =
- "android.bluetooth.device.extra.SDP_SEARCH_STATUS";
-
- /** @hide */
- @IntDef(prefix = "ACCESS_", value = {ACCESS_UNKNOWN,
- ACCESS_ALLOWED, ACCESS_REJECTED})
- @Retention(RetentionPolicy.SOURCE)
- public @interface AccessPermission{}
-
- /**
- * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
- * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
- *
- * @hide
- */
- @SystemApi
- public static final int ACCESS_UNKNOWN = 0;
-
- /**
- * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
- * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
- *
- * @hide
- */
- @SystemApi
- public static final int ACCESS_ALLOWED = 1;
-
- /**
- * For {@link #getPhonebookAccessPermission}, {@link #setPhonebookAccessPermission},
- * {@link #getMessageAccessPermission} and {@link #setMessageAccessPermission}.
- *
- * @hide
- */
- @SystemApi
- public static final int ACCESS_REJECTED = 2;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = { "TRANSPORT_" },
- value = {
- /** Allow host to automatically select a transport (dual-mode only) */
- TRANSPORT_AUTO,
- /** Use Classic or BR/EDR transport.*/
- TRANSPORT_BREDR,
- /** Use Low Energy transport.*/
- TRANSPORT_LE,
- }
- )
- public @interface Transport {}
-
- /**
- * No preference of physical transport for GATT connections to remote dual-mode devices
- */
- public static final int TRANSPORT_AUTO = 0;
-
- /**
- * Prefer BR/EDR transport for GATT connections to remote dual-mode devices
- */
- public static final int TRANSPORT_BREDR = 1;
-
- /**
- * Prefer LE transport for GATT connections to remote dual-mode devices
- */
- public static final int TRANSPORT_LE = 2;
-
- /**
- * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
- * connection.
- */
- public static final int PHY_LE_1M = 1;
-
- /**
- * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
- * connection.
- */
- public static final int PHY_LE_2M = 2;
-
- /**
- * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
- * or connection.
- */
- public static final int PHY_LE_CODED = 3;
-
- /**
- * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
- * options in a bitmask.
- */
- public static final int PHY_LE_1M_MASK = 1;
-
- /**
- * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
- * options in a bitmask.
- */
- public static final int PHY_LE_2M_MASK = 2;
-
- /**
- * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
- * available options in a bitmask.
- */
- public static final int PHY_LE_CODED_MASK = 4;
-
- /**
- * No preferred coding when transmitting on the LE Coded PHY.
- */
- public static final int PHY_OPTION_NO_PREFERRED = 0;
-
- /**
- * Prefer the S=2 coding to be used when transmitting on the LE Coded PHY.
- */
- public static final int PHY_OPTION_S2 = 1;
-
- /**
- * Prefer the S=8 coding to be used when transmitting on the LE Coded PHY.
- */
- public static final int PHY_OPTION_S8 = 2;
-
-
- /** @hide */
- public static final String EXTRA_MAS_INSTANCE =
- "android.bluetooth.device.extra.MAS_INSTANCE";
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = { "ADDRESS_TYPE_" },
- value = {
- /** Hardware MAC Address */
- ADDRESS_TYPE_PUBLIC,
- /** Address is either resolvable, non-resolvable or static.*/
- ADDRESS_TYPE_RANDOM,
- }
- )
- public @interface AddressType {}
-
- /** Hardware MAC Address of the device */
- public static final int ADDRESS_TYPE_PUBLIC = 0;
- /** Address is either resolvable, non-resolvable or static. */
- public static final int ADDRESS_TYPE_RANDOM = 1;
-
- private static final String NULL_MAC_ADDRESS = "00:00:00:00:00:00";
-
- /**
- * Lazy initialization. Guaranteed final after first object constructed, or
- * getService() called.
- * TODO: Unify implementation of sService amongst BluetoothFoo API's
- */
- private static volatile IBluetooth sService;
-
- private final String mAddress;
- @AddressType private final int mAddressType;
-
- private AttributionSource mAttributionSource;
-
- /*package*/
- @UnsupportedAppUsage
- static IBluetooth getService() {
- synchronized (BluetoothDevice.class) {
- if (sService == null) {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- sService = adapter.getBluetoothService(sStateChangeCallback);
- }
- }
- return sService;
- }
-
- static IBluetoothManagerCallback sStateChangeCallback = new IBluetoothManagerCallback.Stub() {
-
- public void onBluetoothServiceUp(IBluetooth bluetoothService)
- throws RemoteException {
- synchronized (BluetoothDevice.class) {
- if (sService == null) {
- sService = bluetoothService;
- }
- }
- }
-
- public void onBluetoothServiceDown()
- throws RemoteException {
- synchronized (BluetoothDevice.class) {
- sService = null;
- }
- }
-
- public void onBrEdrDown() {
- if (DBG) Log.d(TAG, "onBrEdrDown: reached BLE ON state");
- }
-
- public void onOobData(@Transport int transport, OobData oobData) {
- if (DBG) Log.d(TAG, "onOobData: got data");
- }
- };
-
- /**
- * Create a new BluetoothDevice
- * Bluetooth MAC address must be upper case, such as "00:11:22:33:AA:BB",
- * and is validated in this constructor.
- *
- * @param address valid Bluetooth MAC address
- * @param attributionSource attribution for permission-protected calls
- * @throws RuntimeException Bluetooth is not available on this platform
- * @throws IllegalArgumentException address is invalid
- * @hide
- */
- @UnsupportedAppUsage
- /*package*/ BluetoothDevice(String address) {
- getService(); // ensures sService is initialized
- if (!BluetoothAdapter.checkBluetoothAddress(address)) {
- throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
- }
-
- mAddress = address;
- mAddressType = ADDRESS_TYPE_PUBLIC;
- mAttributionSource = AttributionSource.myAttributionSource();
- }
-
- /** {@hide} */
- public void setAttributionSource(@NonNull AttributionSource attributionSource) {
- mAttributionSource = attributionSource;
- }
-
- /** {@hide} */
- public void prepareToEnterProcess(@NonNull AttributionSource attributionSource) {
- setAttributionSource(attributionSource);
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof BluetoothDevice) {
- return mAddress.equals(((BluetoothDevice) o).getAddress());
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return mAddress.hashCode();
- }
-
- /**
- * Returns a string representation of this BluetoothDevice.
- * <p>Currently this is the Bluetooth hardware address, for example
- * "00:11:22:AA:BB:CC". However, you should always use {@link #getAddress}
- * if you explicitly require the Bluetooth hardware address in case the
- * {@link #toString} representation changes in the future.
- *
- * @return string representation of this BluetoothDevice
- */
- @Override
- public String toString() {
- return mAddress;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothDevice> CREATOR =
- new Parcelable.Creator<BluetoothDevice>() {
- public BluetoothDevice createFromParcel(Parcel in) {
- return new BluetoothDevice(in.readString());
- }
-
- public BluetoothDevice[] newArray(int size) {
- return new BluetoothDevice[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(mAddress);
- }
-
- /**
- * Returns the hardware address of this BluetoothDevice.
- * <p> For example, "00:11:22:AA:BB:CC".
- *
- * @return Bluetooth hardware address as string
- */
- public String getAddress() {
- if (DBG) Log.d(TAG, "mAddress: " + mAddress);
- return mAddress;
- }
-
- /**
- * Returns the anonymized hardware address of this BluetoothDevice. The first three octets
- * will be suppressed for anonymization.
- * <p> For example, "XX:XX:XX:AA:BB:CC".
- *
- * @return Anonymized bluetooth hardware address as string
- * @hide
- */
- public String getAnonymizedAddress() {
- return "XX:XX:XX" + getAddress().substring(8);
- }
-
- /**
- * Get the friendly Bluetooth name of the remote device.
- *
- * <p>The local adapter will automatically retrieve remote names when
- * performing a device scan, and will cache them. This method just returns
- * the name for this device from the cache.
- *
- * @return the Bluetooth name, or null if there was a problem.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public String getName() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot get Remote Device name");
- return null;
- }
- try {
- String name = service.getRemoteName(this, mAttributionSource);
- if (name != null) {
- // remove whitespace characters from the name
- return name
- .replace('\t', ' ')
- .replace('\n', ' ')
- .replace('\r', ' ');
- }
- return null;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return null;
- }
-
- /**
- * Get the Bluetooth device type of the remote device.
- *
- * @return the device type {@link #DEVICE_TYPE_CLASSIC}, {@link #DEVICE_TYPE_LE} {@link
- * #DEVICE_TYPE_DUAL}. {@link #DEVICE_TYPE_UNKNOWN} if it's not available
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getType() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot get Remote Device type");
- return DEVICE_TYPE_UNKNOWN;
- }
- try {
- return service.getRemoteType(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return DEVICE_TYPE_UNKNOWN;
- }
-
- /**
- * Get the locally modifiable name (alias) of the remote Bluetooth device.
- *
- * @return the Bluetooth alias, the friendly device name if no alias, or
- * null if there was a problem
- */
- @Nullable
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public String getAlias() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot get Remote Device Alias");
- return null;
- }
- try {
- String alias = service.getRemoteAliasWithAttribution(this, mAttributionSource);
- if (alias == null) {
- return getName();
- }
- return alias
- .replace('\t', ' ')
- .replace('\n', ' ')
- .replace('\r', ' ');
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return null;
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothStatusCodes.SUCCESS,
- BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
- BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
- BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
- BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
- })
- public @interface SetAliasReturnValues{}
-
- /**
- * Sets the locally modifiable name (alias) of the remote Bluetooth device. This method
- * overwrites the previously stored alias. The new alias is saved in local
- * storage so that the change is preserved over power cycles.
- *
- * <p>This method requires the calling app to be associated with Companion Device Manager (see
- * {@link android.companion.CompanionDeviceManager#associate(AssociationRequest,
- * android.companion.CompanionDeviceManager.Callback, Handler)}) and have the
- * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission. Alternatively, if the
- * caller has the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission, they can
- * bypass the Companion Device Manager association requirement as well as other permission
- * requirements.
- *
- * @param alias is the new locally modifiable name for the remote Bluetooth device which must
- * be the empty string. If null, we clear the alias.
- * @return whether the alias was successfully changed
- * @throws IllegalArgumentException if the alias is the empty string
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @SetAliasReturnValues int setAlias(@Nullable String alias) {
- if (alias != null && alias.isEmpty()) {
- throw new IllegalArgumentException("alias cannot be the empty string");
- }
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot set Remote Device name");
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- }
- try {
- return service.setRemoteAlias(this, alias, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Get the most recent identified battery level of this Bluetooth device
- *
- * @return Battery level in percents from 0 to 100, {@link #BATTERY_LEVEL_BLUETOOTH_OFF} if
- * Bluetooth is disabled or {@link #BATTERY_LEVEL_UNKNOWN} if device is disconnected, or does
- * not have any battery reporting service, or return value is invalid
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getBatteryLevel() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "Bluetooth disabled. Cannot get remote device battery level");
- return BATTERY_LEVEL_BLUETOOTH_OFF;
- }
- try {
- return service.getBatteryLevel(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return BATTERY_LEVEL_UNKNOWN;
- }
-
- /**
- * Start the bonding (pairing) process with the remote device.
- * <p>This is an asynchronous call, it will return immediately. Register
- * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
- * the bonding process completes, and its result.
- * <p>Android system services will handle the necessary user interactions
- * to confirm and complete the bonding process.
- *
- * @return false on immediate error, true if bonding will begin
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean createBond() {
- return createBond(TRANSPORT_AUTO);
- }
-
- /**
- * Start the bonding (pairing) process with the remote device using the
- * specified transport.
- *
- * <p>This is an asynchronous call, it will return immediately. Register
- * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
- * the bonding process completes, and its result.
- * <p>Android system services will handle the necessary user interactions
- * to confirm and complete the bonding process.
- *
- * @param transport The transport to use for the pairing procedure.
- * @return false on immediate error, true if bonding will begin
- * @throws IllegalArgumentException if an invalid transport was specified
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean createBond(int transport) {
- return createBondInternal(transport, null, null);
- }
-
- /**
- * Start the bonding (pairing) process with the remote device using the
- * Out Of Band mechanism.
- *
- * <p>This is an asynchronous call, it will return immediately. Register
- * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
- * the bonding process completes, and its result.
- *
- * <p>Android system services will handle the necessary user interactions
- * to confirm and complete the bonding process.
- *
- * <p>There are two possible versions of OOB Data. This data can come in as
- * P192 or P256. This is a reference to the cryptography used to generate the key.
- * The caller may pass one or both. If both types of data are passed, then the
- * P256 data will be preferred, and thus used.
- *
- * @param transport - Transport to use
- * @param remoteP192Data - Out Of Band data (P192) or null
- * @param remoteP256Data - Out Of Band data (P256) or null
- * @return false on immediate error, true if bonding will begin
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean createBondOutOfBand(int transport, @Nullable OobData remoteP192Data,
- @Nullable OobData remoteP256Data) {
- if (remoteP192Data == null && remoteP256Data == null) {
- throw new IllegalArgumentException(
- "One or both arguments for the OOB data types are required to not be null."
- + " Please use createBond() instead if you do not have OOB data to pass.");
- }
- return createBondInternal(transport, remoteP192Data, remoteP256Data);
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private boolean createBondInternal(int transport, @Nullable OobData remoteP192Data,
- @Nullable OobData remoteP256Data) {
- final IBluetooth service = sService;
- if (service == null) {
- Log.w(TAG, "BT not enabled, createBondOutOfBand failed");
- return false;
- }
- if (NULL_MAC_ADDRESS.equals(mAddress)) {
- Log.e(TAG, "Unable to create bond, invalid address " + mAddress);
- return false;
- }
- try {
- return service.createBond(
- this, transport, remoteP192Data, remoteP256Data, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Gets whether bonding was initiated locally
- *
- * @return true if bonding is initiated locally, false otherwise
- *
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isBondingInitiatedLocally() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.w(TAG, "BT not enabled, isBondingInitiatedLocally failed");
- return false;
- }
- try {
- return service.isBondingInitiatedLocally(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Cancel an in-progress bonding request started with {@link #createBond}.
- *
- * @return true on success, false on error
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean cancelBondProcess() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot cancel Remote Device bond");
- return false;
- }
- try {
- Log.i(TAG, "cancelBondProcess() for device " + getAddress()
- + " called by pid: " + Process.myPid()
- + " tid: " + Process.myTid());
- return service.cancelBondProcess(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Remove bond (pairing) with the remote device.
- * <p>Delete the link key associated with the remote device, and
- * immediately terminate connections to that device that require
- * authentication and encryption.
- *
- * @return true on success, false on error
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean removeBond() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot remove Remote Device bond");
- return false;
- }
- try {
- Log.i(TAG, "removeBond() for device " + getAddress()
- + " called by pid: " + Process.myPid()
- + " tid: " + Process.myTid());
- return service.removeBond(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /*
- private static final String BLUETOOTH_BONDING_CACHE_PROPERTY =
- "cache_key.bluetooth.get_bond_state";
- private final PropertyInvalidatedCache<BluetoothDevice, Integer> mBluetoothBondCache =
- new PropertyInvalidatedCache<BluetoothDevice, Integer>(
- 8, BLUETOOTH_BONDING_CACHE_PROPERTY) {
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public Integer recompute(BluetoothDevice query) {
- try {
- return sService.getBondState(query, mAttributionSource);
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
- }
- };
- */
-
- /** @hide */
- /* public void disableBluetoothGetBondStateCache() {
- mBluetoothBondCache.disableLocal();
- } */
-
- /** @hide */
- /*
- public static void invalidateBluetoothGetBondStateCache() {
- PropertyInvalidatedCache.invalidateCache(BLUETOOTH_BONDING_CACHE_PROPERTY);
- }
- */
-
- /**
- * Get the bond state of the remote device.
- * <p>Possible values for the bond state are:
- * {@link #BOND_NONE},
- * {@link #BOND_BONDING},
- * {@link #BOND_BONDED}.
- *
- * @return the bond state
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public int getBondState() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot get bond state");
- return BOND_NONE;
- }
- try {
- //return mBluetoothBondCache.query(this);
- return sService.getBondState(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "failed to ", e);
- e.rethrowFromSystemServer();
- }
- return BOND_NONE;
- }
-
- /**
- * Checks whether this bluetooth device is associated with CDM and meets the criteria to skip
- * the bluetooth pairing dialog because it has been already consented by the CDM prompt.
- *
- * @return true if we can bond without the dialog, false otherwise
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean canBondWithoutDialog() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot check if we can skip pairing dialog");
- return false;
- }
- try {
- if (DBG) Log.d(TAG, "canBondWithoutDialog, device: " + this);
- return service.canBondWithoutDialog(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothStatusCodes.SUCCESS,
- BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED,
- BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
- BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
- BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED
- })
- public @interface ConnectionReturnValues{}
-
- /**
- * Connects all user enabled and supported bluetooth profiles between the local and remote
- * device. If no profiles are user enabled (e.g. first connection), we connect all supported
- * profiles. If the device is not already connected, this will page the device before initiating
- * profile connections. Connection is asynchronous and you should listen to each profile's
- * broadcast intent ACTION_CONNECTION_STATE_CHANGED to verify whether connection was successful.
- * For example, to verify a2dp is connected, you would listen for
- * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
- *
- * @return whether the messages were successfully sent to try to connect all profiles
- * @throws IllegalArgumentException if the device address is invalid
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public @ConnectionReturnValues int connect() {
- if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) {
- throw new IllegalArgumentException("device cannot have an invalid address");
- }
-
- try {
- if (sService == null) {
- Log.e(TAG, "BT not enabled. Cannot connect to remote device.");
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- }
- return sService.connectAllEnabledProfiles(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Disconnects all connected bluetooth profiles between the local and remote device.
- * Disconnection is asynchronous and you should listen to each profile's broadcast intent
- * ACTION_CONNECTION_STATE_CHANGED to verify whether disconnection was successful. For example,
- * to verify a2dp is disconnected, you would listen for
- * {@link BluetoothA2dp#ACTION_CONNECTION_STATE_CHANGED}
- *
- * @return whether the messages were successfully sent to try to disconnect all profiles
- * @throws IllegalArgumentException if the device address is invalid
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionReturnValues int disconnect() {
- if (!BluetoothAdapter.checkBluetoothAddress(getAddress())) {
- throw new IllegalArgumentException("device cannot have an invalid address");
- }
-
- try {
- if (sService == null) {
- Log.e(TAG, "BT not enabled. Cannot disconnect from remote device.");
- return BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ENABLED;
- }
- return sService.disconnectAllEnabledProfiles(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Returns whether there is an open connection to this device.
- *
- * @return True if there is at least one open connection to this device.
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isConnected() {
- final IBluetooth service = sService;
- if (service == null) {
- // BT is not enabled, we cannot be connected.
- return false;
- }
- try {
- return service.getConnectionStateWithAttribution(this, mAttributionSource)
- != CONNECTION_STATE_DISCONNECTED;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
- }
-
- /**
- * Returns whether there is an open connection to this device
- * that has been encrypted.
- *
- * @return True if there is at least one encrypted connection to this device.
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isEncrypted() {
- final IBluetooth service = sService;
- if (service == null) {
- // BT is not enabled, we cannot be connected.
- return false;
- }
- try {
- return service.getConnectionStateWithAttribution(this, mAttributionSource)
- > CONNECTION_STATE_CONNECTED;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
- }
-
- /**
- * Get the Bluetooth class of the remote device.
- *
- * @return Bluetooth class object, or null on error
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothClass getBluetoothClass() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot get Bluetooth Class");
- return null;
- }
- try {
- int classInt = service.getRemoteClass(this, mAttributionSource);
- if (classInt == BluetoothClass.ERROR) return null;
- return new BluetoothClass(classInt);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return null;
- }
-
- /**
- * Returns the supported features (UUIDs) of the remote device.
- *
- * <p>This method does not start a service discovery procedure to retrieve the UUIDs
- * from the remote device. Instead, the local cached copy of the service
- * UUIDs are returned.
- * <p>Use {@link #fetchUuidsWithSdp} if fresh UUIDs are desired.
- *
- * @return the supported features (UUIDs) of the remote device, or null on error
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public ParcelUuid[] getUuids() {
- final IBluetooth service = sService;
- if (service == null || !isBluetoothEnabled()) {
- Log.e(TAG, "BT not enabled. Cannot get remote device Uuids");
- return null;
- }
- try {
- return service.getRemoteUuids(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return null;
- }
-
- /**
- * Perform a service discovery on the remote device to get the UUIDs supported.
- *
- * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
- * with the UUIDs supported by the remote end. If there is an error
- * in getting the SDP records or if the process takes a long time, or the device is bonding and
- * we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the UUIDs that is
- * currently present in the cache. Clients should use the {@link #getUuids} to get UUIDs
- * if service discovery is not to be performed. If there is an ongoing bonding process,
- * service discovery or device inquiry, the request will be queued.
- *
- * @return False if the check fails, True if the process of initiating an ACL connection
- * to the remote device was started or cached UUIDs will be broadcast.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean fetchUuidsWithSdp() {
- return fetchUuidsWithSdp(TRANSPORT_AUTO);
- }
-
- /**
- * Perform a service discovery on the remote device to get the UUIDs supported with the
- * specific transport.
- *
- * <p>This API is asynchronous and {@link #ACTION_UUID} intent is sent,
- * with the UUIDs supported by the remote end. If there is an error
- * in getting the SDP or GATT records or if the process takes a long time, or the device
- * is bonding and we have its UUIDs cached, {@link #ACTION_UUID} intent is sent with the
- * UUIDs that is currently present in the cache. Clients should use the {@link #getUuids}
- * to get UUIDs if service discovery is not to be performed. If there is an ongoing bonding
- * process, service discovery or device inquiry, the request will be queued.
- *
- * @param transport - provide type of transport (e.g. LE or Classic).
- * @return False if the check fails, True if the process of initiating an ACL connection
- * to the remote device was started or cached UUIDs will be broadcast with the specific
- * transport.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean fetchUuidsWithSdp(@Transport int transport) {
- final IBluetooth service = sService;
- if (service == null || !isBluetoothEnabled()) {
- Log.e(TAG, "BT not enabled. Cannot fetchUuidsWithSdp");
- return false;
- }
- try {
- return service.fetchRemoteUuidsWithAttribution(this, transport, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Perform a service discovery on the remote device to get the SDP records associated
- * with the specified UUID.
- *
- * <p>This API is asynchronous and {@link #ACTION_SDP_RECORD} intent is sent,
- * with the SDP records found on the remote end. If there is an error
- * in getting the SDP records or if the process takes a long time,
- * {@link #ACTION_SDP_RECORD} intent is sent with an status value in
- * {@link #EXTRA_SDP_SEARCH_STATUS} different from 0.
- * Detailed status error codes can be found by members of the Bluetooth package in
- * the AbstractionLayer class.
- * <p>The SDP record data will be stored in the intent as {@link #EXTRA_SDP_RECORD}.
- * The object type will match one of the SdpXxxRecord types, depending on the UUID searched
- * for.
- *
- * @return False if the check fails, True if the process
- * of initiating an ACL connection to the remote device
- * was started.
- */
- /** @hide */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean sdpSearch(ParcelUuid uuid) {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot query remote device sdp records");
- return false;
- }
- try {
- return service.sdpSearch(this, uuid, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
- *
- * @return true pin has been set false for error
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setPin(byte[] pin) {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot set Remote Device pin");
- return false;
- }
- try {
- return service.setPin(this, true, pin.length, pin, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Set the pin during pairing when the pairing method is {@link #PAIRING_VARIANT_PIN}
- *
- * @return true pin has been set false for error
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setPin(@NonNull String pin) {
- byte[] pinBytes = convertPinToBytes(pin);
- if (pinBytes == null) {
- return false;
- }
- return setPin(pinBytes);
- }
-
- /**
- * Confirm passkey for {@link #PAIRING_VARIANT_PASSKEY_CONFIRMATION} pairing.
- *
- * @return true confirmation has been sent out false for error
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPairingConfirmation(boolean confirm) {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot set pairing confirmation");
- return false;
- }
- try {
- return service.setPairingConfirmation(this, confirm, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Cancels pairing to this device
- *
- * @return true if pairing cancelled successfully, false otherwise
- *
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean cancelPairing() {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "BT not enabled. Cannot cancel pairing");
- return false;
- }
- try {
- return service.cancelBondProcess(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- boolean isBluetoothEnabled() {
- boolean ret = false;
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- if (adapter != null && adapter.isEnabled()) {
- ret = true;
- }
- return ret;
- }
-
- /**
- * Gets whether the phonebook access is allowed for this bluetooth device
- *
- * @return Whether the phonebook access is allowed to this device. Can be {@link
- * #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link #ACCESS_REJECTED}.
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @AccessPermission int getPhonebookAccessPermission() {
- final IBluetooth service = sService;
- if (service == null) {
- return ACCESS_UNKNOWN;
- }
- try {
- return service.getPhonebookAccessPermission(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return ACCESS_UNKNOWN;
- }
-
- /**
- * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not
- * be routed to the {@link BluetoothDevice} if set to {@code true}.
- *
- * When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
- * is an active device (for A2DP or HFP), the active device for that profile
- * will be set to null.
- * If the {@link BluetoothDevice} exits silence mode while the A2DP or HFP
- * active device is null, the {@link BluetoothDevice} will be set as the
- * active device for that profile.
- * If the {@link BluetoothDevice} is disconnected, it exits silence mode.
- * If the {@link BluetoothDevice} is set as the active device for A2DP or
- * HFP, while silence mode is enabled, then the device will exit silence mode.
- * If the {@link BluetoothDevice} is in silence mode, AVRCP position change
- * event and HFP AG indicators will be disabled.
- * If the {@link BluetoothDevice} is not connected with A2DP or HFP, it cannot
- * enter silence mode.
- *
- * @param silence true to enter silence mode, false to exit
- * @return true on success, false on error.
- * @throws IllegalStateException if Bluetooth is not turned ON.
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setSilenceMode(boolean silence) {
- final IBluetooth service = sService;
- if (service == null) {
- throw new IllegalStateException("Bluetooth is not turned ON");
- }
- try {
- return service.setSilenceMode(this, silence, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "setSilenceMode fail", e);
- return false;
- }
- }
-
- /**
- * Check whether the {@link BluetoothDevice} is in silence mode
- *
- * @return true on device in silence mode, otherwise false.
- * @throws IllegalStateException if Bluetooth is not turned ON.
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean isInSilenceMode() {
- final IBluetooth service = sService;
- if (service == null) {
- throw new IllegalStateException("Bluetooth is not turned ON");
- }
- try {
- return service.getSilenceMode(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "isInSilenceMode fail", e);
- return false;
- }
- }
-
- /**
- * Sets whether the phonebook access is allowed to this device.
- *
- * @param value Can be {@link #ACCESS_UNKNOWN}, {@link #ACCESS_ALLOWED} or {@link
- * #ACCESS_REJECTED}.
- * @return Whether the value has been successfully set.
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPhonebookAccessPermission(@AccessPermission int value) {
- final IBluetooth service = sService;
- if (service == null) {
- return false;
- }
- try {
- return service.setPhonebookAccessPermission(this, value, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Gets whether message access is allowed to this bluetooth device
- *
- * @return Whether the message access is allowed to this device.
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @AccessPermission int getMessageAccessPermission() {
- final IBluetooth service = sService;
- if (service == null) {
- return ACCESS_UNKNOWN;
- }
- try {
- return service.getMessageAccessPermission(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return ACCESS_UNKNOWN;
- }
-
- /**
- * Sets whether the message access is allowed to this device.
- *
- * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded,
- * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if
- * the permission is not being granted.
- * @return Whether the value has been successfully set.
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setMessageAccessPermission(@AccessPermission int value) {
- // Validates param value is one of the accepted constants
- if (value != ACCESS_ALLOWED && value != ACCESS_REJECTED && value != ACCESS_UNKNOWN) {
- throw new IllegalArgumentException(value + "is not a valid AccessPermission value");
- }
- final IBluetooth service = sService;
- if (service == null) {
- return false;
- }
- try {
- return service.setMessageAccessPermission(this, value, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Gets whether sim access is allowed for this bluetooth device
- *
- * @return Whether the Sim access is allowed to this device.
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @AccessPermission int getSimAccessPermission() {
- final IBluetooth service = sService;
- if (service == null) {
- return ACCESS_UNKNOWN;
- }
- try {
- return service.getSimAccessPermission(this, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return ACCESS_UNKNOWN;
- }
-
- /**
- * Sets whether the Sim access is allowed to this device.
- *
- * @param value Can be {@link #ACCESS_UNKNOWN} if the device is unbonded,
- * {@link #ACCESS_ALLOWED} if the permission is being granted, or {@link #ACCESS_REJECTED} if
- * the permission is not being granted.
- * @return Whether the value has been successfully set.
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setSimAccessPermission(int value) {
- final IBluetooth service = sService;
- if (service == null) {
- return false;
- }
- try {
- return service.setSimAccessPermission(this, value, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return false;
- }
-
- /**
- * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
- * outgoing connection to this remote device on given channel.
- * <p>The remote device will be authenticated and communication on this
- * socket will be encrypted.
- * <p> Use this socket only if an authenticated socket link is possible.
- * Authentication refers to the authentication of the link key to
- * prevent person-in-the-middle type of attacks.
- * For example, for Bluetooth 2.1 devices, if any of the devices does not
- * have an input and output capability or just has the ability to
- * display a numeric key, a secure socket connection is not possible.
- * In such a case, use {@link createInsecureRfcommSocket}.
- * For more details, refer to the Security Model section 5.2 (vol 3) of
- * Bluetooth Core Specification version 2.1 + EDR.
- * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
- * connection.
- * <p>Valid RFCOMM channels are in range 1 to 30.
- *
- * @param channel RFCOMM channel to connect to
- * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public BluetoothSocket createRfcommSocket(int channel) throws IOException {
- if (!isBluetoothEnabled()) {
- Log.e(TAG, "Bluetooth is not enabled");
- throw new IOException();
- }
- return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, channel,
- null);
- }
-
- /**
- * Create an L2cap {@link BluetoothSocket} ready to start a secure
- * outgoing connection to this remote device on given channel.
- * <p>The remote device will be authenticated and communication on this
- * socket will be encrypted.
- * <p> Use this socket only if an authenticated socket link is possible.
- * Authentication refers to the authentication of the link key to
- * prevent person-in-the-middle type of attacks.
- * For example, for Bluetooth 2.1 devices, if any of the devices does not
- * have an input and output capability or just has the ability to
- * display a numeric key, a secure socket connection is not possible.
- * In such a case, use {@link createInsecureRfcommSocket}.
- * For more details, refer to the Security Model section 5.2 (vol 3) of
- * Bluetooth Core Specification version 2.1 + EDR.
- * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
- * connection.
- * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
- *
- * @param channel L2cap PSM/channel to connect to
- * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public BluetoothSocket createL2capSocket(int channel) throws IOException {
- return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, true, true, this, channel,
- null);
- }
-
- /**
- * Create an L2cap {@link BluetoothSocket} ready to start an insecure
- * outgoing connection to this remote device on given channel.
- * <p>The remote device will be not authenticated and communication on this
- * socket will not be encrypted.
- * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
- * connection.
- * <p>Valid L2CAP PSM channels are in range 1 to 2^16.
- *
- * @param channel L2cap PSM/channel to connect to
- * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public BluetoothSocket createInsecureL2capSocket(int channel) throws IOException {
- return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP, -1, false, false, this, channel,
- null);
- }
-
- /**
- * Create an RFCOMM {@link BluetoothSocket} ready to start a secure
- * outgoing connection to this remote device using SDP lookup of uuid.
- * <p>This is designed to be used with {@link
- * BluetoothAdapter#listenUsingRfcommWithServiceRecord} for peer-peer
- * Bluetooth applications.
- * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
- * connection. This will also perform an SDP lookup of the given uuid to
- * determine which channel to connect to.
- * <p>The remote device will be authenticated and communication on this
- * socket will be encrypted.
- * <p> Use this socket only if an authenticated socket link is possible.
- * Authentication refers to the authentication of the link key to
- * prevent person-in-the-middle type of attacks.
- * For example, for Bluetooth 2.1 devices, if any of the devices does not
- * have an input and output capability or just has the ability to
- * display a numeric key, a secure socket connection is not possible.
- * In such a case, use {@link #createInsecureRfcommSocketToServiceRecord}.
- * For more details, refer to the Security Model section 5.2 (vol 3) of
- * Bluetooth Core Specification version 2.1 + EDR.
- * <p>Hint: If you are connecting to a Bluetooth serial board then try
- * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
- * However if you are connecting to an Android peer then please generate
- * your own unique UUID.
- *
- * @param uuid service record uuid to lookup RFCOMM channel
- * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public BluetoothSocket createRfcommSocketToServiceRecord(UUID uuid) throws IOException {
- if (!isBluetoothEnabled()) {
- Log.e(TAG, "Bluetooth is not enabled");
- throw new IOException();
- }
-
- return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, true, true, this, -1,
- new ParcelUuid(uuid));
- }
-
- /**
- * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
- * outgoing connection to this remote device using SDP lookup of uuid.
- * <p> The communication channel will not have an authenticated link key
- * i.e it will be subject to person-in-the-middle attacks. For Bluetooth 2.1
- * devices, the link key will be encrypted, as encryption is mandatory.
- * For legacy devices (pre Bluetooth 2.1 devices) the link key will
- * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
- * encrypted and authenticated communication channel is desired.
- * <p>This is designed to be used with {@link
- * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
- * Bluetooth applications.
- * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
- * connection. This will also perform an SDP lookup of the given uuid to
- * determine which channel to connect to.
- * <p>The remote device will be authenticated and communication on this
- * socket will be encrypted.
- * <p>Hint: If you are connecting to a Bluetooth serial board then try
- * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
- * However if you are connecting to an Android peer then please generate
- * your own unique UUID.
- *
- * @param uuid service record uuid to lookup RFCOMM channel
- * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
- if (!isBluetoothEnabled()) {
- Log.e(TAG, "Bluetooth is not enabled");
- throw new IOException();
- }
- return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
- new ParcelUuid(uuid));
- }
-
- /**
- * Construct an insecure RFCOMM socket ready to start an outgoing
- * connection.
- * Call #connect on the returned #BluetoothSocket to begin the connection.
- * The remote device will not be authenticated and communication on this
- * socket will not be encrypted.
- *
- * @param port remote port
- * @return An RFCOMM BluetoothSocket
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- @UnsupportedAppUsage(publicAlternatives = "Use "
- + "{@link #createInsecureRfcommSocketToServiceRecord} instead.")
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public BluetoothSocket createInsecureRfcommSocket(int port) throws IOException {
- if (!isBluetoothEnabled()) {
- Log.e(TAG, "Bluetooth is not enabled");
- throw new IOException();
- }
- return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, port,
- null);
- }
-
- /**
- * Construct a SCO socket ready to start an outgoing connection.
- * Call #connect on the returned #BluetoothSocket to begin the connection.
- *
- * @return a SCO BluetoothSocket
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions.
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public BluetoothSocket createScoSocket() throws IOException {
- if (!isBluetoothEnabled()) {
- Log.e(TAG, "Bluetooth is not enabled");
- throw new IOException();
- }
- return new BluetoothSocket(BluetoothSocket.TYPE_SCO, -1, true, true, this, -1, null);
- }
-
- /**
- * Check that a pin is valid and convert to byte array.
- *
- * Bluetooth pin's are 1 to 16 bytes of UTF-8 characters.
- *
- * @param pin pin as java String
- * @return the pin code as a UTF-8 byte array, or null if it is an invalid Bluetooth pin.
- * @hide
- */
- @UnsupportedAppUsage
- public static byte[] convertPinToBytes(String pin) {
- if (pin == null) {
- return null;
- }
- byte[] pinBytes;
- try {
- pinBytes = pin.getBytes("UTF-8");
- } catch (UnsupportedEncodingException uee) {
- Log.e(TAG, "UTF-8 not supported?!?"); // this should not happen
- return null;
- }
- if (pinBytes.length <= 0 || pinBytes.length > 16) {
- return null;
- }
- return pinBytes;
- }
-
- /**
- * Connect to GATT Server hosted by this device. Caller acts as GATT client.
- * The callback is used to deliver results to Caller, such as connection status as well
- * as any further GATT client operations.
- * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
- * GATT client operations.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @param autoConnect Whether to directly connect to the remote device (false) or to
- * automatically connect as soon as the remote device becomes available (true).
- * @throws IllegalArgumentException if callback is null
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGatt connectGatt(Context context, boolean autoConnect,
- BluetoothGattCallback callback) {
- return (connectGatt(context, autoConnect, callback, TRANSPORT_AUTO));
- }
-
- /**
- * Connect to GATT Server hosted by this device. Caller acts as GATT client.
- * The callback is used to deliver results to Caller, such as connection status as well
- * as any further GATT client operations.
- * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
- * GATT client operations.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @param autoConnect Whether to directly connect to the remote device (false) or to
- * automatically connect as soon as the remote device becomes available (true).
- * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
- * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
- * BluetoothDevice#TRANSPORT_LE}
- * @throws IllegalArgumentException if callback is null
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGatt connectGatt(Context context, boolean autoConnect,
- BluetoothGattCallback callback, int transport) {
- return (connectGatt(context, autoConnect, callback, transport, PHY_LE_1M_MASK));
- }
-
- /**
- * Connect to GATT Server hosted by this device. Caller acts as GATT client.
- * The callback is used to deliver results to Caller, such as connection status as well
- * as any further GATT client operations.
- * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
- * GATT client operations.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @param autoConnect Whether to directly connect to the remote device (false) or to
- * automatically connect as soon as the remote device becomes available (true).
- * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
- * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
- * BluetoothDevice#TRANSPORT_LE}
- * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
- * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
- * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
- * is set to true.
- * @throws NullPointerException if callback is null
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGatt connectGatt(Context context, boolean autoConnect,
- BluetoothGattCallback callback, int transport, int phy) {
- return connectGatt(context, autoConnect, callback, transport, phy, null);
- }
-
- /**
- * Connect to GATT Server hosted by this device. Caller acts as GATT client.
- * The callback is used to deliver results to Caller, such as connection status as well
- * as any further GATT client operations.
- * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
- * GATT client operations.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @param autoConnect Whether to directly connect to the remote device (false) or to
- * automatically connect as soon as the remote device becomes available (true).
- * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
- * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
- * BluetoothDevice#TRANSPORT_LE}
- * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
- * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
- * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
- * is set to true.
- * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
- * an un-specified background thread.
- * @throws NullPointerException if callback is null
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGatt connectGatt(Context context, boolean autoConnect,
- BluetoothGattCallback callback, int transport, int phy,
- Handler handler) {
- return connectGatt(context, autoConnect, callback, transport, false, phy, handler);
- }
-
- /**
- * Connect to GATT Server hosted by this device. Caller acts as GATT client.
- * The callback is used to deliver results to Caller, such as connection status as well
- * as any further GATT client operations.
- * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
- * GATT client operations.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @param autoConnect Whether to directly connect to the remote device (false) or to
- * automatically connect as soon as the remote device becomes available (true).
- * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
- * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
- * BluetoothDevice#TRANSPORT_LE}
- * @param opportunistic Whether this GATT client is opportunistic. An opportunistic GATT client
- * does not hold a GATT connection. It automatically disconnects when no other GATT connections
- * are active for the remote device.
- * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of {@link
- * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, an d{@link
- * BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if {@code autoConnect}
- * is set to true.
- * @param handler The handler to use for the callback. If {@code null}, callbacks will happen on
- * an un-specified background thread.
- * @return A BluetoothGatt instance. You can use BluetoothGatt to conduct GATT client
- * operations.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGatt connectGatt(Context context, boolean autoConnect,
- BluetoothGattCallback callback, int transport,
- boolean opportunistic, int phy, Handler handler) {
- if (callback == null) {
- throw new NullPointerException("callback is null");
- }
-
- // TODO(Bluetooth) check whether platform support BLE
- // Do the check here or in GattServer?
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- IBluetoothManager managerService = adapter.getBluetoothManager();
- try {
- IBluetoothGatt iGatt = managerService.getBluetoothGatt();
- if (iGatt == null) {
- // BLE is not supported
- return null;
- }
- BluetoothGatt gatt = new BluetoothGatt(
- iGatt, this, transport, opportunistic, phy, mAttributionSource);
- gatt.connect(autoConnect, callback, handler);
- return gatt;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- return null;
- }
-
- /**
- * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
- * be used to start a secure outgoing connection to the remote device with the same dynamic
- * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
- * <p>This is designed to be used with {@link BluetoothAdapter#listenUsingL2capChannel()} for
- * peer-peer Bluetooth applications.
- * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
- * <p>Application using this API is responsible for obtaining PSM value from remote device.
- * <p>The remote device will be authenticated and communication on this socket will be
- * encrypted.
- * <p> Use this socket if an authenticated socket link is possible. Authentication refers
- * to the authentication of the link key to prevent person-in-the-middle type of attacks.
- *
- * @param psm dynamic PSM value from remote device
- * @return a CoC #BluetoothSocket ready for an outgoing connection
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public @NonNull BluetoothSocket createL2capChannel(int psm) throws IOException {
- if (!isBluetoothEnabled()) {
- Log.e(TAG, "createL2capChannel: Bluetooth is not enabled");
- throw new IOException();
- }
- if (DBG) Log.d(TAG, "createL2capChannel: psm=" + psm);
- return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, true, true, this, psm,
- null);
- }
-
- /**
- * Create a Bluetooth L2CAP Connection-oriented Channel (CoC) {@link BluetoothSocket} that can
- * be used to start a secure outgoing connection to the remote device with the same dynamic
- * protocol/service multiplexer (PSM) value. The supported Bluetooth transport is LE only.
- * <p>This is designed to be used with {@link
- * BluetoothAdapter#listenUsingInsecureL2capChannel()} for peer-peer Bluetooth applications.
- * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing connection.
- * <p>Application using this API is responsible for obtaining PSM value from remote device.
- * <p> The communication channel may not have an authenticated link key, i.e. it may be subject
- * to person-in-the-middle attacks. Use {@link #createL2capChannel(int)} if an encrypted and
- * authenticated communication channel is possible.
- *
- * @param psm dynamic PSM value from remote device
- * @return a CoC #BluetoothSocket ready for an outgoing connection
- * @throws IOException on error, for example Bluetooth not available, or insufficient
- * permissions
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public @NonNull BluetoothSocket createInsecureL2capChannel(int psm) throws IOException {
- if (!isBluetoothEnabled()) {
- Log.e(TAG, "createInsecureL2capChannel: Bluetooth is not enabled");
- throw new IOException();
- }
- if (DBG) {
- Log.d(TAG, "createInsecureL2capChannel: psm=" + psm);
- }
- return new BluetoothSocket(BluetoothSocket.TYPE_L2CAP_LE, -1, false, false, this, psm,
- null);
- }
-
- /**
- * Set a keyed metadata of this {@link BluetoothDevice} to a
- * {@link String} value.
- * Only bonded devices's metadata will be persisted across Bluetooth
- * restart.
- * Metadata will be removed when the device's bond state is moved to
- * {@link #BOND_NONE}.
- *
- * @param key must be within the list of BluetoothDevice.METADATA_*
- * @param value a byte array data to set for key. Must be less than
- * {@link BluetoothAdapter#METADATA_MAX_LENGTH} characters in length
- * @return true on success, false on error
- * @hide
- */
- @SystemApi
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setMetadata(@MetadataKey int key, @NonNull byte[] value) {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "Bluetooth is not enabled. Cannot set metadata");
- return false;
- }
- if (value.length > METADATA_MAX_LENGTH) {
- throw new IllegalArgumentException("value length is " + value.length
- + ", should not over " + METADATA_MAX_LENGTH);
- }
- try {
- return service.setMetadata(this, key, value, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "setMetadata fail", e);
- return false;
- }
- }
-
- /**
- * Get a keyed metadata for this {@link BluetoothDevice} as {@link String}
- *
- * @param key must be within the list of BluetoothDevice.METADATA_*
- * @return Metadata of the key as byte array, null on error or not found
- * @hide
- */
- @SystemApi
- @Nullable
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public byte[] getMetadata(@MetadataKey int key) {
- final IBluetooth service = sService;
- if (service == null) {
- Log.e(TAG, "Bluetooth is not enabled. Cannot get metadata");
- return null;
- }
- try {
- return service.getMetadata(this, key, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "getMetadata fail", e);
- return null;
- }
- }
-
- /**
- * Get the maxinum metadata key ID.
- *
- * @return the last supported metadata key
- * @hide
- */
- public static @MetadataKey int getMaxMetadataKey() {
- return METADATA_UNTETHERED_CASE_LOW_BATTERY_THRESHOLD;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothDevicePicker.java b/core/java/android/bluetooth/BluetoothDevicePicker.java
deleted file mode 100644
index 26e4657..0000000
--- a/core/java/android/bluetooth/BluetoothDevicePicker.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-
-/**
- * A helper to show a system "Device Picker" activity to the user.
- *
- * @hide
- */
-public interface BluetoothDevicePicker {
- public static final String EXTRA_NEED_AUTH =
- "android.bluetooth.devicepicker.extra.NEED_AUTH";
- public static final String EXTRA_FILTER_TYPE =
- "android.bluetooth.devicepicker.extra.FILTER_TYPE";
- public static final String EXTRA_LAUNCH_PACKAGE =
- "android.bluetooth.devicepicker.extra.LAUNCH_PACKAGE";
- public static final String EXTRA_LAUNCH_CLASS =
- "android.bluetooth.devicepicker.extra.DEVICE_PICKER_LAUNCH_CLASS";
-
- /**
- * Broadcast when one BT device is selected from BT device picker screen.
- * Selected {@link BluetoothDevice} is returned in extra data named
- * {@link BluetoothDevice#EXTRA_DEVICE}.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_DEVICE_SELECTED =
- "android.bluetooth.devicepicker.action.DEVICE_SELECTED";
-
- /**
- * Broadcast when someone want to select one BT device from devices list.
- * This intent contains below extra data:
- * - {@link #EXTRA_NEED_AUTH} (boolean): if need authentication
- * - {@link #EXTRA_FILTER_TYPE} (int): what kinds of device should be
- * listed
- * - {@link #EXTRA_LAUNCH_PACKAGE} (string): where(which package) this
- * intent come from
- * - {@link #EXTRA_LAUNCH_CLASS} (string): where(which class) this intent
- * come from
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_LAUNCH =
- "android.bluetooth.devicepicker.action.LAUNCH";
-
- /** Ask device picker to show all kinds of BT devices */
- public static final int FILTER_TYPE_ALL = 0;
- /** Ask device picker to show BT devices that support AUDIO profiles */
- public static final int FILTER_TYPE_AUDIO = 1;
- /** Ask device picker to show BT devices that support Object Transfer */
- public static final int FILTER_TYPE_TRANSFER = 2;
- /**
- * Ask device picker to show BT devices that support
- * Personal Area Networking User (PANU) profile
- */
- public static final int FILTER_TYPE_PANU = 3;
- /** Ask device picker to show BT devices that support Network Access Point (NAP) profile */
- public static final int FILTER_TYPE_NAP = 4;
-}
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
deleted file mode 100644
index b531829..0000000
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ /dev/null
@@ -1,1848 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.os.Build;
-import android.os.Handler;
-import android.os.ParcelUuid;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Public API for the Bluetooth GATT Profile.
- *
- * <p>This class provides Bluetooth GATT functionality to enable communication
- * with Bluetooth Smart or Smart Ready devices.
- *
- * <p>To connect to a remote peripheral device, create a {@link BluetoothGattCallback}
- * and call {@link BluetoothDevice#connectGatt} to get a instance of this class.
- * GATT capable devices can be discovered using the Bluetooth device discovery or BLE
- * scan process.
- */
-public final class BluetoothGatt implements BluetoothProfile {
- private static final String TAG = "BluetoothGatt";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- @UnsupportedAppUsage
- private IBluetoothGatt mService;
- @UnsupportedAppUsage
- private volatile BluetoothGattCallback mCallback;
- private Handler mHandler;
- @UnsupportedAppUsage
- private int mClientIf;
- private BluetoothDevice mDevice;
- @UnsupportedAppUsage
- private boolean mAutoConnect;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- private int mAuthRetryState;
- private int mConnState;
- private final Object mStateLock = new Object();
- private final Object mDeviceBusyLock = new Object();
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private Boolean mDeviceBusy = false;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private int mTransport;
- private int mPhy;
- private boolean mOpportunistic;
- private final AttributionSource mAttributionSource;
-
- private static final int AUTH_RETRY_STATE_IDLE = 0;
- private static final int AUTH_RETRY_STATE_NO_MITM = 1;
- private static final int AUTH_RETRY_STATE_MITM = 2;
-
- private static final int CONN_STATE_IDLE = 0;
- private static final int CONN_STATE_CONNECTING = 1;
- private static final int CONN_STATE_CONNECTED = 2;
- private static final int CONN_STATE_DISCONNECTING = 3;
- private static final int CONN_STATE_CLOSED = 4;
-
- private static final int WRITE_CHARACTERISTIC_MAX_RETRIES = 5;
- private static final int WRITE_CHARACTERISTIC_TIME_TO_WAIT = 10; // milliseconds
-
- private List<BluetoothGattService> mServices;
-
- /** A GATT operation completed successfully */
- public static final int GATT_SUCCESS = 0;
-
- /** GATT read operation is not permitted */
- public static final int GATT_READ_NOT_PERMITTED = 0x2;
-
- /** GATT write operation is not permitted */
- public static final int GATT_WRITE_NOT_PERMITTED = 0x3;
-
- /** Insufficient authentication for a given operation */
- public static final int GATT_INSUFFICIENT_AUTHENTICATION = 0x5;
-
- /** The given request is not supported */
- public static final int GATT_REQUEST_NOT_SUPPORTED = 0x6;
-
- /** Insufficient encryption for a given operation */
- public static final int GATT_INSUFFICIENT_ENCRYPTION = 0xf;
-
- /** A read or write operation was requested with an invalid offset */
- public static final int GATT_INVALID_OFFSET = 0x7;
-
- /** Insufficient authorization for a given operation */
- public static final int GATT_INSUFFICIENT_AUTHORIZATION = 0x8;
-
- /** A write operation exceeds the maximum length of the attribute */
- public static final int GATT_INVALID_ATTRIBUTE_LENGTH = 0xd;
-
- /** A remote device connection is congested. */
- public static final int GATT_CONNECTION_CONGESTED = 0x8f;
-
- /** A GATT operation failed, errors other than the above */
- public static final int GATT_FAILURE = 0x101;
-
- /**
- * Connection parameter update - Use the connection parameters recommended by the
- * Bluetooth SIG. This is the default value if no connection parameter update
- * is requested.
- */
- public static final int CONNECTION_PRIORITY_BALANCED = 0;
-
- /**
- * Connection parameter update - Request a high priority, low latency connection.
- * An application should only request high priority connection parameters to transfer large
- * amounts of data over LE quickly. Once the transfer is complete, the application should
- * request {@link BluetoothGatt#CONNECTION_PRIORITY_BALANCED} connection parameters to reduce
- * energy use.
- */
- public static final int CONNECTION_PRIORITY_HIGH = 1;
-
- /** Connection parameter update - Request low power, reduced data rate connection parameters. */
- public static final int CONNECTION_PRIORITY_LOW_POWER = 2;
-
- /**
- * No authentication required.
- *
- * @hide
- */
- /*package*/ static final int AUTHENTICATION_NONE = 0;
-
- /**
- * Authentication requested; no person-in-the-middle protection required.
- *
- * @hide
- */
- /*package*/ static final int AUTHENTICATION_NO_MITM = 1;
-
- /**
- * Authentication with person-in-the-middle protection requested.
- *
- * @hide
- */
- /*package*/ static final int AUTHENTICATION_MITM = 2;
-
- /**
- * Bluetooth GATT callbacks. Overrides the default BluetoothGattCallback implementation.
- */
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothGattCallback mBluetoothGattCallback =
- new IBluetoothGattCallback.Stub() {
- /**
- * Application interface registered - app is ready to go
- * @hide
- */
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public void onClientRegistered(int status, int clientIf) {
- if (DBG) {
- Log.d(TAG, "onClientRegistered() - status=" + status
- + " clientIf=" + clientIf);
- }
- if (VDBG) {
- synchronized (mStateLock) {
- if (mConnState != CONN_STATE_CONNECTING) {
- Log.e(TAG, "Bad connection state: " + mConnState);
- }
- }
- }
- mClientIf = clientIf;
- if (status != GATT_SUCCESS) {
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onConnectionStateChange(BluetoothGatt.this,
- GATT_FAILURE,
- BluetoothProfile.STATE_DISCONNECTED);
- }
- }
- });
-
- synchronized (mStateLock) {
- mConnState = CONN_STATE_IDLE;
- }
- return;
- }
- try {
- mService.clientConnect(mClientIf, mDevice.getAddress(),
- !mAutoConnect, mTransport, mOpportunistic,
- mPhy, mAttributionSource); // autoConnect is inverse of "isDirect"
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Phy update callback
- * @hide
- */
- @Override
- public void onPhyUpdate(String address, int txPhy, int rxPhy, int status) {
- if (DBG) {
- Log.d(TAG, "onPhyUpdate() - status=" + status
- + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy);
- }
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
- }
- }
- });
- }
-
- /**
- * Phy read callback
- * @hide
- */
- @Override
- public void onPhyRead(String address, int txPhy, int rxPhy, int status) {
- if (DBG) {
- Log.d(TAG, "onPhyRead() - status=" + status
- + " address=" + address + " txPhy=" + txPhy + " rxPhy=" + rxPhy);
- }
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
- }
- }
- });
- }
-
- /**
- * Client connection state changed
- * @hide
- */
- @Override
- public void onClientConnectionState(int status, int clientIf,
- boolean connected, String address) {
- if (DBG) {
- Log.d(TAG, "onClientConnectionState() - status=" + status
- + " clientIf=" + clientIf + " device=" + address);
- }
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
- int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
- BluetoothProfile.STATE_DISCONNECTED;
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onConnectionStateChange(BluetoothGatt.this, status,
- profileState);
- }
- }
- });
-
- synchronized (mStateLock) {
- if (connected) {
- mConnState = CONN_STATE_CONNECTED;
- } else {
- mConnState = CONN_STATE_IDLE;
- }
- }
-
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
- }
-
- /**
- * Remote search has been completed.
- * The internal object structure should now reflect the state
- * of the remote device database. Let the application know that
- * we are done at this point.
- * @hide
- */
- @Override
- public void onSearchComplete(String address, List<BluetoothGattService> services,
- int status) {
- if (DBG) {
- Log.d(TAG,
- "onSearchComplete() = Device=" + address + " Status=" + status);
- }
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- for (BluetoothGattService s : services) {
- //services we receive don't have device set properly.
- s.setDevice(mDevice);
- }
-
- mServices.addAll(services);
-
- // Fix references to included services, as they doesn't point to right objects.
- for (BluetoothGattService fixedService : mServices) {
- ArrayList<BluetoothGattService> includedServices =
- new ArrayList(fixedService.getIncludedServices());
- fixedService.getIncludedServices().clear();
-
- for (BluetoothGattService brokenRef : includedServices) {
- BluetoothGattService includedService = getService(mDevice,
- brokenRef.getUuid(), brokenRef.getInstanceId());
- if (includedService != null) {
- fixedService.addIncludedService(includedService);
- } else {
- Log.e(TAG, "Broken GATT database: can't find included service.");
- }
- }
- }
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onServicesDiscovered(BluetoothGatt.this, status);
- }
- }
- });
- }
-
- /**
- * Remote characteristic has been read.
- * Updates the internal value.
- * @hide
- */
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public void onCharacteristicRead(String address, int status, int handle,
- byte[] value) {
- if (VDBG) {
- Log.d(TAG, "onCharacteristicRead() - Device=" + address
- + " handle=" + handle + " Status=" + status);
- }
-
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
-
- if ((status == GATT_INSUFFICIENT_AUTHENTICATION
- || status == GATT_INSUFFICIENT_ENCRYPTION)
- && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
- try {
- final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
- ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
- mService.readCharacteristic(
- mClientIf, address, handle, authReq, mAttributionSource);
- mAuthRetryState++;
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- mAuthRetryState = AUTH_RETRY_STATE_IDLE;
-
- BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice,
- handle);
- if (characteristic == null) {
- Log.w(TAG, "onCharacteristicRead() failed to find characteristic!");
- return;
- }
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- if (status == 0) characteristic.setValue(value);
- callback.onCharacteristicRead(BluetoothGatt.this, characteristic,
- value, status);
- // Keep calling deprecated callback to maintain app compatibility
- callback.onCharacteristicRead(BluetoothGatt.this, characteristic,
- status);
- }
- }
- });
- }
-
- /**
- * Characteristic has been written to the remote device.
- * Let the app know how we did...
- * @hide
- */
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public void onCharacteristicWrite(String address, int status, int handle,
- byte[] value) {
- if (VDBG) {
- Log.d(TAG, "onCharacteristicWrite() - Device=" + address
- + " handle=" + handle + " Status=" + status);
- }
-
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
-
- BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice,
- handle);
- if (characteristic == null) return;
-
- if ((status == GATT_INSUFFICIENT_AUTHENTICATION
- || status == GATT_INSUFFICIENT_ENCRYPTION)
- && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
- try {
- final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
- ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
- int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN;
- for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
- requestStatus = mService.writeCharacteristic(mClientIf, address,
- handle, characteristic.getWriteType(), authReq,
- value, mAttributionSource);
- if (requestStatus
- != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) {
- break;
- }
- try {
- Thread.sleep(WRITE_CHARACTERISTIC_TIME_TO_WAIT);
- } catch (InterruptedException e) {
- }
- }
- mAuthRetryState++;
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- mAuthRetryState = AUTH_RETRY_STATE_IDLE;
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onCharacteristicWrite(BluetoothGatt.this, characteristic,
- status);
- }
- }
- });
- }
-
- /**
- * Remote characteristic has been updated.
- * Updates the internal value.
- * @hide
- */
- @Override
- public void onNotify(String address, int handle, byte[] value) {
- if (VDBG) Log.d(TAG, "onNotify() - Device=" + address + " handle=" + handle);
-
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- BluetoothGattCharacteristic characteristic = getCharacteristicById(mDevice,
- handle);
- if (characteristic == null) return;
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- characteristic.setValue(value);
- callback.onCharacteristicChanged(BluetoothGatt.this,
- characteristic, value);
- // Keep calling deprecated callback to maintain app compatibility
- callback.onCharacteristicChanged(BluetoothGatt.this,
- characteristic);
- }
- }
- });
- }
-
- /**
- * Descriptor has been read.
- * @hide
- */
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public void onDescriptorRead(String address, int status, int handle, byte[] value) {
- if (VDBG) {
- Log.d(TAG,
- "onDescriptorRead() - Device=" + address + " handle=" + handle);
- }
-
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
-
- BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
- if (descriptor == null) return;
-
-
- if ((status == GATT_INSUFFICIENT_AUTHENTICATION
- || status == GATT_INSUFFICIENT_ENCRYPTION)
- && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
- try {
- final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
- ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
- mService.readDescriptor(
- mClientIf, address, handle, authReq, mAttributionSource);
- mAuthRetryState++;
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- mAuthRetryState = AUTH_RETRY_STATE_IDLE;
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- if (status == 0) descriptor.setValue(value);
- callback.onDescriptorRead(BluetoothGatt.this, descriptor, status,
- value);
- // Keep calling deprecated callback to maintain app compatibility
- callback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
- }
- }
- });
- }
-
- /**
- * Descriptor write operation complete.
- * @hide
- */
- @Override
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public void onDescriptorWrite(String address, int status, int handle,
- byte[] value) {
- if (VDBG) {
- Log.d(TAG,
- "onDescriptorWrite() - Device=" + address + " handle=" + handle);
- }
-
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
-
- BluetoothGattDescriptor descriptor = getDescriptorById(mDevice, handle);
- if (descriptor == null) return;
-
- if ((status == GATT_INSUFFICIENT_AUTHENTICATION
- || status == GATT_INSUFFICIENT_ENCRYPTION)
- && (mAuthRetryState != AUTH_RETRY_STATE_MITM)) {
- try {
- final int authReq = (mAuthRetryState == AUTH_RETRY_STATE_IDLE)
- ? AUTHENTICATION_NO_MITM : AUTHENTICATION_MITM;
- mService.writeDescriptor(mClientIf, address, handle,
- authReq, value, mAttributionSource);
- mAuthRetryState++;
- return;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- mAuthRetryState = AUTH_RETRY_STATE_IDLE;
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
- }
- }
- });
- }
-
- /**
- * Prepared write transaction completed (or aborted)
- * @hide
- */
- @Override
- public void onExecuteWrite(String address, int status) {
- if (VDBG) {
- Log.d(TAG, "onExecuteWrite() - Device=" + address
- + " status=" + status);
- }
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onReliableWriteCompleted(BluetoothGatt.this, status);
- }
- }
- });
- }
-
- /**
- * Remote device RSSI has been read
- * @hide
- */
- @Override
- public void onReadRemoteRssi(String address, int rssi, int status) {
- if (VDBG) {
- Log.d(TAG, "onReadRemoteRssi() - Device=" + address
- + " rssi=" + rssi + " status=" + status);
- }
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
- }
- }
- });
- }
-
- /**
- * Callback invoked when the MTU for a given connection changes
- * @hide
- */
- @Override
- public void onConfigureMTU(String address, int mtu, int status) {
- if (DBG) {
- Log.d(TAG, "onConfigureMTU() - Device=" + address
- + " mtu=" + mtu + " status=" + status);
- }
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onMtuChanged(BluetoothGatt.this, mtu, status);
- }
- }
- });
- }
-
- /**
- * Callback invoked when the given connection is updated
- * @hide
- */
- @Override
- public void onConnectionUpdated(String address, int interval, int latency,
- int timeout, int status) {
- if (DBG) {
- Log.d(TAG, "onConnectionUpdated() - Device=" + address
- + " interval=" + interval + " latency=" + latency
- + " timeout=" + timeout + " status=" + status);
- }
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
- timeout, status);
- }
- }
- });
- }
-
- /**
- * Callback invoked when service changed event is received
- * @hide
- */
- @Override
- public void onServiceChanged(String address) {
- if (DBG) {
- Log.d(TAG, "onServiceChanged() - Device=" + address);
- }
-
- if (!address.equals(mDevice.getAddress())) {
- return;
- }
-
- runOrQueueCallback(new Runnable() {
- @Override
- public void run() {
- final BluetoothGattCallback callback = mCallback;
- if (callback != null) {
- callback.onServiceChanged(BluetoothGatt.this);
- }
- }
- });
- }
- };
-
- /* package */ BluetoothGatt(IBluetoothGatt iGatt, BluetoothDevice device, int transport,
- boolean opportunistic, int phy, AttributionSource attributionSource) {
- mService = iGatt;
- mDevice = device;
- mTransport = transport;
- mPhy = phy;
- mOpportunistic = opportunistic;
- mAttributionSource = attributionSource;
- mServices = new ArrayList<BluetoothGattService>();
-
- mConnState = CONN_STATE_IDLE;
- mAuthRetryState = AUTH_RETRY_STATE_IDLE;
- }
-
- /**
- * Close this Bluetooth GATT client.
- *
- * Application should call this method as early as possible after it is done with
- * this GATT client.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void close() {
- if (DBG) Log.d(TAG, "close()");
-
- unregisterApp();
- mConnState = CONN_STATE_CLOSED;
- mAuthRetryState = AUTH_RETRY_STATE_IDLE;
- }
-
- /**
- * Returns a service by UUID, instance and type.
- *
- * @hide
- */
- /*package*/ BluetoothGattService getService(BluetoothDevice device, UUID uuid,
- int instanceId) {
- for (BluetoothGattService svc : mServices) {
- if (svc.getDevice().equals(device)
- && svc.getInstanceId() == instanceId
- && svc.getUuid().equals(uuid)) {
- return svc;
- }
- }
- return null;
- }
-
-
- /**
- * Returns a characteristic with id equal to instanceId.
- *
- * @hide
- */
- /*package*/ BluetoothGattCharacteristic getCharacteristicById(BluetoothDevice device,
- int instanceId) {
- for (BluetoothGattService svc : mServices) {
- for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
- if (charac.getInstanceId() == instanceId) {
- return charac;
- }
- }
- }
- return null;
- }
-
- /**
- * Returns a descriptor with id equal to instanceId.
- *
- * @hide
- */
- /*package*/ BluetoothGattDescriptor getDescriptorById(BluetoothDevice device, int instanceId) {
- for (BluetoothGattService svc : mServices) {
- for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
- for (BluetoothGattDescriptor desc : charac.getDescriptors()) {
- if (desc.getInstanceId() == instanceId) {
- return desc;
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Queue the runnable on a {@link Handler} provided by the user, or execute the runnable
- * immediately if no Handler was provided.
- */
- private void runOrQueueCallback(final Runnable cb) {
- if (mHandler == null) {
- try {
- cb.run();
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
- } else {
- mHandler.post(cb);
- }
- }
-
- /**
- * Register an application callback to start using GATT.
- *
- * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
- * is used to notify success or failure if the function returns true.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @return If true, the callback will be called to notify success or failure, false on immediate
- * error
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
- return registerApp(callback, handler, false);
- }
-
- /**
- * Register an application callback to start using GATT.
- *
- * <p>This is an asynchronous call. The callback {@link BluetoothGattCallback#onAppRegistered}
- * is used to notify success or failure if the function returns true.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @param eatt_support indicate to allow for eatt support
- * @return If true, the callback will be called to notify success or failure, false on immediate
- * error
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private boolean registerApp(BluetoothGattCallback callback, Handler handler,
- boolean eatt_support) {
- if (DBG) Log.d(TAG, "registerApp()");
- if (mService == null) return false;
-
- mCallback = callback;
- mHandler = handler;
- UUID uuid = UUID.randomUUID();
- if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
-
- try {
- mService.registerClient(
- new ParcelUuid(uuid), mBluetoothGattCallback, eatt_support, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Unregister the current application and callbacks.
- */
- @UnsupportedAppUsage
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private void unregisterApp() {
- if (DBG) Log.d(TAG, "unregisterApp() - mClientIf=" + mClientIf);
- if (mService == null || mClientIf == 0) return;
-
- try {
- mCallback = null;
- mService.unregisterClient(mClientIf, mAttributionSource);
- mClientIf = 0;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Initiate a connection to a Bluetooth GATT capable device.
- *
- * <p>The connection may not be established right away, but will be
- * completed when the remote device is available. A
- * {@link BluetoothGattCallback#onConnectionStateChange} callback will be
- * invoked when the connection state changes as a result of this function.
- *
- * <p>The autoConnect parameter determines whether to actively connect to
- * the remote device, or rather passively scan and finalize the connection
- * when the remote device is in range/available. Generally, the first ever
- * connection to a device should be direct (autoConnect set to false) and
- * subsequent connections to known devices should be invoked with the
- * autoConnect parameter set to true.
- *
- * @param device Remote device to connect to
- * @param autoConnect Whether to directly connect to the remote device (false) or to
- * automatically connect as soon as the remote device becomes available (true).
- * @return true, if the connection attempt was initiated successfully
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
- Handler handler) {
- if (DBG) {
- Log.d(TAG,
- "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
- }
- synchronized (mStateLock) {
- if (mConnState != CONN_STATE_IDLE) {
- throw new IllegalStateException("Not idle");
- }
- mConnState = CONN_STATE_CONNECTING;
- }
-
- mAutoConnect = autoConnect;
-
- if (!registerApp(callback, handler)) {
- synchronized (mStateLock) {
- mConnState = CONN_STATE_IDLE;
- }
- Log.e(TAG, "Failed to register callback");
- return false;
- }
-
- // The connection will continue in the onClientRegistered callback
- return true;
- }
-
- /**
- * Disconnects an established connection, or cancels a connection attempt
- * currently in progress.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void disconnect() {
- if (DBG) Log.d(TAG, "cancelOpen() - device: " + mDevice.getAddress());
- if (mService == null || mClientIf == 0) return;
-
- try {
- mService.clientDisconnect(mClientIf, mDevice.getAddress(), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Connect back to remote device.
- *
- * <p>This method is used to re-connect to a remote device after the
- * connection has been dropped. If the device is not in range, the
- * re-connection will be triggered once the device is back in range.
- *
- * @return true, if the connection attempt was initiated successfully
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean connect() {
- try {
- // autoConnect is inverse of "isDirect"
- mService.clientConnect(mClientIf, mDevice.getAddress(), false, mTransport,
- mOpportunistic, mPhy, mAttributionSource);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
- }
-
- /**
- * Set the preferred connection PHY for this app. Please note that this is just a
- * recommendation, whether the PHY change will happen depends on other applications preferences,
- * local and remote controller capabilities. Controller can override these settings.
- * <p>
- * {@link BluetoothGattCallback#onPhyUpdate} will be triggered as a result of this call, even
- * if no PHY change happens. It is also triggered when remote device updates the PHY.
- *
- * @param txPhy preferred transmitter PHY. Bitwise OR of any of {@link
- * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
- * BluetoothDevice#PHY_LE_CODED_MASK}.
- * @param rxPhy preferred receiver PHY. Bitwise OR of any of {@link
- * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
- * BluetoothDevice#PHY_LE_CODED_MASK}.
- * @param phyOptions preferred coding to use when transmitting on the LE Coded PHY. Can be one
- * of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or
- * {@link BluetoothDevice#PHY_OPTION_S8}
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setPreferredPhy(int txPhy, int rxPhy, int phyOptions) {
- try {
- mService.clientSetPreferredPhy(mClientIf, mDevice.getAddress(), txPhy, rxPhy,
- phyOptions, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Read the current transmitter PHY and receiver PHY of the connection. The values are returned
- * in {@link BluetoothGattCallback#onPhyRead}
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void readPhy() {
- try {
- mService.clientReadPhy(mClientIf, mDevice.getAddress(), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Return the remote bluetooth device this GATT client targets to
- *
- * @return remote bluetooth device
- */
- @RequiresNoPermission
- public BluetoothDevice getDevice() {
- return mDevice;
- }
-
- /**
- * Discovers services offered by a remote device as well as their
- * characteristics and descriptors.
- *
- * <p>This is an asynchronous operation. Once service discovery is completed,
- * the {@link BluetoothGattCallback#onServicesDiscovered} callback is
- * triggered. If the discovery was successful, the remote services can be
- * retrieved using the {@link #getServices} function.
- *
- * @return true, if the remote service discovery has been started
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean discoverServices() {
- if (DBG) Log.d(TAG, "discoverServices() - device: " + mDevice.getAddress());
- if (mService == null || mClientIf == 0) return false;
-
- mServices.clear();
-
- try {
- mService.discoverServices(mClientIf, mDevice.getAddress(), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Discovers a service by UUID. This is exposed only for passing PTS tests.
- * It should never be used by real applications. The service is not searched
- * for characteristics and descriptors, or returned in any callback.
- *
- * @return true, if the remote service discovery has been started
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean discoverServiceByUuid(UUID uuid) {
- if (DBG) Log.d(TAG, "discoverServiceByUuid() - device: " + mDevice.getAddress());
- if (mService == null || mClientIf == 0) return false;
-
- mServices.clear();
-
- try {
- mService.discoverServiceByUuid(
- mClientIf, mDevice.getAddress(), new ParcelUuid(uuid), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
- return true;
- }
-
- /**
- * Returns a list of GATT services offered by the remote device.
- *
- * <p>This function requires that service discovery has been completed
- * for the given device.
- *
- * @return List of services on the remote device. Returns an empty list if service discovery has
- * not yet been performed.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public List<BluetoothGattService> getServices() {
- List<BluetoothGattService> result =
- new ArrayList<BluetoothGattService>();
-
- for (BluetoothGattService service : mServices) {
- if (service.getDevice().equals(mDevice)) {
- result.add(service);
- }
- }
-
- return result;
- }
-
- /**
- * Returns a {@link BluetoothGattService}, if the requested UUID is
- * supported by the remote device.
- *
- * <p>This function requires that service discovery has been completed
- * for the given device.
- *
- * <p>If multiple instances of the same service (as identified by UUID)
- * exist, the first instance of the service is returned.
- *
- * @param uuid UUID of the requested service
- * @return BluetoothGattService if supported, or null if the requested service is not offered by
- * the remote device.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public BluetoothGattService getService(UUID uuid) {
- for (BluetoothGattService service : mServices) {
- if (service.getDevice().equals(mDevice) && service.getUuid().equals(uuid)) {
- return service;
- }
- }
-
- return null;
- }
-
- /**
- * Reads the requested characteristic from the associated remote device.
- *
- * <p>This is an asynchronous operation. The result of the read operation
- * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
- * BluetoothGattCharacteristic, byte[], int)} callback.
- *
- * @param characteristic Characteristic to read from the remote device
- * @return true, if the read operation was initiated successfully
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean readCharacteristic(BluetoothGattCharacteristic characteristic) {
- if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) == 0) {
- return false;
- }
-
- if (VDBG) Log.d(TAG, "readCharacteristic() - uuid: " + characteristic.getUuid());
- if (mService == null || mClientIf == 0) return false;
-
- BluetoothGattService service = characteristic.getService();
- if (service == null) return false;
-
- BluetoothDevice device = service.getDevice();
- if (device == null) return false;
-
- synchronized (mDeviceBusyLock) {
- if (mDeviceBusy) return false;
- mDeviceBusy = true;
- }
-
- try {
- mService.readCharacteristic(mClientIf, device.getAddress(),
- characteristic.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
- return false;
- }
-
- return true;
- }
-
- /**
- * Reads the characteristic using its UUID from the associated remote device.
- *
- * <p>This is an asynchronous operation. The result of the read operation
- * is reported by the {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
- * BluetoothGattCharacteristic, byte[], int)} callback.
- *
- * @param uuid UUID of characteristic to read from the remote device
- * @return true, if the read operation was initiated successfully
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
- if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
- if (mService == null || mClientIf == 0) return false;
-
- synchronized (mDeviceBusyLock) {
- if (mDeviceBusy) return false;
- mDeviceBusy = true;
- }
-
- try {
- mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(),
- new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE,
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
- return false;
- }
-
- return true;
- }
-
-
- /**
- * Writes a given characteristic and its values to the associated remote device.
- *
- * <p>Once the write operation has been completed, the
- * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
- * reporting the result of the operation.
- *
- * @param characteristic Characteristic to write on the remote device
- * @return true, if the write operation was initiated successfully
- * @throws IllegalArgumentException if characteristic or its value are null
- *
- * @deprecated Use {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[],
- * int)} as this is not memory safe.
- */
- @Deprecated
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic) {
- try {
- return writeCharacteristic(characteristic, characteristic.getValue(),
- characteristic.getWriteType()) == BluetoothStatusCodes.SUCCESS;
- } catch (Exception e) {
- return false;
- }
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothStatusCodes.SUCCESS,
- BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
- BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION,
- BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED,
- BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
- BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED,
- BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY,
- BluetoothStatusCodes.ERROR_UNKNOWN
- })
- public @interface WriteOperationReturnValues{}
-
- /**
- * Writes a given characteristic and its values to the associated remote device.
- *
- * <p>Once the write operation has been completed, the
- * {@link BluetoothGattCallback#onCharacteristicWrite} callback is invoked,
- * reporting the result of the operation.
- *
- * @param characteristic Characteristic to write on the remote device
- * @return whether the characteristic was successfully written to
- * @throws IllegalArgumentException if characteristic or value are null
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @WriteOperationReturnValues
- public int writeCharacteristic(@NonNull BluetoothGattCharacteristic characteristic,
- @NonNull byte[] value, int writeType) {
- if (characteristic == null) {
- throw new IllegalArgumentException("characteristic must not be null");
- }
- if (value == null) {
- throw new IllegalArgumentException("value must not be null");
- }
- if (VDBG) Log.d(TAG, "writeCharacteristic() - uuid: " + characteristic.getUuid());
- if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_WRITE) == 0
- && (characteristic.getProperties()
- & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) == 0) {
- return BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED;
- }
- if (mService == null || mClientIf == 0) {
- return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
- }
-
- BluetoothGattService service = characteristic.getService();
- if (service == null) {
- throw new IllegalArgumentException("Characteristic must have a non-null service");
- }
-
- BluetoothDevice device = service.getDevice();
- if (device == null) {
- throw new IllegalArgumentException("Service must have a non-null device");
- }
-
- synchronized (mDeviceBusyLock) {
- if (mDeviceBusy) {
- return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY;
- }
- mDeviceBusy = true;
- }
-
- int requestStatus = BluetoothStatusCodes.ERROR_UNKNOWN;
- try {
- for (int i = 0; i < WRITE_CHARACTERISTIC_MAX_RETRIES; i++) {
- requestStatus = mService.writeCharacteristic(mClientIf, device.getAddress(),
- characteristic.getInstanceId(), writeType, AUTHENTICATION_NONE, value,
- mAttributionSource);
- if (requestStatus != BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY) {
- break;
- }
- try {
- Thread.sleep(WRITE_CHARACTERISTIC_TIME_TO_WAIT);
- } catch (InterruptedException e) {
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
- throw e.rethrowFromSystemServer();
- }
-
- return requestStatus;
- }
-
- /**
- * Reads the value for a given descriptor from the associated remote device.
- *
- * <p>Once the read operation has been completed, the
- * {@link BluetoothGattCallback#onDescriptorRead} callback is
- * triggered, signaling the result of the operation.
- *
- * @param descriptor Descriptor value to read from the remote device
- * @return true, if the read operation was initiated successfully
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean readDescriptor(BluetoothGattDescriptor descriptor) {
- if (VDBG) Log.d(TAG, "readDescriptor() - uuid: " + descriptor.getUuid());
- if (mService == null || mClientIf == 0) return false;
-
- BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
- if (characteristic == null) return false;
-
- BluetoothGattService service = characteristic.getService();
- if (service == null) return false;
-
- BluetoothDevice device = service.getDevice();
- if (device == null) return false;
-
- synchronized (mDeviceBusyLock) {
- if (mDeviceBusy) return false;
- mDeviceBusy = true;
- }
-
- try {
- mService.readDescriptor(mClientIf, device.getAddress(),
- descriptor.getInstanceId(), AUTHENTICATION_NONE, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
- return false;
- }
-
- return true;
- }
-
- /**
- * Write the value of a given descriptor to the associated remote device.
- *
- * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the
- * result of the write operation.
- *
- * @param descriptor Descriptor to write to the associated remote device
- * @return true, if the write operation was initiated successfully
- * @throws IllegalArgumentException if descriptor or its value are null
- *
- * @deprecated Use {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])} as
- * this is not memory safe.
- */
- @Deprecated
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean writeDescriptor(BluetoothGattDescriptor descriptor) {
- try {
- return writeDescriptor(descriptor, descriptor.getValue())
- == BluetoothStatusCodes.SUCCESS;
- } catch (Exception e) {
- return false;
- }
- }
-
- /**
- * Write the value of a given descriptor to the associated remote device.
- *
- * <p>A {@link BluetoothGattCallback#onDescriptorWrite} callback is triggered to report the
- * result of the write operation.
- *
- * @param descriptor Descriptor to write to the associated remote device
- * @return true, if the write operation was initiated successfully
- * @throws IllegalArgumentException if descriptor or value are null
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @WriteOperationReturnValues
- public int writeDescriptor(@NonNull BluetoothGattDescriptor descriptor,
- @NonNull byte[] value) {
- if (descriptor == null) {
- throw new IllegalArgumentException("descriptor must not be null");
- }
- if (value == null) {
- throw new IllegalArgumentException("value must not be null");
- }
- if (VDBG) Log.d(TAG, "writeDescriptor() - uuid: " + descriptor.getUuid());
- if (mService == null || mClientIf == 0) {
- return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
- }
-
- BluetoothGattCharacteristic characteristic = descriptor.getCharacteristic();
- if (characteristic == null) {
- throw new IllegalArgumentException("Descriptor must have a non-null characteristic");
- }
-
- BluetoothGattService service = characteristic.getService();
- if (service == null) {
- throw new IllegalArgumentException("Characteristic must have a non-null service");
- }
-
- BluetoothDevice device = service.getDevice();
- if (device == null) {
- throw new IllegalArgumentException("Service must have a non-null device");
- }
-
- synchronized (mDeviceBusyLock) {
- if (mDeviceBusy) return BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY;
- mDeviceBusy = true;
- }
-
- try {
- return mService.writeDescriptor(mClientIf, device.getAddress(),
- descriptor.getInstanceId(), AUTHENTICATION_NONE, value, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
- e.rethrowFromSystemServer();
- }
- return BluetoothStatusCodes.ERROR_UNKNOWN;
- }
-
- /**
- * Initiates a reliable write transaction for a given remote device.
- *
- * <p>Once a reliable write transaction has been initiated, all calls
- * to {@link #writeCharacteristic} are sent to the remote device for
- * verification and queued up for atomic execution. The application will
- * receive a {@link BluetoothGattCallback#onCharacteristicWrite} callback in response to every
- * {@link #writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} call and is
- * responsible for verifying if the value has been transmitted accurately.
- *
- * <p>After all characteristics have been queued up and verified,
- * {@link #executeReliableWrite} will execute all writes. If a characteristic
- * was not written correctly, calling {@link #abortReliableWrite} will
- * cancel the current transaction without committing any values on the
- * remote device.
- *
- * @return true, if the reliable write transaction has been initiated
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean beginReliableWrite() {
- if (VDBG) Log.d(TAG, "beginReliableWrite() - device: " + mDevice.getAddress());
- if (mService == null || mClientIf == 0) return false;
-
- try {
- mService.beginReliableWrite(mClientIf, mDevice.getAddress(), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Executes a reliable write transaction for a given remote device.
- *
- * <p>This function will commit all queued up characteristic write
- * operations for a given remote device.
- *
- * <p>A {@link BluetoothGattCallback#onReliableWriteCompleted} callback is
- * invoked to indicate whether the transaction has been executed correctly.
- *
- * @return true, if the request to execute the transaction has been sent
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean executeReliableWrite() {
- if (VDBG) Log.d(TAG, "executeReliableWrite() - device: " + mDevice.getAddress());
- if (mService == null || mClientIf == 0) return false;
-
- synchronized (mDeviceBusyLock) {
- if (mDeviceBusy) return false;
- mDeviceBusy = true;
- }
-
- try {
- mService.endReliableWrite(mClientIf, mDevice.getAddress(), true, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- synchronized (mDeviceBusyLock) {
- mDeviceBusy = false;
- }
- return false;
- }
-
- return true;
- }
-
- /**
- * Cancels a reliable write transaction for a given device.
- *
- * <p>Calling this function will discard all queued characteristic write
- * operations for a given remote device.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void abortReliableWrite() {
- if (VDBG) Log.d(TAG, "abortReliableWrite() - device: " + mDevice.getAddress());
- if (mService == null || mClientIf == 0) return;
-
- try {
- mService.endReliableWrite(mClientIf, mDevice.getAddress(), false, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * @deprecated Use {@link #abortReliableWrite()}
- */
- @Deprecated
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void abortReliableWrite(BluetoothDevice mDevice) {
- abortReliableWrite();
- }
-
- /**
- * Enable or disable notifications/indications for a given characteristic.
- *
- * <p>Once notifications are enabled for a characteristic, a
- * {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt,
- * BluetoothGattCharacteristic, byte[])} callback will be triggered if the remote device
- * indicates that the given characteristic has changed.
- *
- * @param characteristic The characteristic for which to enable notifications
- * @param enable Set to true to enable notifications/indications
- * @return true, if the requested notification status was set successfully
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,
- boolean enable) {
- if (DBG) {
- Log.d(TAG, "setCharacteristicNotification() - uuid: " + characteristic.getUuid()
- + " enable: " + enable);
- }
- if (mService == null || mClientIf == 0) return false;
-
- BluetoothGattService service = characteristic.getService();
- if (service == null) return false;
-
- BluetoothDevice device = service.getDevice();
- if (device == null) return false;
-
- try {
- mService.registerForNotification(mClientIf, device.getAddress(),
- characteristic.getInstanceId(), enable, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Clears the internal cache and forces a refresh of the services from the
- * remote device.
- *
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean refresh() {
- if (DBG) Log.d(TAG, "refresh() - device: " + mDevice.getAddress());
- if (mService == null || mClientIf == 0) return false;
-
- try {
- mService.refreshDevice(mClientIf, mDevice.getAddress(), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Read the RSSI for a connected remote device.
- *
- * <p>The {@link BluetoothGattCallback#onReadRemoteRssi} callback will be
- * invoked when the RSSI value has been read.
- *
- * @return true, if the RSSI value has been requested successfully
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean readRemoteRssi() {
- if (DBG) Log.d(TAG, "readRssi() - device: " + mDevice.getAddress());
- if (mService == null || mClientIf == 0) return false;
-
- try {
- mService.readRemoteRssi(mClientIf, mDevice.getAddress(), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Request an MTU size used for a given connection.
- *
- * <p>When performing a write request operation (write without response),
- * the data sent is truncated to the MTU size. This function may be used
- * to request a larger MTU size to be able to send more data at once.
- *
- * <p>A {@link BluetoothGattCallback#onMtuChanged} callback will indicate
- * whether this operation was successful.
- *
- * @return true, if the new MTU value has been requested successfully
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean requestMtu(int mtu) {
- if (DBG) {
- Log.d(TAG, "configureMTU() - device: " + mDevice.getAddress()
- + " mtu: " + mtu);
- }
- if (mService == null || mClientIf == 0) return false;
-
- try {
- mService.configureMTU(mClientIf, mDevice.getAddress(), mtu, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Request a connection parameter update.
- *
- * <p>This function will send a connection parameter update request to the
- * remote device.
- *
- * @param connectionPriority Request a specific connection priority. Must be one of {@link
- * BluetoothGatt#CONNECTION_PRIORITY_BALANCED}, {@link BluetoothGatt#CONNECTION_PRIORITY_HIGH}
- * or {@link BluetoothGatt#CONNECTION_PRIORITY_LOW_POWER}.
- * @throws IllegalArgumentException If the parameters are outside of their specified range.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean requestConnectionPriority(int connectionPriority) {
- if (connectionPriority < CONNECTION_PRIORITY_BALANCED
- || connectionPriority > CONNECTION_PRIORITY_LOW_POWER) {
- throw new IllegalArgumentException("connectionPriority not within valid range");
- }
-
- if (DBG) Log.d(TAG, "requestConnectionPriority() - params: " + connectionPriority);
- if (mService == null || mClientIf == 0) return false;
-
- try {
- mService.connectionParameterUpdate(
- mClientIf, mDevice.getAddress(), connectionPriority, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Request an LE connection parameter update.
- *
- * <p>This function will send an LE connection parameters update request to the remote device.
- *
- * @return true, if the request is send to the Bluetooth stack.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean requestLeConnectionUpdate(int minConnectionInterval, int maxConnectionInterval,
- int slaveLatency, int supervisionTimeout,
- int minConnectionEventLen, int maxConnectionEventLen) {
- if (DBG) {
- Log.d(TAG, "requestLeConnectionUpdate() - min=(" + minConnectionInterval
- + ")" + (1.25 * minConnectionInterval)
- + "msec, max=(" + maxConnectionInterval + ")"
- + (1.25 * maxConnectionInterval) + "msec, latency=" + slaveLatency
- + ", timeout=" + supervisionTimeout + "msec" + ", min_ce="
- + minConnectionEventLen + ", max_ce=" + maxConnectionEventLen);
- }
- if (mService == null || mClientIf == 0) return false;
-
- try {
- mService.leConnectionUpdate(mClientIf, mDevice.getAddress(),
- minConnectionInterval, maxConnectionInterval,
- slaveLatency, supervisionTimeout,
- minConnectionEventLen, maxConnectionEventLen,
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
- * with {@link BluetoothProfile#GATT} as argument
- * @throws UnsupportedOperationException
- */
- @Override
- @RequiresNoPermission
- @Deprecated
- public int getConnectionState(BluetoothDevice device) {
- throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
- }
-
- /**
- * @deprecated Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
- * with {@link BluetoothProfile#GATT} as argument
- *
- * @throws UnsupportedOperationException
- */
- @Override
- @RequiresNoPermission
- @Deprecated
- public List<BluetoothDevice> getConnectedDevices() {
- throw new UnsupportedOperationException(
- "Use BluetoothManager#getConnectedDevices instead.");
- }
-
- /**
- * @deprecated Not supported - please use
- * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
- * with {@link BluetoothProfile#GATT} as first argument
- *
- * @throws UnsupportedOperationException
- */
- @Override
- @RequiresNoPermission
- @Deprecated
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- throw new UnsupportedOperationException(
- "Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
deleted file mode 100644
index d0a5a1e..0000000
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.NonNull;
-
-/**
- * This abstract class is used to implement {@link BluetoothGatt} callbacks.
- */
-public abstract class BluetoothGattCallback {
-
- /**
- * Callback triggered as result of {@link BluetoothGatt#setPreferredPhy}, or as a result of
- * remote device changing the PHY.
- *
- * @param gatt GATT client
- * @param txPhy the transmitter PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
- * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
- * @param status Status of the PHY update operation. {@link BluetoothGatt#GATT_SUCCESS} if the
- * operation succeeds.
- */
- public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
- }
-
- /**
- * Callback triggered as result of {@link BluetoothGatt#readPhy}
- *
- * @param gatt GATT client
- * @param txPhy the transmitter PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
- * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
- * @param status Status of the PHY read operation. {@link BluetoothGatt#GATT_SUCCESS} if the
- * operation succeeds.
- */
- public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
- }
-
- /**
- * Callback indicating when GATT client has connected/disconnected to/from a remote
- * GATT server.
- *
- * @param gatt GATT client
- * @param status Status of the connect or disconnect operation. {@link
- * BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
- * @param newState Returns the new connection state. Can be one of {@link
- * BluetoothProfile#STATE_DISCONNECTED} or {@link BluetoothProfile#STATE_CONNECTED}
- */
- public void onConnectionStateChange(BluetoothGatt gatt, int status,
- int newState) {
- }
-
- /**
- * Callback invoked when the list of remote services, characteristics and descriptors
- * for the remote device have been updated, ie new services have been discovered.
- *
- * @param gatt GATT client invoked {@link BluetoothGatt#discoverServices}
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the remote device has been explored
- * successfully.
- */
- public void onServicesDiscovered(BluetoothGatt gatt, int status) {
- }
-
- /**
- * Callback reporting the result of a characteristic read operation.
- *
- * @param gatt GATT client invoked
- * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)}
- * @param characteristic Characteristic that was read from the associated remote device.
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
- * successfully.
- * @deprecated Use {@link BluetoothGattCallback#onCharacteristicRead(BluetoothGatt,
- * BluetoothGattCharacteristic, byte[], int)} as it is memory safe
- */
- @Deprecated
- public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
- int status) {
- }
-
- /**
- * Callback reporting the result of a characteristic read operation.
- *
- * @param gatt GATT client invoked
- * {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)}
- * @param characteristic Characteristic that was read from the associated remote device.
- * @param value the value of the characteristic
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
- * successfully.
- */
- public void onCharacteristicRead(@NonNull BluetoothGatt gatt, @NonNull
- BluetoothGattCharacteristic characteristic, @NonNull byte[] value, int status) {
- }
-
- /**
- * Callback indicating the result of a characteristic write operation.
- *
- * <p>If this callback is invoked while a reliable write transaction is
- * in progress, the value of the characteristic represents the value
- * reported by the remote device. An application should compare this
- * value to the desired value to be written. If the values don't match,
- * the application must abort the reliable write transaction.
- *
- * @param gatt GATT client that invoked
- * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic,
- * byte[], int)}
- * @param characteristic Characteristic that was written to the associated remote device.
- * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if
- * the
- * operation succeeds.
- */
- public void onCharacteristicWrite(BluetoothGatt gatt,
- BluetoothGattCharacteristic characteristic, int status) {
- }
-
- /**
- * Callback triggered as a result of a remote characteristic notification.
- *
- * @param gatt GATT client the characteristic is associated with
- * @param characteristic Characteristic that has been updated as a result of a remote
- * notification event.
- * @deprecated Use {@link BluetoothGattCallback#onCharacteristicChanged(BluetoothGatt,
- * BluetoothGattCharacteristic, byte[])} as it is memory safe by providing the characteristic
- * value at the time of notification.
- */
- @Deprecated
- public void onCharacteristicChanged(BluetoothGatt gatt,
- BluetoothGattCharacteristic characteristic) {
- }
-
- /**
- * Callback triggered as a result of a remote characteristic notification. Note that the value
- * within the characteristic object may have changed since receiving the remote characteristic
- * notification, so check the parameter value for the value at the time of notification.
- *
- * @param gatt GATT client the characteristic is associated with
- * @param characteristic Characteristic that has been updated as a result of a remote
- * notification event.
- * @param value notified characteristic value
- */
- public void onCharacteristicChanged(@NonNull BluetoothGatt gatt,
- @NonNull BluetoothGattCharacteristic characteristic, @NonNull byte[] value) {
- }
-
- /**
- * Callback reporting the result of a descriptor read operation.
- *
- * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor}
- * @param descriptor Descriptor that was read from the associated remote device.
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
- * successfully
- * @deprecated Use {@link BluetoothGattCallback#onDescriptorRead(BluetoothGatt,
- * BluetoothGattDescriptor, int, byte[])} as it is memory safe by providing the descriptor
- * value at the time it was read.
- */
- @Deprecated
- public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
- int status) {
- }
-
- /**
- * Callback reporting the result of a descriptor read operation.
- *
- * @param gatt GATT client invoked {@link BluetoothGatt#readDescriptor}
- * @param descriptor Descriptor that was read from the associated remote device.
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the read operation was completed
- * successfully
- * @param value the descriptor value at the time of the read operation
- */
- public void onDescriptorRead(@NonNull BluetoothGatt gatt,
- @NonNull BluetoothGattDescriptor descriptor, int status, @NonNull byte[] value) {
- }
-
- /**
- * Callback indicating the result of a descriptor write operation.
- *
- * @param gatt GATT client invoked {@link BluetoothGatt#writeDescriptor}
- * @param descriptor Descriptor that was writte to the associated remote device.
- * @param status The result of the write operation {@link BluetoothGatt#GATT_SUCCESS} if the
- * operation succeeds.
- */
- public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
- int status) {
- }
-
- /**
- * Callback invoked when a reliable write transaction has been completed.
- *
- * @param gatt GATT client invoked {@link BluetoothGatt#executeReliableWrite}
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the reliable write transaction was
- * executed successfully
- */
- public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
- }
-
- /**
- * Callback reporting the RSSI for a remote device connection.
- *
- * This callback is triggered in response to the
- * {@link BluetoothGatt#readRemoteRssi} function.
- *
- * @param gatt GATT client invoked {@link BluetoothGatt#readRemoteRssi}
- * @param rssi The RSSI value for the remote device
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the RSSI was read successfully
- */
- public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
- }
-
- /**
- * Callback indicating the MTU for a given device connection has changed.
- *
- * This callback is triggered in response to the
- * {@link BluetoothGatt#requestMtu} function, or in response to a connection
- * event.
- *
- * @param gatt GATT client invoked {@link BluetoothGatt#requestMtu}
- * @param mtu The new MTU size
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the MTU has been changed successfully
- */
- public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
- }
-
- /**
- * Callback indicating the connection parameters were updated.
- *
- * @param gatt GATT client involved
- * @param interval Connection interval used on this connection, 1.25ms unit. Valid range is from
- * 6 (7.5ms) to 3200 (4000ms).
- * @param latency Worker latency for the connection in number of connection events. Valid range
- * is from 0 to 499
- * @param timeout Supervision timeout for this connection, in 10ms unit. Valid range is from 10
- * (0.1s) to 3200 (32s)
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the connection has been updated
- * successfully
- * @hide
- */
- public void onConnectionUpdated(BluetoothGatt gatt, int interval, int latency, int timeout,
- int status) {
- }
-
- /**
- * Callback indicating service changed event is received
- *
- * <p>Receiving this event means that the GATT database is out of sync with
- * the remote device. {@link BluetoothGatt#discoverServices} should be
- * called to re-discover the services.
- *
- * @param gatt GATT client involved
- */
- public void onServiceChanged(@NonNull BluetoothGatt gatt) {
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothGattCharacteristic.java b/core/java/android/bluetooth/BluetoothGattCharacteristic.java
deleted file mode 100644
index c5e986e..0000000
--- a/core/java/android/bluetooth/BluetoothGattCharacteristic.java
+++ /dev/null
@@ -1,806 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.bluetooth;
-
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Represents a Bluetooth GATT Characteristic
- *
- * <p>A GATT characteristic is a basic data element used to construct a GATT service,
- * {@link BluetoothGattService}. The characteristic contains a value as well as
- * additional information and optional GATT descriptors, {@link BluetoothGattDescriptor}.
- */
-public class BluetoothGattCharacteristic implements Parcelable {
-
- /**
- * Characteristic proprty: Characteristic is broadcastable.
- */
- public static final int PROPERTY_BROADCAST = 0x01;
-
- /**
- * Characteristic property: Characteristic is readable.
- */
- public static final int PROPERTY_READ = 0x02;
-
- /**
- * Characteristic property: Characteristic can be written without response.
- */
- public static final int PROPERTY_WRITE_NO_RESPONSE = 0x04;
-
- /**
- * Characteristic property: Characteristic can be written.
- */
- public static final int PROPERTY_WRITE = 0x08;
-
- /**
- * Characteristic property: Characteristic supports notification
- */
- public static final int PROPERTY_NOTIFY = 0x10;
-
- /**
- * Characteristic property: Characteristic supports indication
- */
- public static final int PROPERTY_INDICATE = 0x20;
-
- /**
- * Characteristic property: Characteristic supports write with signature
- */
- public static final int PROPERTY_SIGNED_WRITE = 0x40;
-
- /**
- * Characteristic property: Characteristic has extended properties
- */
- public static final int PROPERTY_EXTENDED_PROPS = 0x80;
-
- /**
- * Characteristic read permission
- */
- public static final int PERMISSION_READ = 0x01;
-
- /**
- * Characteristic permission: Allow encrypted read operations
- */
- public static final int PERMISSION_READ_ENCRYPTED = 0x02;
-
- /**
- * Characteristic permission: Allow reading with person-in-the-middle protection
- */
- public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04;
-
- /**
- * Characteristic write permission
- */
- public static final int PERMISSION_WRITE = 0x10;
-
- /**
- * Characteristic permission: Allow encrypted writes
- */
- public static final int PERMISSION_WRITE_ENCRYPTED = 0x20;
-
- /**
- * Characteristic permission: Allow encrypted writes with person-in-the-middle
- * protection
- */
- public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40;
-
- /**
- * Characteristic permission: Allow signed write operations
- */
- public static final int PERMISSION_WRITE_SIGNED = 0x80;
-
- /**
- * Characteristic permission: Allow signed write operations with
- * person-in-the-middle protection
- */
- public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100;
-
- /**
- * Write characteristic, requesting acknoledgement by the remote device
- */
- public static final int WRITE_TYPE_DEFAULT = 0x02;
-
- /**
- * Write characteristic without requiring a response by the remote device
- */
- public static final int WRITE_TYPE_NO_RESPONSE = 0x01;
-
- /**
- * Write characteristic including authentication signature
- */
- public static final int WRITE_TYPE_SIGNED = 0x04;
-
- /**
- * Characteristic value format type uint8
- */
- public static final int FORMAT_UINT8 = 0x11;
-
- /**
- * Characteristic value format type uint16
- */
- public static final int FORMAT_UINT16 = 0x12;
-
- /**
- * Characteristic value format type uint32
- */
- public static final int FORMAT_UINT32 = 0x14;
-
- /**
- * Characteristic value format type sint8
- */
- public static final int FORMAT_SINT8 = 0x21;
-
- /**
- * Characteristic value format type sint16
- */
- public static final int FORMAT_SINT16 = 0x22;
-
- /**
- * Characteristic value format type sint32
- */
- public static final int FORMAT_SINT32 = 0x24;
-
- /**
- * Characteristic value format type sfloat (16-bit float)
- */
- public static final int FORMAT_SFLOAT = 0x32;
-
- /**
- * Characteristic value format type float (32-bit float)
- */
- public static final int FORMAT_FLOAT = 0x34;
-
-
- /**
- * The UUID of this characteristic.
- *
- * @hide
- */
- protected UUID mUuid;
-
- /**
- * Instance ID for this characteristic.
- *
- * @hide
- */
- @UnsupportedAppUsage
- protected int mInstance;
-
- /**
- * Characteristic properties.
- *
- * @hide
- */
- protected int mProperties;
-
- /**
- * Characteristic permissions.
- *
- * @hide
- */
- protected int mPermissions;
-
- /**
- * Key size (default = 16).
- *
- * @hide
- */
- protected int mKeySize = 16;
-
- /**
- * Write type for this characteristic.
- * See WRITE_TYPE_* constants.
- *
- * @hide
- */
- protected int mWriteType;
-
- /**
- * Back-reference to the service this characteristic belongs to.
- *
- * @hide
- */
- @UnsupportedAppUsage
- protected BluetoothGattService mService;
-
- /**
- * The cached value of this characteristic.
- *
- * @hide
- */
- protected byte[] mValue;
-
- /**
- * List of descriptors included in this characteristic.
- */
- protected List<BluetoothGattDescriptor> mDescriptors;
-
- /**
- * Create a new BluetoothGattCharacteristic.
- *
- * @param uuid The UUID for this characteristic
- * @param properties Properties of this characteristic
- * @param permissions Permissions for this characteristic
- */
- public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions) {
- initCharacteristic(null, uuid, 0, properties, permissions);
- }
-
- /**
- * Create a new BluetoothGattCharacteristic
- *
- * @hide
- */
- /*package*/ BluetoothGattCharacteristic(BluetoothGattService service,
- UUID uuid, int instanceId,
- int properties, int permissions) {
- initCharacteristic(service, uuid, instanceId, properties, permissions);
- }
-
- /**
- * Create a new BluetoothGattCharacteristic
- *
- * @hide
- */
- public BluetoothGattCharacteristic(UUID uuid, int instanceId,
- int properties, int permissions) {
- initCharacteristic(null, uuid, instanceId, properties, permissions);
- }
-
- private void initCharacteristic(BluetoothGattService service,
- UUID uuid, int instanceId,
- int properties, int permissions) {
- mUuid = uuid;
- mInstance = instanceId;
- mProperties = properties;
- mPermissions = permissions;
- mService = service;
- mValue = null;
- mDescriptors = new ArrayList<BluetoothGattDescriptor>();
-
- if ((mProperties & PROPERTY_WRITE_NO_RESPONSE) != 0) {
- mWriteType = WRITE_TYPE_NO_RESPONSE;
- } else {
- mWriteType = WRITE_TYPE_DEFAULT;
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeParcelable(new ParcelUuid(mUuid), 0);
- out.writeInt(mInstance);
- out.writeInt(mProperties);
- out.writeInt(mPermissions);
- out.writeInt(mKeySize);
- out.writeInt(mWriteType);
- out.writeTypedList(mDescriptors);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothGattCharacteristic> CREATOR =
- new Parcelable.Creator<BluetoothGattCharacteristic>() {
- public BluetoothGattCharacteristic createFromParcel(Parcel in) {
- return new BluetoothGattCharacteristic(in);
- }
-
- public BluetoothGattCharacteristic[] newArray(int size) {
- return new BluetoothGattCharacteristic[size];
- }
- };
-
- private BluetoothGattCharacteristic(Parcel in) {
- mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
- mInstance = in.readInt();
- mProperties = in.readInt();
- mPermissions = in.readInt();
- mKeySize = in.readInt();
- mWriteType = in.readInt();
-
- mDescriptors = new ArrayList<BluetoothGattDescriptor>();
-
- ArrayList<BluetoothGattDescriptor> descs =
- in.createTypedArrayList(BluetoothGattDescriptor.CREATOR);
- if (descs != null) {
- for (BluetoothGattDescriptor desc : descs) {
- desc.setCharacteristic(this);
- mDescriptors.add(desc);
- }
- }
- }
-
- /**
- * Returns the desired key size.
- *
- * @hide
- */
- public int getKeySize() {
- return mKeySize;
- }
-
- /**
- * Adds a descriptor to this characteristic.
- *
- * @param descriptor Descriptor to be added to this characteristic.
- * @return true, if the descriptor was added to the characteristic
- */
- public boolean addDescriptor(BluetoothGattDescriptor descriptor) {
- mDescriptors.add(descriptor);
- descriptor.setCharacteristic(this);
- return true;
- }
-
- /**
- * Get a descriptor by UUID and isntance id.
- *
- * @hide
- */
- /*package*/ BluetoothGattDescriptor getDescriptor(UUID uuid, int instanceId) {
- for (BluetoothGattDescriptor descriptor : mDescriptors) {
- if (descriptor.getUuid().equals(uuid)
- && descriptor.getInstanceId() == instanceId) {
- return descriptor;
- }
- }
- return null;
- }
-
- /**
- * Returns the service this characteristic belongs to.
- *
- * @return The asscociated service
- */
- public BluetoothGattService getService() {
- return mService;
- }
-
- /**
- * Sets the service associated with this device.
- *
- * @hide
- */
- @UnsupportedAppUsage
- /*package*/ void setService(BluetoothGattService service) {
- mService = service;
- }
-
- /**
- * Returns the UUID of this characteristic
- *
- * @return UUID of this characteristic
- */
- public UUID getUuid() {
- return mUuid;
- }
-
- /**
- * Returns the instance ID for this characteristic.
- *
- * <p>If a remote device offers multiple characteristics with the same UUID,
- * the instance ID is used to distuinguish between characteristics.
- *
- * @return Instance ID of this characteristic
- */
- public int getInstanceId() {
- return mInstance;
- }
-
- /**
- * Force the instance ID.
- *
- * @hide
- */
- public void setInstanceId(int instanceId) {
- mInstance = instanceId;
- }
-
- /**
- * Returns the properties of this characteristic.
- *
- * <p>The properties contain a bit mask of property flags indicating
- * the features of this characteristic.
- *
- * @return Properties of this characteristic
- */
- public int getProperties() {
- return mProperties;
- }
-
- /**
- * Returns the permissions for this characteristic.
- *
- * @return Permissions of this characteristic
- */
- public int getPermissions() {
- return mPermissions;
- }
-
- /**
- * Gets the write type for this characteristic.
- *
- * @return Write type for this characteristic
- */
- public int getWriteType() {
- return mWriteType;
- }
-
- /**
- * Set the write type for this characteristic
- *
- * <p>Setting the write type of a characteristic determines how the
- * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)} function
- * write this characteristic.
- *
- * @param writeType The write type to for this characteristic. Can be one of: {@link
- * #WRITE_TYPE_DEFAULT}, {@link #WRITE_TYPE_NO_RESPONSE} or {@link #WRITE_TYPE_SIGNED}.
- */
- public void setWriteType(int writeType) {
- mWriteType = writeType;
- }
-
- /**
- * Set the desired key size.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public void setKeySize(int keySize) {
- mKeySize = keySize;
- }
-
- /**
- * Returns a list of descriptors for this characteristic.
- *
- * @return Descriptors for this characteristic
- */
- public List<BluetoothGattDescriptor> getDescriptors() {
- return mDescriptors;
- }
-
- /**
- * Returns a descriptor with a given UUID out of the list of
- * descriptors for this characteristic.
- *
- * @return GATT descriptor object or null if no descriptor with the given UUID was found.
- */
- public BluetoothGattDescriptor getDescriptor(UUID uuid) {
- for (BluetoothGattDescriptor descriptor : mDescriptors) {
- if (descriptor.getUuid().equals(uuid)) {
- return descriptor;
- }
- }
- return null;
- }
-
- /**
- * Get the stored value for this characteristic.
- *
- * <p>This function returns the stored value for this characteristic as
- * retrieved by calling {@link BluetoothGatt#readCharacteristic}. The cached
- * value of the characteristic is updated as a result of a read characteristic
- * operation or if a characteristic update notification has been received.
- *
- * @return Cached value of the characteristic
- *
- * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} instead
- */
- @Deprecated
- public byte[] getValue() {
- return mValue;
- }
-
- /**
- * Return the stored value of this characteristic.
- *
- * <p>The formatType parameter determines how the characteristic value
- * is to be interpreted. For example, settting formatType to
- * {@link #FORMAT_UINT16} specifies that the first two bytes of the
- * characteristic value at the given offset are interpreted to generate the
- * return value.
- *
- * @param formatType The format type used to interpret the characteristic value.
- * @param offset Offset at which the integer value can be found.
- * @return Cached value of the characteristic or null of offset exceeds value size.
- *
- * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
- * the characteristic value
- */
- @Deprecated
- public Integer getIntValue(int formatType, int offset) {
- if ((offset + getTypeLen(formatType)) > mValue.length) return null;
-
- switch (formatType) {
- case FORMAT_UINT8:
- return unsignedByteToInt(mValue[offset]);
-
- case FORMAT_UINT16:
- return unsignedBytesToInt(mValue[offset], mValue[offset + 1]);
-
- case FORMAT_UINT32:
- return unsignedBytesToInt(mValue[offset], mValue[offset + 1],
- mValue[offset + 2], mValue[offset + 3]);
- case FORMAT_SINT8:
- return unsignedToSigned(unsignedByteToInt(mValue[offset]), 8);
-
- case FORMAT_SINT16:
- return unsignedToSigned(unsignedBytesToInt(mValue[offset],
- mValue[offset + 1]), 16);
-
- case FORMAT_SINT32:
- return unsignedToSigned(unsignedBytesToInt(mValue[offset],
- mValue[offset + 1], mValue[offset + 2], mValue[offset + 3]), 32);
- }
-
- return null;
- }
-
- /**
- * Return the stored value of this characteristic.
- * <p>See {@link #getValue} for details.
- *
- * @param formatType The format type used to interpret the characteristic value.
- * @param offset Offset at which the float value can be found.
- * @return Cached value of the characteristic at a given offset or null if the requested offset
- * exceeds the value size.
- *
- * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
- * the characteristic value
- */
- @Deprecated
- public Float getFloatValue(int formatType, int offset) {
- if ((offset + getTypeLen(formatType)) > mValue.length) return null;
-
- switch (formatType) {
- case FORMAT_SFLOAT:
- return bytesToFloat(mValue[offset], mValue[offset + 1]);
-
- case FORMAT_FLOAT:
- return bytesToFloat(mValue[offset], mValue[offset + 1],
- mValue[offset + 2], mValue[offset + 3]);
- }
-
- return null;
- }
-
- /**
- * Return the stored value of this characteristic.
- * <p>See {@link #getValue} for details.
- *
- * @param offset Offset at which the string value can be found.
- * @return Cached value of the characteristic
- *
- * @deprecated Use {@link BluetoothGatt#readCharacteristic(BluetoothGattCharacteristic)} to get
- * the characteristic value
- */
- @Deprecated
- public String getStringValue(int offset) {
- if (mValue == null || offset > mValue.length) return null;
- byte[] strBytes = new byte[mValue.length - offset];
- for (int i = 0; i != (mValue.length - offset); ++i) strBytes[i] = mValue[offset + i];
- return new String(strBytes);
- }
-
- /**
- * Updates the locally stored value of this characteristic.
- *
- * <p>This function modifies the locally stored cached value of this
- * characteristic. To send the value to the remote device, call
- * {@link BluetoothGatt#writeCharacteristic} to send the value to the
- * remote device.
- *
- * @param value New value for this characteristic
- * @return true if the locally stored value has been set, false if the requested value could not
- * be stored locally.
- *
- * @deprecated Pass the characteristic value directly into
- * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
- */
- @Deprecated
- public boolean setValue(byte[] value) {
- mValue = value;
- return true;
- }
-
- /**
- * Set the locally stored value of this characteristic.
- * <p>See {@link #setValue(byte[])} for details.
- *
- * @param value New value for this characteristic
- * @param formatType Integer format type used to transform the value parameter
- * @param offset Offset at which the value should be placed
- * @return true if the locally stored value has been set
- *
- * @deprecated Pass the characteristic value directly into
- * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
- */
- @Deprecated
- public boolean setValue(int value, int formatType, int offset) {
- int len = offset + getTypeLen(formatType);
- if (mValue == null) mValue = new byte[len];
- if (len > mValue.length) return false;
-
- switch (formatType) {
- case FORMAT_SINT8:
- value = intToSignedBits(value, 8);
- // Fall-through intended
- case FORMAT_UINT8:
- mValue[offset] = (byte) (value & 0xFF);
- break;
-
- case FORMAT_SINT16:
- value = intToSignedBits(value, 16);
- // Fall-through intended
- case FORMAT_UINT16:
- mValue[offset++] = (byte) (value & 0xFF);
- mValue[offset] = (byte) ((value >> 8) & 0xFF);
- break;
-
- case FORMAT_SINT32:
- value = intToSignedBits(value, 32);
- // Fall-through intended
- case FORMAT_UINT32:
- mValue[offset++] = (byte) (value & 0xFF);
- mValue[offset++] = (byte) ((value >> 8) & 0xFF);
- mValue[offset++] = (byte) ((value >> 16) & 0xFF);
- mValue[offset] = (byte) ((value >> 24) & 0xFF);
- break;
-
- default:
- return false;
- }
- return true;
- }
-
- /**
- * Set the locally stored value of this characteristic.
- * <p>See {@link #setValue(byte[])} for details.
- *
- * @param mantissa Mantissa for this characteristic
- * @param exponent exponent value for this characteristic
- * @param formatType Float format type used to transform the value parameter
- * @param offset Offset at which the value should be placed
- * @return true if the locally stored value has been set
- *
- * @deprecated Pass the characteristic value directly into
- * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
- */
- @Deprecated
- public boolean setValue(int mantissa, int exponent, int formatType, int offset) {
- int len = offset + getTypeLen(formatType);
- if (mValue == null) mValue = new byte[len];
- if (len > mValue.length) return false;
-
- switch (formatType) {
- case FORMAT_SFLOAT:
- mantissa = intToSignedBits(mantissa, 12);
- exponent = intToSignedBits(exponent, 4);
- mValue[offset++] = (byte) (mantissa & 0xFF);
- mValue[offset] = (byte) ((mantissa >> 8) & 0x0F);
- mValue[offset] += (byte) ((exponent & 0x0F) << 4);
- break;
-
- case FORMAT_FLOAT:
- mantissa = intToSignedBits(mantissa, 24);
- exponent = intToSignedBits(exponent, 8);
- mValue[offset++] = (byte) (mantissa & 0xFF);
- mValue[offset++] = (byte) ((mantissa >> 8) & 0xFF);
- mValue[offset++] = (byte) ((mantissa >> 16) & 0xFF);
- mValue[offset] += (byte) (exponent & 0xFF);
- break;
-
- default:
- return false;
- }
-
- return true;
- }
-
- /**
- * Set the locally stored value of this characteristic.
- * <p>See {@link #setValue(byte[])} for details.
- *
- * @param value New value for this characteristic
- * @return true if the locally stored value has been set
- *
- * @deprecated Pass the characteristic value directly into
- * {@link BluetoothGatt#writeCharacteristic(BluetoothGattCharacteristic, byte[], int)}
- */
- @Deprecated
- public boolean setValue(String value) {
- mValue = value.getBytes();
- return true;
- }
-
- /**
- * Returns the size of a give value type.
- */
- private int getTypeLen(int formatType) {
- return formatType & 0xF;
- }
-
- /**
- * Convert a signed byte to an unsigned int.
- */
- private int unsignedByteToInt(byte b) {
- return b & 0xFF;
- }
-
- /**
- * Convert signed bytes to a 16-bit unsigned int.
- */
- private int unsignedBytesToInt(byte b0, byte b1) {
- return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8));
- }
-
- /**
- * Convert signed bytes to a 32-bit unsigned int.
- */
- private int unsignedBytesToInt(byte b0, byte b1, byte b2, byte b3) {
- return (unsignedByteToInt(b0) + (unsignedByteToInt(b1) << 8))
- + (unsignedByteToInt(b2) << 16) + (unsignedByteToInt(b3) << 24);
- }
-
- /**
- * Convert signed bytes to a 16-bit short float value.
- */
- private float bytesToFloat(byte b0, byte b1) {
- int mantissa = unsignedToSigned(unsignedByteToInt(b0)
- + ((unsignedByteToInt(b1) & 0x0F) << 8), 12);
- int exponent = unsignedToSigned(unsignedByteToInt(b1) >> 4, 4);
- return (float) (mantissa * Math.pow(10, exponent));
- }
-
- /**
- * Convert signed bytes to a 32-bit short float value.
- */
- private float bytesToFloat(byte b0, byte b1, byte b2, byte b3) {
- int mantissa = unsignedToSigned(unsignedByteToInt(b0)
- + (unsignedByteToInt(b1) << 8)
- + (unsignedByteToInt(b2) << 16), 24);
- return (float) (mantissa * Math.pow(10, b3));
- }
-
- /**
- * Convert an unsigned integer value to a two's-complement encoded
- * signed value.
- */
- private int unsignedToSigned(int unsigned, int size) {
- if ((unsigned & (1 << size - 1)) != 0) {
- unsigned = -1 * ((1 << size - 1) - (unsigned & ((1 << size - 1) - 1)));
- }
- return unsigned;
- }
-
- /**
- * Convert an integer into the signed bits of a given length.
- */
- private int intToSignedBits(int i, int size) {
- if (i < 0) {
- i = (1 << size - 1) + (i & ((1 << size - 1) - 1));
- }
- return i;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothGattDescriptor.java b/core/java/android/bluetooth/BluetoothGattDescriptor.java
deleted file mode 100644
index a35d5b9..0000000
--- a/core/java/android/bluetooth/BluetoothGattDescriptor.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.os.Parcelable;
-
-import java.util.UUID;
-
-/**
- * Represents a Bluetooth GATT Descriptor
- *
- * <p> GATT Descriptors contain additional information and attributes of a GATT
- * characteristic, {@link BluetoothGattCharacteristic}. They can be used to describe
- * the characteristic's features or to control certain behaviours of the characteristic.
- */
-public class BluetoothGattDescriptor implements Parcelable {
-
- /**
- * Value used to enable notification for a client configuration descriptor
- */
- public static final byte[] ENABLE_NOTIFICATION_VALUE = {0x01, 0x00};
-
- /**
- * Value used to enable indication for a client configuration descriptor
- */
- public static final byte[] ENABLE_INDICATION_VALUE = {0x02, 0x00};
-
- /**
- * Value used to disable notifications or indicatinos
- */
- public static final byte[] DISABLE_NOTIFICATION_VALUE = {0x00, 0x00};
-
- /**
- * Descriptor read permission
- */
- public static final int PERMISSION_READ = 0x01;
-
- /**
- * Descriptor permission: Allow encrypted read operations
- */
- public static final int PERMISSION_READ_ENCRYPTED = 0x02;
-
- /**
- * Descriptor permission: Allow reading with person-in-the-middle protection
- */
- public static final int PERMISSION_READ_ENCRYPTED_MITM = 0x04;
-
- /**
- * Descriptor write permission
- */
- public static final int PERMISSION_WRITE = 0x10;
-
- /**
- * Descriptor permission: Allow encrypted writes
- */
- public static final int PERMISSION_WRITE_ENCRYPTED = 0x20;
-
- /**
- * Descriptor permission: Allow encrypted writes with person-in-the-middle
- * protection
- */
- public static final int PERMISSION_WRITE_ENCRYPTED_MITM = 0x40;
-
- /**
- * Descriptor permission: Allow signed write operations
- */
- public static final int PERMISSION_WRITE_SIGNED = 0x80;
-
- /**
- * Descriptor permission: Allow signed write operations with
- * person-in-the-middle protection
- */
- public static final int PERMISSION_WRITE_SIGNED_MITM = 0x100;
-
- /**
- * The UUID of this descriptor.
- *
- * @hide
- */
- protected UUID mUuid;
-
- /**
- * Instance ID for this descriptor.
- *
- * @hide
- */
- @UnsupportedAppUsage
- protected int mInstance;
-
- /**
- * Permissions for this descriptor
- *
- * @hide
- */
- protected int mPermissions;
-
- /**
- * Back-reference to the characteristic this descriptor belongs to.
- *
- * @hide
- */
- @UnsupportedAppUsage
- protected BluetoothGattCharacteristic mCharacteristic;
-
- /**
- * The value for this descriptor.
- *
- * @hide
- */
- protected byte[] mValue;
-
- /**
- * Create a new BluetoothGattDescriptor.
- *
- * @param uuid The UUID for this descriptor
- * @param permissions Permissions for this descriptor
- */
- public BluetoothGattDescriptor(UUID uuid, int permissions) {
- initDescriptor(null, uuid, 0, permissions);
- }
-
- /**
- * Create a new BluetoothGattDescriptor.
- *
- * @param characteristic The characteristic this descriptor belongs to
- * @param uuid The UUID for this descriptor
- * @param permissions Permissions for this descriptor
- */
- /*package*/ BluetoothGattDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
- int instance, int permissions) {
- initDescriptor(characteristic, uuid, instance, permissions);
- }
-
- /**
- * @hide
- */
- public BluetoothGattDescriptor(UUID uuid, int instance, int permissions) {
- initDescriptor(null, uuid, instance, permissions);
- }
-
- private void initDescriptor(BluetoothGattCharacteristic characteristic, UUID uuid,
- int instance, int permissions) {
- mCharacteristic = characteristic;
- mUuid = uuid;
- mInstance = instance;
- mPermissions = permissions;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeParcelable(new ParcelUuid(mUuid), 0);
- out.writeInt(mInstance);
- out.writeInt(mPermissions);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothGattDescriptor> CREATOR =
- new Parcelable.Creator<BluetoothGattDescriptor>() {
- public BluetoothGattDescriptor createFromParcel(Parcel in) {
- return new BluetoothGattDescriptor(in);
- }
-
- public BluetoothGattDescriptor[] newArray(int size) {
- return new BluetoothGattDescriptor[size];
- }
- };
-
- private BluetoothGattDescriptor(Parcel in) {
- mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
- mInstance = in.readInt();
- mPermissions = in.readInt();
- }
-
- /**
- * Returns the characteristic this descriptor belongs to.
- *
- * @return The characteristic.
- */
- public BluetoothGattCharacteristic getCharacteristic() {
- return mCharacteristic;
- }
-
- /**
- * Set the back-reference to the associated characteristic
- *
- * @hide
- */
- @UnsupportedAppUsage
- /*package*/ void setCharacteristic(BluetoothGattCharacteristic characteristic) {
- mCharacteristic = characteristic;
- }
-
- /**
- * Returns the UUID of this descriptor.
- *
- * @return UUID of this descriptor
- */
- public UUID getUuid() {
- return mUuid;
- }
-
- /**
- * Returns the instance ID for this descriptor.
- *
- * <p>If a remote device offers multiple descriptors with the same UUID,
- * the instance ID is used to distuinguish between descriptors.
- *
- * @return Instance ID of this descriptor
- * @hide
- */
- public int getInstanceId() {
- return mInstance;
- }
-
- /**
- * Force the instance ID.
- *
- * @hide
- */
- public void setInstanceId(int instanceId) {
- mInstance = instanceId;
- }
-
- /**
- * Returns the permissions for this descriptor.
- *
- * @return Permissions of this descriptor
- */
- public int getPermissions() {
- return mPermissions;
- }
-
- /**
- * Returns the stored value for this descriptor
- *
- * <p>This function returns the stored value for this descriptor as
- * retrieved by calling {@link BluetoothGatt#readDescriptor}. The cached
- * value of the descriptor is updated as a result of a descriptor read
- * operation.
- *
- * @return Cached value of the descriptor
- *
- * @deprecated Use {@link BluetoothGatt#readDescriptor(BluetoothGattDescriptor)} instead
- */
- @Deprecated
- public byte[] getValue() {
- return mValue;
- }
-
- /**
- * Updates the locally stored value of this descriptor.
- *
- * <p>This function modifies the locally stored cached value of this
- * descriptor. To send the value to the remote device, call
- * {@link BluetoothGatt#writeDescriptor} to send the value to the
- * remote device.
- *
- * @param value New value for this descriptor
- * @return true if the locally stored value has been set, false if the requested value could not
- * be stored locally.
- *
- * @deprecated Pass the descriptor value directly into
- * {@link BluetoothGatt#writeDescriptor(BluetoothGattDescriptor, byte[])}
- */
- @Deprecated
- public boolean setValue(byte[] value) {
- mValue = value;
- return true;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothGattIncludedService.java b/core/java/android/bluetooth/BluetoothGattIncludedService.java
deleted file mode 100644
index 5580619..0000000
--- a/core/java/android/bluetooth/BluetoothGattIncludedService.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.os.Parcelable;
-
-import java.util.UUID;
-
-/**
- * Represents a Bluetooth GATT Included Service
- *
- * @hide
- */
-public class BluetoothGattIncludedService implements Parcelable {
-
- /**
- * The UUID of this service.
- */
- protected UUID mUuid;
-
- /**
- * Instance ID for this service.
- */
- protected int mInstanceId;
-
- /**
- * Service type (Primary/Secondary).
- */
- protected int mServiceType;
-
- /**
- * Create a new BluetoothGattIncludedService
- */
- public BluetoothGattIncludedService(UUID uuid, int instanceId, int serviceType) {
- mUuid = uuid;
- mInstanceId = instanceId;
- mServiceType = serviceType;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeParcelable(new ParcelUuid(mUuid), 0);
- out.writeInt(mInstanceId);
- out.writeInt(mServiceType);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothGattIncludedService> CREATOR =
- new Parcelable.Creator<BluetoothGattIncludedService>() {
- public BluetoothGattIncludedService createFromParcel(Parcel in) {
- return new BluetoothGattIncludedService(in);
- }
-
- public BluetoothGattIncludedService[] newArray(int size) {
- return new BluetoothGattIncludedService[size];
- }
- };
-
- private BluetoothGattIncludedService(Parcel in) {
- mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
- mInstanceId = in.readInt();
- mServiceType = in.readInt();
- }
-
- /**
- * Returns the UUID of this service
- *
- * @return UUID of this service
- */
- public UUID getUuid() {
- return mUuid;
- }
-
- /**
- * Returns the instance ID for this service
- *
- * <p>If a remote device offers multiple services with the same UUID
- * (ex. multiple battery services for different batteries), the instance
- * ID is used to distuinguish services.
- *
- * @return Instance ID of this service
- */
- public int getInstanceId() {
- return mInstanceId;
- }
-
- /**
- * Get the type of this service (primary/secondary)
- */
- public int getType() {
- return mServiceType;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothGattServer.java b/core/java/android/bluetooth/BluetoothGattServer.java
deleted file mode 100644
index 08e0178..0000000
--- a/core/java/android/bluetooth/BluetoothGattServer.java
+++ /dev/null
@@ -1,954 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.content.AttributionSource;
-import android.os.ParcelUuid;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Public API for the Bluetooth GATT Profile server role.
- *
- * <p>This class provides Bluetooth GATT server role functionality,
- * allowing applications to create Bluetooth Smart services and
- * characteristics.
- *
- * <p>BluetoothGattServer is a proxy object for controlling the Bluetooth Service
- * via IPC. Use {@link BluetoothManager#openGattServer} to get an instance
- * of this class.
- */
-public final class BluetoothGattServer implements BluetoothProfile {
- private static final String TAG = "BluetoothGattServer";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- private final IBluetoothGatt mService;
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
-
- private BluetoothGattServerCallback mCallback;
-
- private Object mServerIfLock = new Object();
- private int mServerIf;
- private int mTransport;
- private BluetoothGattService mPendingService;
- private List<BluetoothGattService> mServices;
-
- private static final int CALLBACK_REG_TIMEOUT = 10000;
-
- /**
- * Bluetooth GATT interface callbacks
- */
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothGattServerCallback mBluetoothGattServerCallback =
- new IBluetoothGattServerCallback.Stub() {
- /**
- * Application interface registered - app is ready to go
- * @hide
- */
- @Override
- public void onServerRegistered(int status, int serverIf) {
- if (DBG) {
- Log.d(TAG, "onServerRegistered() - status=" + status
- + " serverIf=" + serverIf);
- }
- synchronized (mServerIfLock) {
- if (mCallback != null) {
- mServerIf = serverIf;
- mServerIfLock.notify();
- } else {
- // registration timeout
- Log.e(TAG, "onServerRegistered: mCallback is null");
- }
- }
- }
-
- /**
- * Server connection state changed
- * @hide
- */
- @Override
- public void onServerConnectionState(int status, int serverIf,
- boolean connected, String address) {
- if (DBG) {
- Log.d(TAG, "onServerConnectionState() - status=" + status
- + " serverIf=" + serverIf + " device=" + address);
- }
- try {
- mCallback.onConnectionStateChange(mAdapter.getRemoteDevice(address), status,
- connected ? BluetoothProfile.STATE_CONNECTED :
- BluetoothProfile.STATE_DISCONNECTED);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
- }
-
- /**
- * Service has been added
- * @hide
- */
- @Override
- public void onServiceAdded(int status, BluetoothGattService service) {
- if (DBG) {
- Log.d(TAG, "onServiceAdded() - handle=" + service.getInstanceId()
- + " uuid=" + service.getUuid() + " status=" + status);
- }
-
- if (mPendingService == null) {
- return;
- }
-
- BluetoothGattService tmp = mPendingService;
- mPendingService = null;
-
- // Rewrite newly assigned handles to existing service.
- tmp.setInstanceId(service.getInstanceId());
- List<BluetoothGattCharacteristic> temp_chars = tmp.getCharacteristics();
- List<BluetoothGattCharacteristic> svc_chars = service.getCharacteristics();
- for (int i = 0; i < svc_chars.size(); i++) {
- BluetoothGattCharacteristic temp_char = temp_chars.get(i);
- BluetoothGattCharacteristic svc_char = svc_chars.get(i);
-
- temp_char.setInstanceId(svc_char.getInstanceId());
-
- List<BluetoothGattDescriptor> temp_descs = temp_char.getDescriptors();
- List<BluetoothGattDescriptor> svc_descs = svc_char.getDescriptors();
- for (int j = 0; j < svc_descs.size(); j++) {
- temp_descs.get(j).setInstanceId(svc_descs.get(j).getInstanceId());
- }
- }
-
- mServices.add(tmp);
-
- try {
- mCallback.onServiceAdded((int) status, tmp);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
- }
-
- /**
- * Remote client characteristic read request.
- * @hide
- */
- @Override
- public void onCharacteristicReadRequest(String address, int transId,
- int offset, boolean isLong, int handle) {
- if (VDBG) Log.d(TAG, "onCharacteristicReadRequest() - handle=" + handle);
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- BluetoothGattCharacteristic characteristic = getCharacteristicByHandle(handle);
- if (characteristic == null) {
- Log.w(TAG, "onCharacteristicReadRequest() no char for handle " + handle);
- return;
- }
-
- try {
- mCallback.onCharacteristicReadRequest(device, transId, offset,
- characteristic);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
- }
-
- /**
- * Remote client descriptor read request.
- * @hide
- */
- @Override
- public void onDescriptorReadRequest(String address, int transId,
- int offset, boolean isLong, int handle) {
- if (VDBG) Log.d(TAG, "onCharacteristicReadRequest() - handle=" + handle);
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- BluetoothGattDescriptor descriptor = getDescriptorByHandle(handle);
- if (descriptor == null) {
- Log.w(TAG, "onDescriptorReadRequest() no desc for handle " + handle);
- return;
- }
-
- try {
- mCallback.onDescriptorReadRequest(device, transId, offset, descriptor);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
- }
-
- /**
- * Remote client characteristic write request.
- * @hide
- */
- @Override
- public void onCharacteristicWriteRequest(String address, int transId,
- int offset, int length, boolean isPrep, boolean needRsp,
- int handle, byte[] value) {
- if (VDBG) Log.d(TAG, "onCharacteristicWriteRequest() - handle=" + handle);
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- BluetoothGattCharacteristic characteristic = getCharacteristicByHandle(handle);
- if (characteristic == null) {
- Log.w(TAG, "onCharacteristicWriteRequest() no char for handle " + handle);
- return;
- }
-
- try {
- mCallback.onCharacteristicWriteRequest(device, transId, characteristic,
- isPrep, needRsp, offset, value);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
-
- }
-
- /**
- * Remote client descriptor write request.
- * @hide
- */
- @Override
- public void onDescriptorWriteRequest(String address, int transId, int offset,
- int length, boolean isPrep, boolean needRsp, int handle, byte[] value) {
- if (VDBG) Log.d(TAG, "onDescriptorWriteRequest() - handle=" + handle);
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- BluetoothGattDescriptor descriptor = getDescriptorByHandle(handle);
- if (descriptor == null) {
- Log.w(TAG, "onDescriptorWriteRequest() no desc for handle " + handle);
- return;
- }
-
- try {
- mCallback.onDescriptorWriteRequest(device, transId, descriptor,
- isPrep, needRsp, offset, value);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
- }
-
- /**
- * Execute pending writes.
- * @hide
- */
- @Override
- public void onExecuteWrite(String address, int transId,
- boolean execWrite) {
- if (DBG) {
- Log.d(TAG, "onExecuteWrite() - "
- + "device=" + address + ", transId=" + transId
- + "execWrite=" + execWrite);
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- if (device == null) return;
-
- try {
- mCallback.onExecuteWrite(device, transId, execWrite);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
- }
-
- /**
- * A notification/indication has been sent.
- * @hide
- */
- @Override
- public void onNotificationSent(String address, int status) {
- if (VDBG) {
- Log.d(TAG, "onNotificationSent() - "
- + "device=" + address + ", status=" + status);
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- if (device == null) return;
-
- try {
- mCallback.onNotificationSent(device, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception: " + ex);
- }
- }
-
- /**
- * The MTU for a connection has changed
- * @hide
- */
- @Override
- public void onMtuChanged(String address, int mtu) {
- if (DBG) {
- Log.d(TAG, "onMtuChanged() - "
- + "device=" + address + ", mtu=" + mtu);
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- if (device == null) return;
-
- try {
- mCallback.onMtuChanged(device, mtu);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception: " + ex);
- }
- }
-
- /**
- * The PHY for a connection was updated
- * @hide
- */
- @Override
- public void onPhyUpdate(String address, int txPhy, int rxPhy, int status) {
- if (DBG) {
- Log.d(TAG,
- "onPhyUpdate() - " + "device=" + address + ", txPHy=" + txPhy
- + ", rxPHy=" + rxPhy);
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- if (device == null) return;
-
- try {
- mCallback.onPhyUpdate(device, txPhy, rxPhy, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception: " + ex);
- }
- }
-
- /**
- * The PHY for a connection was read
- * @hide
- */
- @Override
- public void onPhyRead(String address, int txPhy, int rxPhy, int status) {
- if (DBG) {
- Log.d(TAG,
- "onPhyUpdate() - " + "device=" + address + ", txPHy=" + txPhy
- + ", rxPHy=" + rxPhy);
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- if (device == null) return;
-
- try {
- mCallback.onPhyRead(device, txPhy, rxPhy, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception: " + ex);
- }
- }
-
- /**
- * Callback invoked when the given connection is updated
- * @hide
- */
- @Override
- public void onConnectionUpdated(String address, int interval, int latency,
- int timeout, int status) {
- if (DBG) {
- Log.d(TAG, "onConnectionUpdated() - Device=" + address
- + " interval=" + interval + " latency=" + latency
- + " timeout=" + timeout + " status=" + status);
- }
- BluetoothDevice device = mAdapter.getRemoteDevice(address);
- if (device == null) return;
-
- try {
- mCallback.onConnectionUpdated(device, interval, latency,
- timeout, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception: " + ex);
- }
- }
-
- };
-
- /**
- * Create a BluetoothGattServer proxy object.
- */
- /* package */ BluetoothGattServer(IBluetoothGatt iGatt, int transport,
- BluetoothAdapter adapter) {
- mService = iGatt;
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mCallback = null;
- mServerIf = 0;
- mTransport = transport;
- mServices = new ArrayList<BluetoothGattService>();
- }
-
- /**
- * Returns a characteristic with given handle.
- *
- * @hide
- */
- /*package*/ BluetoothGattCharacteristic getCharacteristicByHandle(int handle) {
- for (BluetoothGattService svc : mServices) {
- for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
- if (charac.getInstanceId() == handle) {
- return charac;
- }
- }
- }
- return null;
- }
-
- /**
- * Returns a descriptor with given handle.
- *
- * @hide
- */
- /*package*/ BluetoothGattDescriptor getDescriptorByHandle(int handle) {
- for (BluetoothGattService svc : mServices) {
- for (BluetoothGattCharacteristic charac : svc.getCharacteristics()) {
- for (BluetoothGattDescriptor desc : charac.getDescriptors()) {
- if (desc.getInstanceId() == handle) {
- return desc;
- }
- }
- }
- }
- return null;
- }
-
- /**
- * Close this GATT server instance.
- *
- * Application should call this method as early as possible after it is done with
- * this GATT server.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void close() {
- if (DBG) Log.d(TAG, "close()");
- unregisterCallback();
- }
-
- /**
- * Register an application callback to start using GattServer.
- *
- * <p>This is an asynchronous call. The callback is used to notify
- * success or failure if the function returns true.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @return true, the callback will be called to notify success or failure, false on immediate
- * error
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- /*package*/ boolean registerCallback(BluetoothGattServerCallback callback) {
- return registerCallback(callback, false);
- }
-
- /**
- * Register an application callback to start using GattServer.
- *
- * <p>This is an asynchronous call. The callback is used to notify
- * success or failure if the function returns true.
- *
- * @param callback GATT callback handler that will receive asynchronous callbacks.
- * @param eatt_support indicates if server can use eatt
- * @return true, the callback will be called to notify success or failure, false on immediate
- * error
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- /*package*/ boolean registerCallback(BluetoothGattServerCallback callback,
- boolean eatt_support) {
- if (DBG) Log.d(TAG, "registerCallback()");
- if (mService == null) {
- Log.e(TAG, "GATT service not available");
- return false;
- }
- UUID uuid = UUID.randomUUID();
- if (DBG) Log.d(TAG, "registerCallback() - UUID=" + uuid);
-
- synchronized (mServerIfLock) {
- if (mCallback != null) {
- Log.e(TAG, "App can register callback only once");
- return false;
- }
-
- mCallback = callback;
- try {
- mService.registerServer(new ParcelUuid(uuid), mBluetoothGattServerCallback,
- eatt_support, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- mCallback = null;
- return false;
- }
-
- try {
- mServerIfLock.wait(CALLBACK_REG_TIMEOUT);
- } catch (InterruptedException e) {
- Log.e(TAG, "" + e);
- mCallback = null;
- }
-
- if (mServerIf == 0) {
- mCallback = null;
- return false;
- } else {
- return true;
- }
- }
- }
-
- /**
- * Unregister the current application and callbacks.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private void unregisterCallback() {
- if (DBG) Log.d(TAG, "unregisterCallback() - mServerIf=" + mServerIf);
- if (mService == null || mServerIf == 0) return;
-
- try {
- mCallback = null;
- mService.unregisterServer(mServerIf, mAttributionSource);
- mServerIf = 0;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Returns a service by UUID, instance and type.
- *
- * @hide
- */
- /*package*/ BluetoothGattService getService(UUID uuid, int instanceId, int type) {
- for (BluetoothGattService svc : mServices) {
- if (svc.getType() == type
- && svc.getInstanceId() == instanceId
- && svc.getUuid().equals(uuid)) {
- return svc;
- }
- }
- return null;
- }
-
- /**
- * Initiate a connection to a Bluetooth GATT capable device.
- *
- * <p>The connection may not be established right away, but will be
- * completed when the remote device is available. A
- * {@link BluetoothGattServerCallback#onConnectionStateChange} callback will be
- * invoked when the connection state changes as a result of this function.
- *
- * <p>The autoConnect parameter determines whether to actively connect to
- * the remote device, or rather passively scan and finalize the connection
- * when the remote device is in range/available. Generally, the first ever
- * connection to a device should be direct (autoConnect set to false) and
- * subsequent connections to known devices should be invoked with the
- * autoConnect parameter set to true.
- *
- * @param autoConnect Whether to directly connect to the remote device (false) or to
- * automatically connect as soon as the remote device becomes available (true).
- * @return true, if the connection attempt was initiated successfully
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean connect(BluetoothDevice device, boolean autoConnect) {
- if (DBG) {
- Log.d(TAG,
- "connect() - device: " + device.getAddress() + ", auto: " + autoConnect);
- }
- if (mService == null || mServerIf == 0) return false;
-
- try {
- // autoConnect is inverse of "isDirect"
- mService.serverConnect(
- mServerIf, device.getAddress(), !autoConnect, mTransport, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Disconnects an established connection, or cancels a connection attempt
- * currently in progress.
- *
- * @param device Remote device
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void cancelConnection(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "cancelConnection() - device: " + device.getAddress());
- if (mService == null || mServerIf == 0) return;
-
- try {
- mService.serverDisconnect(mServerIf, device.getAddress(), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Set the preferred connection PHY for this app. Please note that this is just a
- * recommendation, whether the PHY change will happen depends on other applications peferences,
- * local and remote controller capabilities. Controller can override these settings. <p> {@link
- * BluetoothGattServerCallback#onPhyUpdate} will be triggered as a result of this call, even if
- * no PHY change happens. It is also triggered when remote device updates the PHY.
- *
- * @param device The remote device to send this response to
- * @param txPhy preferred transmitter PHY. Bitwise OR of any of {@link
- * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
- * BluetoothDevice#PHY_LE_CODED_MASK}.
- * @param rxPhy preferred receiver PHY. Bitwise OR of any of {@link
- * BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK}, and {@link
- * BluetoothDevice#PHY_LE_CODED_MASK}.
- * @param phyOptions preferred coding to use when transmitting on the LE Coded PHY. Can be one
- * of {@link BluetoothDevice#PHY_OPTION_NO_PREFERRED}, {@link BluetoothDevice#PHY_OPTION_S2} or
- * {@link BluetoothDevice#PHY_OPTION_S8}
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setPreferredPhy(BluetoothDevice device, int txPhy, int rxPhy, int phyOptions) {
- try {
- mService.serverSetPreferredPhy(mServerIf, device.getAddress(), txPhy, rxPhy,
- phyOptions, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Read the current transmitter PHY and receiver PHY of the connection. The values are returned
- * in {@link BluetoothGattServerCallback#onPhyRead}
- *
- * @param device The remote device to send this response to
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void readPhy(BluetoothDevice device) {
- try {
- mService.serverReadPhy(mServerIf, device.getAddress(), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Send a response to a read or write request to a remote device.
- *
- * <p>This function must be invoked in when a remote read/write request
- * is received by one of these callback methods:
- *
- * <ul>
- * <li>{@link BluetoothGattServerCallback#onCharacteristicReadRequest}
- * <li>{@link BluetoothGattServerCallback#onCharacteristicWriteRequest}
- * <li>{@link BluetoothGattServerCallback#onDescriptorReadRequest}
- * <li>{@link BluetoothGattServerCallback#onDescriptorWriteRequest}
- * </ul>
- *
- * @param device The remote device to send this response to
- * @param requestId The ID of the request that was received with the callback
- * @param status The status of the request to be sent to the remote devices
- * @param offset Value offset for partial read/write response
- * @param value The value of the attribute that was read/written (optional)
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean sendResponse(BluetoothDevice device, int requestId,
- int status, int offset, byte[] value) {
- if (VDBG) Log.d(TAG, "sendResponse() - device: " + device.getAddress());
- if (mService == null || mServerIf == 0) return false;
-
- try {
- mService.sendResponse(mServerIf, device.getAddress(), requestId,
- status, offset, value, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
- return true;
- }
-
- /**
- * Send a notification or indication that a local characteristic has been
- * updated.
- *
- * <p>A notification or indication is sent to the remote device to signal
- * that the characteristic has been updated. This function should be invoked
- * for every client that requests notifications/indications by writing
- * to the "Client Configuration" descriptor for the given characteristic.
- *
- * @param device The remote device to receive the notification/indication
- * @param characteristic The local characteristic that has been updated
- * @param confirm true to request confirmation from the client (indication), false to send a
- * notification
- * @return true, if the notification has been triggered successfully
- * @throws IllegalArgumentException
- *
- * @deprecated Use {@link BluetoothGattServer#notifyCharacteristicChanged(BluetoothDevice,
- * BluetoothGattCharacteristic, boolean, byte[])} as this is not memory safe.
- */
- @Deprecated
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean notifyCharacteristicChanged(BluetoothDevice device,
- BluetoothGattCharacteristic characteristic, boolean confirm) {
- return notifyCharacteristicChanged(device, characteristic, confirm,
- characteristic.getValue()) == BluetoothStatusCodes.SUCCESS;
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothStatusCodes.SUCCESS,
- BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION,
- BluetoothStatusCodes.ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION,
- BluetoothStatusCodes.ERROR_DEVICE_NOT_CONNECTED,
- BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
- BluetoothStatusCodes.ERROR_GATT_WRITE_NOT_ALLOWED,
- BluetoothStatusCodes.ERROR_GATT_WRITE_REQUEST_BUSY,
- BluetoothStatusCodes.ERROR_UNKNOWN
- })
- public @interface NotifyCharacteristicReturnValues{}
-
- /**
- * Send a notification or indication that a local characteristic has been
- * updated.
- *
- * <p>A notification or indication is sent to the remote device to signal
- * that the characteristic has been updated. This function should be invoked
- * for every client that requests notifications/indications by writing
- * to the "Client Configuration" descriptor for the given characteristic.
- *
- * @param device the remote device to receive the notification/indication
- * @param characteristic the local characteristic that has been updated
- * @param confirm {@code true} to request confirmation from the client (indication) or
- * {@code false} to send a notification
- * @param value the characteristic value
- * @return whether the notification has been triggered successfully
- * @throws IllegalArgumentException if the characteristic value or service is null
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @NotifyCharacteristicReturnValues
- public int notifyCharacteristicChanged(@NonNull BluetoothDevice device,
- @NonNull BluetoothGattCharacteristic characteristic, boolean confirm,
- @NonNull byte[] value) {
- if (VDBG) Log.d(TAG, "notifyCharacteristicChanged() - device: " + device.getAddress());
- if (mService == null || mServerIf == 0) {
- return BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND;
- }
-
- if (characteristic == null) {
- throw new IllegalArgumentException("characteristic must not be null");
- }
- if (device == null) {
- throw new IllegalArgumentException("device must not be null");
- }
- BluetoothGattService service = characteristic.getService();
- if (service == null) {
- throw new IllegalArgumentException("Characteristic must have a non-null service");
- }
- if (value == null) {
- throw new IllegalArgumentException("Characteristic value must not be null");
- }
-
- try {
- return mService.sendNotification(mServerIf, device.getAddress(),
- characteristic.getInstanceId(), confirm,
- value, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Add a service to the list of services to be hosted.
- *
- * <p>Once a service has been addded to the list, the service and its
- * included characteristics will be provided by the local device.
- *
- * <p>If the local device has already exposed services when this function
- * is called, a service update notification will be sent to all clients.
- *
- * <p>The {@link BluetoothGattServerCallback#onServiceAdded} callback will indicate
- * whether this service has been added successfully. Do not add another service
- * before this callback.
- *
- * @param service Service to be added to the list of services provided by this device.
- * @return true, if the request to add service has been initiated
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean addService(BluetoothGattService service) {
- if (DBG) Log.d(TAG, "addService() - service: " + service.getUuid());
- if (mService == null || mServerIf == 0) return false;
-
- mPendingService = service;
-
- try {
- mService.addService(mServerIf, service, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Removes a service from the list of services to be provided.
- *
- * @param service Service to be removed.
- * @return true, if the service has been removed
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean removeService(BluetoothGattService service) {
- if (DBG) Log.d(TAG, "removeService() - service: " + service.getUuid());
- if (mService == null || mServerIf == 0) return false;
-
- BluetoothGattService intService = getService(service.getUuid(),
- service.getInstanceId(), service.getType());
- if (intService == null) return false;
-
- try {
- mService.removeService(mServerIf, service.getInstanceId(), mAttributionSource);
- mServices.remove(intService);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return false;
- }
-
- return true;
- }
-
- /**
- * Remove all services from the list of provided services.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void clearServices() {
- if (DBG) Log.d(TAG, "clearServices()");
- if (mService == null || mServerIf == 0) return;
-
- try {
- mService.clearServices(mServerIf, mAttributionSource);
- mServices.clear();
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- /**
- * Returns a list of GATT services offered by this device.
- *
- * <p>An application must call {@link #addService} to add a serice to the
- * list of services offered by this device.
- *
- * @return List of services. Returns an empty list if no services have been added yet.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public List<BluetoothGattService> getServices() {
- return mServices;
- }
-
- /**
- * Returns a {@link BluetoothGattService} from the list of services offered
- * by this device.
- *
- * <p>If multiple instances of the same service (as identified by UUID)
- * exist, the first instance of the service is returned.
- *
- * @param uuid UUID of the requested service
- * @return BluetoothGattService if supported, or null if the requested service is not offered by
- * this device.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresNoPermission
- public BluetoothGattService getService(UUID uuid) {
- for (BluetoothGattService service : mServices) {
- if (service.getUuid().equals(uuid)) {
- return service;
- }
- }
-
- return null;
- }
-
-
- /**
- * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
- * with {@link BluetoothProfile#GATT} as argument
- *
- * @throws UnsupportedOperationException
- */
- @Override
- @RequiresNoPermission
- public int getConnectionState(BluetoothDevice device) {
- throw new UnsupportedOperationException("Use BluetoothManager#getConnectionState instead.");
- }
-
- /**
- * Not supported - please use {@link BluetoothManager#getConnectedDevices(int)}
- * with {@link BluetoothProfile#GATT} as argument
- *
- * @throws UnsupportedOperationException
- */
- @Override
- @RequiresNoPermission
- public List<BluetoothDevice> getConnectedDevices() {
- throw new UnsupportedOperationException(
- "Use BluetoothManager#getConnectedDevices instead.");
- }
-
- /**
- * Not supported - please use
- * {@link BluetoothManager#getDevicesMatchingConnectionStates(int, int[])}
- * with {@link BluetoothProfile#GATT} as first argument
- *
- * @throws UnsupportedOperationException
- */
- @Override
- @RequiresNoPermission
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- throw new UnsupportedOperationException(
- "Use BluetoothManager#getDevicesMatchingConnectionStates instead.");
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java
deleted file mode 100644
index 0ead5f5..0000000
--- a/core/java/android/bluetooth/BluetoothGattServerCallback.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-/**
- * This abstract class is used to implement {@link BluetoothGattServer} callbacks.
- */
-public abstract class BluetoothGattServerCallback {
-
- /**
- * Callback indicating when a remote device has been connected or disconnected.
- *
- * @param device Remote device that has been connected or disconnected.
- * @param status Status of the connect or disconnect operation.
- * @param newState Returns the new connection state. Can be one of {@link
- * BluetoothProfile#STATE_DISCONNECTED} or {@link BluetoothProfile#STATE_CONNECTED}
- */
- public void onConnectionStateChange(BluetoothDevice device, int status,
- int newState) {
- }
-
- /**
- * Indicates whether a local service has been added successfully.
- *
- * @param status Returns {@link BluetoothGatt#GATT_SUCCESS} if the service was added
- * successfully.
- * @param service The service that has been added
- */
- public void onServiceAdded(int status, BluetoothGattService service) {
- }
-
- /**
- * A remote client has requested to read a local characteristic.
- *
- * <p>An application must call {@link BluetoothGattServer#sendResponse}
- * to complete the request.
- *
- * @param device The remote device that has requested the read operation
- * @param requestId The Id of the request
- * @param offset Offset into the value of the characteristic
- * @param characteristic Characteristic to be read
- */
- public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
- int offset, BluetoothGattCharacteristic characteristic) {
- }
-
- /**
- * A remote client has requested to write to a local characteristic.
- *
- * <p>An application must call {@link BluetoothGattServer#sendResponse}
- * to complete the request.
- *
- * @param device The remote device that has requested the write operation
- * @param requestId The Id of the request
- * @param characteristic Characteristic to be written to.
- * @param preparedWrite true, if this write operation should be queued for later execution.
- * @param responseNeeded true, if the remote device requires a response
- * @param offset The offset given for the value
- * @param value The value the client wants to assign to the characteristic
- */
- public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
- BluetoothGattCharacteristic characteristic,
- boolean preparedWrite, boolean responseNeeded,
- int offset, byte[] value) {
- }
-
- /**
- * A remote client has requested to read a local descriptor.
- *
- * <p>An application must call {@link BluetoothGattServer#sendResponse}
- * to complete the request.
- *
- * @param device The remote device that has requested the read operation
- * @param requestId The Id of the request
- * @param offset Offset into the value of the characteristic
- * @param descriptor Descriptor to be read
- */
- public void onDescriptorReadRequest(BluetoothDevice device, int requestId,
- int offset, BluetoothGattDescriptor descriptor) {
- }
-
- /**
- * A remote client has requested to write to a local descriptor.
- *
- * <p>An application must call {@link BluetoothGattServer#sendResponse}
- * to complete the request.
- *
- * @param device The remote device that has requested the write operation
- * @param requestId The Id of the request
- * @param descriptor Descriptor to be written to.
- * @param preparedWrite true, if this write operation should be queued for later execution.
- * @param responseNeeded true, if the remote device requires a response
- * @param offset The offset given for the value
- * @param value The value the client wants to assign to the descriptor
- */
- public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
- BluetoothGattDescriptor descriptor,
- boolean preparedWrite, boolean responseNeeded,
- int offset, byte[] value) {
- }
-
- /**
- * Execute all pending write operations for this device.
- *
- * <p>An application must call {@link BluetoothGattServer#sendResponse}
- * to complete the request.
- *
- * @param device The remote device that has requested the write operations
- * @param requestId The Id of the request
- * @param execute Whether the pending writes should be executed (true) or cancelled (false)
- */
- public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
- }
-
- /**
- * Callback invoked when a notification or indication has been sent to
- * a remote device.
- *
- * <p>When multiple notifications are to be sent, an application must
- * wait for this callback to be received before sending additional
- * notifications.
- *
- * @param device The remote device the notification has been sent to
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the operation was successful
- */
- public void onNotificationSent(BluetoothDevice device, int status) {
- }
-
- /**
- * Callback indicating the MTU for a given device connection has changed.
- *
- * <p>This callback will be invoked if a remote client has requested to change
- * the MTU for a given connection.
- *
- * @param device The remote device that requested the MTU change
- * @param mtu The new MTU size
- */
- public void onMtuChanged(BluetoothDevice device, int mtu) {
- }
-
- /**
- * Callback triggered as result of {@link BluetoothGattServer#setPreferredPhy}, or as a result
- * of remote device changing the PHY.
- *
- * @param device The remote device
- * @param txPhy the transmitter PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
- * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
- * @param status Status of the PHY update operation. {@link BluetoothGatt#GATT_SUCCESS} if the
- * operation succeeds.
- */
- public void onPhyUpdate(BluetoothDevice device, int txPhy, int rxPhy, int status) {
- }
-
- /**
- * Callback triggered as result of {@link BluetoothGattServer#readPhy}
- *
- * @param device The remote device that requested the PHY read
- * @param txPhy the transmitter PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
- * @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
- * @param status Status of the PHY read operation. {@link BluetoothGatt#GATT_SUCCESS} if the
- * operation succeeds.
- */
- public void onPhyRead(BluetoothDevice device, int txPhy, int rxPhy, int status) {
- }
-
- /**
- * Callback indicating the connection parameters were updated.
- *
- * @param device The remote device involved
- * @param interval Connection interval used on this connection, 1.25ms unit. Valid range is from
- * 6 (7.5ms) to 3200 (4000ms).
- * @param latency Worker latency for the connection in number of connection events. Valid range
- * is from 0 to 499
- * @param timeout Supervision timeout for this connection, in 10ms unit. Valid range is from 10
- * (0.1s) to 3200 (32s)
- * @param status {@link BluetoothGatt#GATT_SUCCESS} if the connection has been updated
- * successfully
- * @hide
- */
- public void onConnectionUpdated(BluetoothDevice device, int interval, int latency, int timeout,
- int status) {
- }
-
-}
diff --git a/core/java/android/bluetooth/BluetoothGattService.java b/core/java/android/bluetooth/BluetoothGattService.java
deleted file mode 100644
index f64d09f..0000000
--- a/core/java/android/bluetooth/BluetoothGattService.java
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.bluetooth;
-
-import android.annotation.RequiresPermission;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.UUID;
-
-/**
- * Represents a Bluetooth GATT Service
- *
- * <p> Gatt Service contains a collection of {@link BluetoothGattCharacteristic},
- * as well as referenced services.
- */
-public class BluetoothGattService implements Parcelable {
-
- /**
- * Primary service
- */
- public static final int SERVICE_TYPE_PRIMARY = 0;
-
- /**
- * Secondary service (included by primary services)
- */
- public static final int SERVICE_TYPE_SECONDARY = 1;
-
-
- /**
- * The remote device this service is associated with.
- * This applies to client applications only.
- *
- * @hide
- */
- @UnsupportedAppUsage
- protected BluetoothDevice mDevice;
-
- /**
- * The UUID of this service.
- *
- * @hide
- */
- protected UUID mUuid;
-
- /**
- * Instance ID for this service.
- *
- * @hide
- */
- protected int mInstanceId;
-
- /**
- * Handle counter override (for conformance testing).
- *
- * @hide
- */
- protected int mHandles = 0;
-
- /**
- * Service type (Primary/Secondary).
- *
- * @hide
- */
- protected int mServiceType;
-
- /**
- * List of characteristics included in this service.
- */
- protected List<BluetoothGattCharacteristic> mCharacteristics;
-
- /**
- * List of included services for this service.
- */
- protected List<BluetoothGattService> mIncludedServices;
-
- /**
- * Whether the service uuid should be advertised.
- */
- private boolean mAdvertisePreferred;
-
- /**
- * Create a new BluetoothGattService.
- *
- * @param uuid The UUID for this service
- * @param serviceType The type of this service,
- * {@link BluetoothGattService#SERVICE_TYPE_PRIMARY}
- * or {@link BluetoothGattService#SERVICE_TYPE_SECONDARY}
- */
- public BluetoothGattService(UUID uuid, int serviceType) {
- mDevice = null;
- mUuid = uuid;
- mInstanceId = 0;
- mServiceType = serviceType;
- mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
- mIncludedServices = new ArrayList<BluetoothGattService>();
- }
-
- /**
- * Create a new BluetoothGattService
- *
- * @hide
- */
- /*package*/ BluetoothGattService(BluetoothDevice device, UUID uuid,
- int instanceId, int serviceType) {
- mDevice = device;
- mUuid = uuid;
- mInstanceId = instanceId;
- mServiceType = serviceType;
- mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
- mIncludedServices = new ArrayList<BluetoothGattService>();
- }
-
- /**
- * Create a new BluetoothGattService
- *
- * @hide
- */
- public BluetoothGattService(UUID uuid, int instanceId, int serviceType) {
- mDevice = null;
- mUuid = uuid;
- mInstanceId = instanceId;
- mServiceType = serviceType;
- mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
- mIncludedServices = new ArrayList<BluetoothGattService>();
- }
-
- /**
- * @hide
- */
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeParcelable(new ParcelUuid(mUuid), 0);
- out.writeInt(mInstanceId);
- out.writeInt(mServiceType);
- out.writeTypedList(mCharacteristics);
-
- ArrayList<BluetoothGattIncludedService> includedServices =
- new ArrayList<BluetoothGattIncludedService>(mIncludedServices.size());
- for (BluetoothGattService s : mIncludedServices) {
- includedServices.add(new BluetoothGattIncludedService(s.getUuid(),
- s.getInstanceId(), s.getType()));
- }
- out.writeTypedList(includedServices);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothGattService> CREATOR =
- new Parcelable.Creator<BluetoothGattService>() {
- public BluetoothGattService createFromParcel(Parcel in) {
- return new BluetoothGattService(in);
- }
-
- public BluetoothGattService[] newArray(int size) {
- return new BluetoothGattService[size];
- }
- };
-
- private BluetoothGattService(Parcel in) {
- mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
- mInstanceId = in.readInt();
- mServiceType = in.readInt();
-
- mCharacteristics = new ArrayList<BluetoothGattCharacteristic>();
-
- ArrayList<BluetoothGattCharacteristic> chrcs =
- in.createTypedArrayList(BluetoothGattCharacteristic.CREATOR);
- if (chrcs != null) {
- for (BluetoothGattCharacteristic chrc : chrcs) {
- chrc.setService(this);
- mCharacteristics.add(chrc);
- }
- }
-
- mIncludedServices = new ArrayList<BluetoothGattService>();
-
- ArrayList<BluetoothGattIncludedService> inclSvcs =
- in.createTypedArrayList(BluetoothGattIncludedService.CREATOR);
- if (chrcs != null) {
- for (BluetoothGattIncludedService isvc : inclSvcs) {
- mIncludedServices.add(new BluetoothGattService(null, isvc.getUuid(),
- isvc.getInstanceId(), isvc.getType()));
- }
- }
- }
-
- /**
- * Returns the device associated with this service.
- *
- * @hide
- */
- /*package*/ BluetoothDevice getDevice() {
- return mDevice;
- }
-
- /**
- * Returns the device associated with this service.
- *
- * @hide
- */
- /*package*/ void setDevice(BluetoothDevice device) {
- mDevice = device;
- }
-
- /**
- * Add an included service to this service.
- *
- * @param service The service to be added
- * @return true, if the included service was added to the service
- */
- @RequiresLegacyBluetoothPermission
- public boolean addService(BluetoothGattService service) {
- mIncludedServices.add(service);
- return true;
- }
-
- /**
- * Add a characteristic to this service.
- *
- * @param characteristic The characteristics to be added
- * @return true, if the characteristic was added to the service
- */
- @RequiresLegacyBluetoothPermission
- public boolean addCharacteristic(BluetoothGattCharacteristic characteristic) {
- mCharacteristics.add(characteristic);
- characteristic.setService(this);
- return true;
- }
-
- /**
- * Get characteristic by UUID and instanceId.
- *
- * @hide
- */
- /*package*/ BluetoothGattCharacteristic getCharacteristic(UUID uuid, int instanceId) {
- for (BluetoothGattCharacteristic characteristic : mCharacteristics) {
- if (uuid.equals(characteristic.getUuid())
- && characteristic.getInstanceId() == instanceId) {
- return characteristic;
- }
- }
- return null;
- }
-
- /**
- * Force the instance ID.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public void setInstanceId(int instanceId) {
- mInstanceId = instanceId;
- }
-
- /**
- * Get the handle count override (conformance testing.
- *
- * @hide
- */
- /*package*/ int getHandles() {
- return mHandles;
- }
-
- /**
- * Force the number of handles to reserve for this service.
- * This is needed for conformance testing only.
- *
- * @hide
- */
- public void setHandles(int handles) {
- mHandles = handles;
- }
-
- /**
- * Add an included service to the internal map.
- *
- * @hide
- */
- public void addIncludedService(BluetoothGattService includedService) {
- mIncludedServices.add(includedService);
- }
-
- /**
- * Returns the UUID of this service
- *
- * @return UUID of this service
- */
- public UUID getUuid() {
- return mUuid;
- }
-
- /**
- * Returns the instance ID for this service
- *
- * <p>If a remote device offers multiple services with the same UUID
- * (ex. multiple battery services for different batteries), the instance
- * ID is used to distuinguish services.
- *
- * @return Instance ID of this service
- */
- public int getInstanceId() {
- return mInstanceId;
- }
-
- /**
- * Get the type of this service (primary/secondary)
- */
- public int getType() {
- return mServiceType;
- }
-
- /**
- * Get the list of included GATT services for this service.
- *
- * @return List of included services or empty list if no included services were discovered.
- */
- public List<BluetoothGattService> getIncludedServices() {
- return mIncludedServices;
- }
-
- /**
- * Returns a list of characteristics included in this service.
- *
- * @return Characteristics included in this service
- */
- public List<BluetoothGattCharacteristic> getCharacteristics() {
- return mCharacteristics;
- }
-
- /**
- * Returns a characteristic with a given UUID out of the list of
- * characteristics offered by this service.
- *
- * <p>This is a convenience function to allow access to a given characteristic
- * without enumerating over the list returned by {@link #getCharacteristics}
- * manually.
- *
- * <p>If a remote service offers multiple characteristics with the same
- * UUID, the first instance of a characteristic with the given UUID
- * is returned.
- *
- * @return GATT characteristic object or null if no characteristic with the given UUID was
- * found.
- */
- public BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
- for (BluetoothGattCharacteristic characteristic : mCharacteristics) {
- if (uuid.equals(characteristic.getUuid())) {
- return characteristic;
- }
- }
- return null;
- }
-
- /**
- * Returns whether the uuid of the service should be advertised.
- *
- * @hide
- */
- public boolean isAdvertisePreferred() {
- return mAdvertisePreferred;
- }
-
- /**
- * Set whether the service uuid should be advertised.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public void setAdvertisePreferred(boolean advertisePreferred) {
- mAdvertisePreferred = advertisePreferred;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
deleted file mode 100644
index 2ed1eb4..0000000
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ /dev/null
@@ -1,1516 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.util.CloseGuard;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Public API for controlling the Bluetooth Headset Service. This includes both
- * Bluetooth Headset and Handsfree (v1.5) profiles.
- *
- * <p>BluetoothHeadset is a proxy object for controlling the Bluetooth Headset
- * Service via IPC.
- *
- * <p> Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHeadset proxy object. Use
- * {@link BluetoothAdapter#closeProfileProxy} to close the service connection.
- *
- * <p> Android only supports one connected Bluetooth Headset at a time.
- * Each method is protected with its appropriate permission.
- */
-public final class BluetoothHeadset implements BluetoothProfile {
- private static final String TAG = "BluetoothHeadset";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the Headset
- * profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.headset.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * Intent used to broadcast the change in the Audio Connection state of the
- * HFP profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_AUDIO_CONNECTED}, {@link #STATE_AUDIO_DISCONNECTED},
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_AUDIO_STATE_CHANGED =
- "android.bluetooth.headset.profile.action.AUDIO_STATE_CHANGED";
-
- /**
- * Intent used to broadcast the selection of a connected device as active.
- *
- * <p>This intent will have one extra:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
- * be null if no device is active. </li>
- * </ul>
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage(trackingBug = 171933273)
- public static final String ACTION_ACTIVE_DEVICE_CHANGED =
- "android.bluetooth.headset.profile.action.ACTIVE_DEVICE_CHANGED";
-
- /**
- * Intent used to broadcast that the headset has posted a
- * vendor-specific event.
- *
- * <p>This intent will have 4 extras and 1 category.
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote Bluetooth Device
- * </li>
- * <li> {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD} - The vendor
- * specific command </li>
- * <li> {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE} - The AT
- * command type which can be one of {@link #AT_CMD_TYPE_READ},
- * {@link #AT_CMD_TYPE_TEST}, or {@link #AT_CMD_TYPE_SET},
- * {@link #AT_CMD_TYPE_BASIC},{@link #AT_CMD_TYPE_ACTION}. </li>
- * <li> {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS} - Command
- * arguments. </li>
- * </ul>
- *
- * <p> The category is the Company ID of the vendor defining the
- * vendor-specific command. {@link BluetoothAssignedNumbers}
- *
- * For example, for Plantronics specific events
- * Category will be {@link #VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY}.55
- *
- * <p> For example, an AT+XEVENT=foo,3 will get translated into
- * <ul>
- * <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD = +XEVENT </li>
- * <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE = AT_CMD_TYPE_SET </li>
- * <li> EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS = foo, 3 </li>
- * </ul>
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_VENDOR_SPECIFIC_HEADSET_EVENT =
- "android.bluetooth.headset.action.VENDOR_SPECIFIC_HEADSET_EVENT";
-
- /**
- * A String extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
- * intents that contains the name of the vendor-specific command.
- */
- public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD =
- "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD";
-
- /**
- * An int extra field in {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
- * intents that contains the AT command type of the vendor-specific command.
- */
- public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE =
- "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE";
-
- /**
- * AT command type READ used with
- * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
- * For example, AT+VGM?. There are no arguments for this command type.
- */
- public static final int AT_CMD_TYPE_READ = 0;
-
- /**
- * AT command type TEST used with
- * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
- * For example, AT+VGM=?. There are no arguments for this command type.
- */
- public static final int AT_CMD_TYPE_TEST = 1;
-
- /**
- * AT command type SET used with
- * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
- * For example, AT+VGM=<args>.
- */
- public static final int AT_CMD_TYPE_SET = 2;
-
- /**
- * AT command type BASIC used with
- * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
- * For example, ATD. Single character commands and everything following the
- * character are arguments.
- */
- public static final int AT_CMD_TYPE_BASIC = 3;
-
- /**
- * AT command type ACTION used with
- * {@link #EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_CMD_TYPE}
- * For example, AT+CHUP. There are no arguments for action commands.
- */
- public static final int AT_CMD_TYPE_ACTION = 4;
-
- /**
- * A Parcelable String array extra field in
- * {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT} intents that contains
- * the arguments to the vendor-specific command.
- */
- public static final String EXTRA_VENDOR_SPECIFIC_HEADSET_EVENT_ARGS =
- "android.bluetooth.headset.extra.VENDOR_SPECIFIC_HEADSET_EVENT_ARGS";
-
- /**
- * The intent category to be used with {@link #ACTION_VENDOR_SPECIFIC_HEADSET_EVENT}
- * for the companyId
- */
- public static final String VENDOR_SPECIFIC_HEADSET_EVENT_COMPANY_ID_CATEGORY =
- "android.bluetooth.headset.intent.category.companyid";
-
- /**
- * A vendor-specific command for unsolicited result code.
- */
- public static final String VENDOR_RESULT_CODE_COMMAND_ANDROID = "+ANDROID";
-
- /**
- * A vendor-specific AT command
- *
- * @hide
- */
- public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XAPL = "+XAPL";
-
- /**
- * A vendor-specific AT command
- *
- * @hide
- */
- public static final String VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV = "+IPHONEACCEV";
-
- /**
- * Battery level indicator associated with
- * {@link #VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV}
- *
- * @hide
- */
- public static final int VENDOR_SPECIFIC_HEADSET_EVENT_IPHONEACCEV_BATTERY_LEVEL = 1;
-
- /**
- * A vendor-specific AT command
- *
- * @hide
- */
- public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT = "+XEVENT";
-
- /**
- * Battery level indicator associated with {@link #VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT}
- *
- * @hide
- */
- public static final String VENDOR_SPECIFIC_HEADSET_EVENT_XEVENT_BATTERY_LEVEL = "BATTERY";
-
- /**
- * Headset state when SCO audio is not connected.
- * This state can be one of
- * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
- * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
- */
- public static final int STATE_AUDIO_DISCONNECTED = 10;
-
- /**
- * Headset state when SCO audio is connecting.
- * This state can be one of
- * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
- * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
- */
- public static final int STATE_AUDIO_CONNECTING = 11;
-
- /**
- * Headset state when SCO audio is connected.
- * This state can be one of
- * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
- * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
- */
- public static final int STATE_AUDIO_CONNECTED = 12;
-
- /**
- * Intent used to broadcast the headset's indicator status
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_HF_INDICATORS_IND_ID} - The Assigned number of headset Indicator which
- * is supported by the headset ( as indicated by AT+BIND command in the SLC
- * sequence) or whose value is changed (indicated by AT+BIEV command) </li>
- * <li> {@link #EXTRA_HF_INDICATORS_IND_VALUE} - Updated value of headset indicator. </li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - Remote device. </li>
- * </ul>
- * <p>{@link #EXTRA_HF_INDICATORS_IND_ID} is defined by Bluetooth SIG and each of the indicators
- * are given an assigned number. Below shows the assigned number of Indicator added so far
- * - Enhanced Safety - 1, Valid Values: 0 - Disabled, 1 - Enabled
- * - Battery Level - 2, Valid Values: 0~100 - Remaining level of Battery
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HF_INDICATORS_VALUE_CHANGED =
- "android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED";
-
- /**
- * A int extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
- * intents that contains the assigned number of the headset indicator as defined by
- * Bluetooth SIG that is being sent. Value range is 0-65535 as defined in HFP 1.7
- *
- * @hide
- */
- public static final String EXTRA_HF_INDICATORS_IND_ID =
- "android.bluetooth.headset.extra.HF_INDICATORS_IND_ID";
-
- /**
- * A int extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
- * intents that contains the value of the Headset indicator that is being sent.
- *
- * @hide
- */
- public static final String EXTRA_HF_INDICATORS_IND_VALUE =
- "android.bluetooth.headset.extra.HF_INDICATORS_IND_VALUE";
-
- private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100;
- private static final int MESSAGE_HEADSET_SERVICE_DISCONNECTED = 101;
-
- private final CloseGuard mCloseGuard = new CloseGuard();
-
- private Context mContext;
- private ServiceListener mServiceListener;
- private volatile IBluetoothHeadset mService;
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
- new IBluetoothStateChangeCallback.Stub() {
- public void onBluetoothStateChange(boolean up) {
- if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
- if (!up) {
- doUnbind();
- } else {
- doBind();
- }
- }
- };
-
- /**
- * Create a BluetoothHeadset proxy object.
- */
- /* package */ BluetoothHeadset(Context context, ServiceListener l, BluetoothAdapter adapter) {
- mContext = context;
- mServiceListener = l;
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
-
- // Preserve legacy compatibility where apps were depending on
- // registerStateChangeCallback() performing a permissions check which
- // has been relaxed in modern platform versions
- if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R
- && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Need BLUETOOTH permission");
- }
-
- IBluetoothManager mgr = mAdapter.getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- doBind();
- mCloseGuard.open("close");
- }
-
- private boolean doBind() {
- synchronized (mConnection) {
- if (mService == null) {
- if (VDBG) Log.d(TAG, "Binding service...");
- try {
- return mAdapter.getBluetoothManager().bindBluetoothProfileService(
- BluetoothProfile.HEADSET, mConnection);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to bind HeadsetService", e);
- }
- }
- }
- return false;
- }
-
- private void doUnbind() {
- synchronized (mConnection) {
- if (mService != null) {
- if (VDBG) Log.d(TAG, "Unbinding service...");
- try {
- mAdapter.getBluetoothManager().unbindBluetoothProfileService(
- BluetoothProfile.HEADSET, mConnection);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to unbind HeadsetService", e);
- } finally {
- mService = null;
- }
- }
- }
- }
-
- /**
- * Close the connection to the backing service.
- * Other public functions of BluetoothHeadset will return default error
- * results once close() has been called. Multiple invocations of close()
- * are ok.
- */
- @UnsupportedAppUsage
- /*package*/ void close() {
- if (VDBG) log("close()");
-
- IBluetoothManager mgr = mAdapter.getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "", re);
- }
- }
- mServiceListener = null;
- doUnbind();
- mCloseGuard.close();
- }
-
- /** {@hide} */
- @Override
- protected void finalize() throws Throwable {
- mCloseGuard.warnIfOpen();
- close();
- }
-
- /**
- * Initiate connection to a profile of the remote bluetooth device.
- *
- * <p> Currently, the system supports only 1 connection to the
- * headset/handsfree profile. The API will automatically disconnect connected
- * devices before connecting.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is already connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that
- * connection state intent for the profile will be broadcasted with
- * the state. Users can get the connection state of the profile
- * from this intent.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connectWithAttribution(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnection from a profile
- *
- * <p> This API will return false in scenarios like the profile on the
- * Bluetooth device is not in connected state etc. When this API returns,
- * true, it is guaranteed that the connection state change
- * intent will be broadcasted with the state. Users can get the
- * disconnection state of the profile from this intent.
- *
- * <p> If the disconnection is initiated by a remote device, the state
- * will transition from {@link #STATE_CONNECTED} to
- * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
- * host (local) device the state will transition from
- * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
- * state {@link #STATE_DISCONNECTED}. The transition to
- * {@link #STATE_DISCONNECTING} can be used to distinguish between the
- * two scenarios.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnectWithAttribution(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothHeadset service = mService;
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevicesWithAttribution(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothHeadset service = mService;
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (VDBG) log("getConnectionState(" + device + ")");
- final IBluetoothHeadset service = mService;
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionStateWithAttribution(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
- * {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothHeadset service = mService;
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Checks whether the headset supports some form of noise reduction
- *
- * @param device Bluetooth device
- * @return true if echo cancellation and/or noise reduction is supported, false otherwise
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isNoiseReductionSupported(@NonNull BluetoothDevice device) {
- if (DBG) log("isNoiseReductionSupported()");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isNoiseReductionSupported(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Checks whether the headset supports voice recognition
- *
- * @param device Bluetooth device
- * @return true if voice recognition is supported, false otherwise
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isVoiceRecognitionSupported(@NonNull BluetoothDevice device) {
- if (DBG) log("isVoiceRecognitionSupported()");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isVoiceRecognitionSupported(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Start Bluetooth voice recognition. This methods sends the voice
- * recognition AT command to the headset and establishes the
- * audio connection.
- *
- * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
- * If this function returns true, this intent will be broadcasted with
- * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}.
- *
- * <p> {@link #EXTRA_STATE} will transition from
- * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when
- * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
- * in case of failure to establish the audio connection.
- *
- * @param device Bluetooth headset
- * @return false if there is no headset connected, or the connected headset doesn't support
- * voice recognition, or voice recognition is already started, or audio channel is occupied,
- * or on error, true otherwise
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public boolean startVoiceRecognition(BluetoothDevice device) {
- if (DBG) log("startVoiceRecognition()");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.startVoiceRecognition(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Stop Bluetooth Voice Recognition mode, and shut down the
- * Bluetooth audio path.
- *
- * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
- * If this function returns true, this intent will be broadcasted with
- * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
- *
- * @param device Bluetooth headset
- * @return false if there is no headset connected, or voice recognition has not started,
- * or voice recognition has ended on this headset, or on error, true otherwise
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean stopVoiceRecognition(BluetoothDevice device) {
- if (DBG) log("stopVoiceRecognition()");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.stopVoiceRecognition(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Check if Bluetooth SCO audio is connected.
- *
- * @param device Bluetooth headset
- * @return true if SCO is connected, false otherwise or on error
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isAudioConnected(BluetoothDevice device) {
- if (VDBG) log("isAudioConnected()");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isAudioConnected(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Indicates if current platform supports voice dialing over bluetooth SCO.
- *
- * @return true if voice dialing over bluetooth is supported, false otherwise.
- * @hide
- */
- public static boolean isBluetoothVoiceDialingEnabled(Context context) {
- return context.getResources().getBoolean(
- com.android.internal.R.bool.config_bluetooth_sco_off_call);
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothHeadset.STATE_AUDIO_DISCONNECTED,
- BluetoothHeadset.STATE_AUDIO_CONNECTING,
- BluetoothHeadset.STATE_AUDIO_CONNECTED,
- BluetoothStatusCodes.ERROR_TIMEOUT
- })
- public @interface GetAudioStateReturnValues {}
-
- /**
- * Get the current audio state of the Headset.
- *
- * @param device is the Bluetooth device for which the audio state is being queried
- * @return the audio state of the device or an error code
- * @throws IllegalArgumentException if the device is null
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @GetAudioStateReturnValues int getAudioState(@NonNull BluetoothDevice device) {
- if (VDBG) log("getAudioState");
- if (device == null) {
- throw new IllegalArgumentException("device cannot be null");
- }
- final IBluetoothHeadset service = mService;
- final int defaultValue = BluetoothHeadset.STATE_AUDIO_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (!isDisabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getAudioState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- throw e.rethrowFromSystemServer();
- } catch (TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- return BluetoothStatusCodes.ERROR_TIMEOUT;
- }
- }
- return defaultValue;
- }
-
- /**
- * Sets whether audio routing is allowed. When set to {@code false}, the AG will not route any
- * audio to the HF unless explicitly told to.
- * This method should be used in cases where the SCO channel is shared between multiple profiles
- * and must be delegated by a source knowledgeable
- * Note: This is an internal function and shouldn't be exposed
- *
- * @param allowed {@code true} if the profile can reroute audio, {@code false} otherwise.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setAudioRouteAllowed(boolean allowed) {
- if (VDBG) log("setAudioRouteAllowed");
- final IBluetoothHeadset service = mService;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.setAudioRouteAllowed(allowed, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Returns whether audio routing is allowed. see {@link #setAudioRouteAllowed(boolean)}.
- * Note: This is an internal function and shouldn't be exposed
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean getAudioRouteAllowed() {
- if (VDBG) log("getAudioRouteAllowed");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.getAudioRouteAllowed(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Force SCO audio to be opened regardless any other restrictions
- *
- * @param forced Whether or not SCO audio connection should be forced: True to force SCO audio
- * False to use SCO audio in normal manner
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setForceScoAudio(boolean forced) {
- if (VDBG) log("setForceScoAudio " + String.valueOf(forced));
- final IBluetoothHeadset service = mService;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.setForceScoAudio(forced, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothStatusCodes.SUCCESS,
- BluetoothStatusCodes.ERROR_UNKNOWN,
- BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
- BluetoothStatusCodes.ERROR_TIMEOUT,
- BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_CONNECTED,
- BluetoothStatusCodes.ERROR_NO_ACTIVE_DEVICES,
- BluetoothStatusCodes.ERROR_NOT_ACTIVE_DEVICE,
- BluetoothStatusCodes.ERROR_AUDIO_ROUTE_BLOCKED,
- BluetoothStatusCodes.ERROR_CALL_ACTIVE,
- BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED
- })
- public @interface ConnectAudioReturnValues {}
-
- /**
- * Initiates a connection of SCO audio to the current active HFP device. The active HFP device
- * can be identified with {@link BluetoothAdapter#getActiveDevices(int)}.
- * <p>
- * If this function returns {@link BluetoothStatusCodes#SUCCESS}, the intent
- * {@link #ACTION_AUDIO_STATE_CHANGED} will be broadcasted twice. First with {@link #EXTRA_STATE}
- * set to {@link #STATE_AUDIO_CONNECTING}. This will be followed by a broadcast with
- * {@link #EXTRA_STATE} set to either {@link #STATE_AUDIO_CONNECTED} if the audio connection is
- * established or {@link #STATE_AUDIO_DISCONNECTED} if there was a failure in establishing the
- * audio connection.
- *
- * @return whether the connection was successfully initiated or an error code on failure
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectAudioReturnValues int connectAudio() {
- if (VDBG) log("connectAudio()");
- final IBluetoothHeadset service = mService;
- final int defaultValue = BluetoothStatusCodes.ERROR_UNKNOWN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.connectAudio(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- throw e.rethrowFromSystemServer();
- } catch (TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- return BluetoothStatusCodes.ERROR_TIMEOUT;
- }
- }
- return defaultValue;
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- BluetoothStatusCodes.SUCCESS,
- BluetoothStatusCodes.ERROR_UNKNOWN,
- BluetoothStatusCodes.ERROR_PROFILE_SERVICE_NOT_BOUND,
- BluetoothStatusCodes.ERROR_TIMEOUT,
- BluetoothStatusCodes.ERROR_PROFILE_NOT_CONNECTED,
- BluetoothStatusCodes.ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED
- })
- public @interface DisconnectAudioReturnValues {}
-
- /**
- * Initiates a disconnection of HFP SCO audio from actively connected devices. It also tears
- * down voice recognition or virtual voice call, if any exists.
- *
- * <p> If this function returns {@link BluetoothStatusCodes#SUCCESS}, the intent
- * {@link #ACTION_AUDIO_STATE_CHANGED} will be broadcasted with {@link #EXTRA_STATE} set to
- * {@link #STATE_AUDIO_DISCONNECTED}.
- *
- * @return whether the disconnection was initiated successfully or an error code on failure
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @DisconnectAudioReturnValues int disconnectAudio() {
- if (VDBG) log("disconnectAudio()");
- final IBluetoothHeadset service = mService;
- final int defaultValue = BluetoothStatusCodes.ERROR_UNKNOWN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.disconnectAudio(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- throw e.rethrowFromSystemServer();
- } catch (TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- return BluetoothStatusCodes.ERROR_TIMEOUT;
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiates a SCO channel connection as a virtual voice call to the current active device
- * Active handsfree device will be notified of incoming call and connected call.
- *
- * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
- * If this function returns true, this intent will be broadcasted with
- * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_CONNECTING}.
- *
- * <p> {@link #EXTRA_STATE} will transition from
- * {@link #STATE_AUDIO_CONNECTING} to {@link #STATE_AUDIO_CONNECTED} when
- * audio connection is established and to {@link #STATE_AUDIO_DISCONNECTED}
- * in case of failure to establish the audio connection.
- *
- * @return true if successful, false if one of the following case applies
- * - SCO audio is not idle (connecting or connected)
- * - virtual call has already started
- * - there is no active device
- * - a Telecom managed call is going on
- * - binder is dead or Bluetooth is disabled or other error
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public boolean startScoUsingVirtualVoiceCall() {
- if (DBG) log("startScoUsingVirtualVoiceCall()");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.startScoUsingVirtualVoiceCall(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Terminates an ongoing SCO connection and the associated virtual call.
- *
- * <p> Users can listen to {@link #ACTION_AUDIO_STATE_CHANGED}.
- * If this function returns true, this intent will be broadcasted with
- * {@link #EXTRA_STATE} set to {@link #STATE_AUDIO_DISCONNECTED}.
- *
- * @return true if successful, false if one of the following case applies
- * - virtual voice call is not started or has ended
- * - binder is dead or Bluetooth is disabled or other error
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public boolean stopScoUsingVirtualVoiceCall() {
- if (DBG) log("stopScoUsingVirtualVoiceCall()");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.stopScoUsingVirtualVoiceCall(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Notify Headset of phone state change.
- * This is a backdoor for phone app to call BluetoothHeadset since
- * there is currently not a good way to get precise call state change outside
- * of phone app.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public void phoneStateChanged(int numActive, int numHeld, int callState, String number,
- int type, String name) {
- final IBluetoothHeadset service = mService;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- service.phoneStateChanged(numActive, numHeld, callState, number, type, name,
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Send Headset of CLCC response
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- public void clccResponse(int index, int direction, int status, int mode, boolean mpty,
- String number, int type) {
- final IBluetoothHeadset service = mService;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.clccResponse(index, direction, status, mode, mpty, number, type,
- mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Sends a vendor-specific unsolicited result code to the headset.
- *
- * <p>The actual string to be sent is <code>command + ": " + arg</code>. For example, if {@code
- * command} is {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} and {@code arg} is {@code "0"}, the
- * string <code>"+ANDROID: 0"</code> will be sent.
- *
- * <p>Currently only {@link #VENDOR_RESULT_CODE_COMMAND_ANDROID} is allowed as {@code command}.
- *
- * @param device Bluetooth headset.
- * @param command A vendor-specific command.
- * @param arg The argument that will be attached to the command.
- * @return {@code false} if there is no headset connected, or if the command is not an allowed
- * vendor-specific unsolicited result code, or on error. {@code true} otherwise.
- * @throws IllegalArgumentException if {@code command} is {@code null}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean sendVendorSpecificResultCode(BluetoothDevice device, String command,
- String arg) {
- if (DBG) {
- log("sendVendorSpecificResultCode()");
- }
- if (command == null) {
- throw new IllegalArgumentException("command is null");
- }
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.sendVendorSpecificResultCode(device, command, arg,
- mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Select a connected device as active.
- *
- * The active device selection is per profile. An active device's
- * purpose is profile-specific. For example, in HFP and HSP profiles,
- * it is the device used for phone call audio. If a remote device is not
- * connected, it cannot be selected as active.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is not connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that the
- * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
- * with the active device.
- *
- * @param device Remote Bluetooth Device, could be null if phone call audio should not be
- * streamed to a headset
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.MODIFY_PHONE_STATE,
- })
- @UnsupportedAppUsage(trackingBug = 171933273)
- public boolean setActiveDevice(@Nullable BluetoothDevice device) {
- if (DBG) {
- Log.d(TAG, "setActiveDevice: " + device);
- }
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && (device == null || isValidDevice(device))) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setActiveDevice(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the connected device that is active.
- *
- * @return the connected device that is active or null if no device
- * is active.
- * @hide
- */
- @UnsupportedAppUsage(trackingBug = 171933273)
- @Nullable
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothDevice getActiveDevice() {
- if (VDBG) Log.d(TAG, "getActiveDevice");
- final IBluetoothHeadset service = mService;
- final BluetoothDevice defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<BluetoothDevice> recv =
- new SynchronousResultReceiver();
- service.getActiveDevice(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Check if in-band ringing is currently enabled. In-band ringing could be disabled during an
- * active connection.
- *
- * @return true if in-band ringing is enabled, false if in-band ringing is disabled
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean isInbandRingingEnabled() {
- if (DBG) log("isInbandRingingEnabled()");
- final IBluetoothHeadset service = mService;
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isInbandRingingEnabled(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Check if in-band ringing is supported for this platform.
- *
- * @return true if in-band ringing is supported, false if in-band ringing is not supported
- * @hide
- */
- public static boolean isInbandRingingSupported(Context context) {
- return context.getResources().getBoolean(
- com.android.internal.R.bool.config_bluetooth_hfp_inband_ringing_support);
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final IBluetoothProfileServiceConnection mConnection =
- new IBluetoothProfileServiceConnection.Stub() {
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- if (DBG) Log.d(TAG, "Proxy object connected");
- mService = IBluetoothHeadset.Stub.asInterface(service);
- mHandler.sendMessage(mHandler.obtainMessage(
- MESSAGE_HEADSET_SERVICE_CONNECTED));
- }
-
- @Override
- public void onServiceDisconnected(ComponentName className) {
- if (DBG) Log.d(TAG, "Proxy object disconnected");
- doUnbind();
- mHandler.sendMessage(mHandler.obtainMessage(
- MESSAGE_HEADSET_SERVICE_DISCONNECTED));
- }
- };
-
- @UnsupportedAppUsage
- private boolean isEnabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_ON;
- }
-
- private boolean isDisabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_OFF;
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_HEADSET_SERVICE_CONNECTED: {
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.HEADSET,
- BluetoothHeadset.this);
- }
- break;
- }
- case MESSAGE_HEADSET_SERVICE_DISCONNECTED: {
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET);
- }
- break;
- }
- }
- }
- };
-}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
deleted file mode 100644
index 7d7a7f7..0000000
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ /dev/null
@@ -1,1356 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Public API to control Hands Free Profile (HFP role only).
- * <p>
- * This class defines methods that shall be used by application to manage profile
- * connection, calls states and calls actions.
- * <p>
- *
- * @hide
- */
-public final class BluetoothHeadsetClient implements BluetoothProfile {
- private static final String TAG = "BluetoothHeadsetClient";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Intent sent whenever connection to remote changes.
- *
- * <p>It includes two extras:
- * <code>BluetoothProfile.EXTRA_PREVIOUS_STATE</code>
- * and <code>BluetoothProfile.EXTRA_STATE</code>, which
- * are mandatory.
- * <p>There are also non mandatory feature extras:
- * {@link #EXTRA_AG_FEATURE_3WAY_CALLING},
- * {@link #EXTRA_AG_FEATURE_VOICE_RECOGNITION},
- * {@link #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT},
- * {@link #EXTRA_AG_FEATURE_REJECT_CALL},
- * {@link #EXTRA_AG_FEATURE_ECC},
- * {@link #EXTRA_AG_FEATURE_RESPONSE_AND_HOLD},
- * {@link #EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL},
- * {@link #EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL},
- * {@link #EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT},
- * {@link #EXTRA_AG_FEATURE_MERGE},
- * {@link #EXTRA_AG_FEATURE_MERGE_AND_DETACH},
- * sent as boolean values only when <code>EXTRA_STATE</code>
- * is set to <code>STATE_CONNECTED</code>.</p>
- *
- * <p>Note that features supported by AG are being sent as
- * booleans with value <code>true</code>,
- * and not supported ones are <strong>not</strong> being sent at all.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.headsetclient.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * Intent sent whenever audio state changes.
- *
- * <p>It includes two mandatory extras:
- * {@link BluetoothProfile#EXTRA_STATE},
- * {@link BluetoothProfile#EXTRA_PREVIOUS_STATE},
- * with possible values:
- * {@link #STATE_AUDIO_CONNECTING},
- * {@link #STATE_AUDIO_CONNECTED},
- * {@link #STATE_AUDIO_DISCONNECTED}</p>
- * <p>When <code>EXTRA_STATE</code> is set
- * to </code>STATE_AUDIO_CONNECTED</code>,
- * it also includes {@link #EXTRA_AUDIO_WBS}
- * indicating wide band speech support.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_AUDIO_STATE_CHANGED =
- "android.bluetooth.headsetclient.profile.action.AUDIO_STATE_CHANGED";
-
- /**
- * Intent sending updates of the Audio Gateway state.
- * Each extra is being sent only when value it
- * represents has been changed recently on AG.
- * <p>It can contain one or more of the following extras:
- * {@link #EXTRA_NETWORK_STATUS},
- * {@link #EXTRA_NETWORK_SIGNAL_STRENGTH},
- * {@link #EXTRA_NETWORK_ROAMING},
- * {@link #EXTRA_BATTERY_LEVEL},
- * {@link #EXTRA_OPERATOR_NAME},
- * {@link #EXTRA_VOICE_RECOGNITION},
- * {@link #EXTRA_IN_BAND_RING}</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_AG_EVENT =
- "android.bluetooth.headsetclient.profile.action.AG_EVENT";
-
- /**
- * Intent sent whenever state of a call changes.
- *
- * <p>It includes:
- * {@link #EXTRA_CALL},
- * with value of {@link BluetoothHeadsetClientCall} instance,
- * representing actual call state.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CALL_CHANGED =
- "android.bluetooth.headsetclient.profile.action.AG_CALL_CHANGED";
-
- /**
- * Intent that notifies about the result of the last issued action.
- * Please note that not every action results in explicit action result code being sent.
- * Instead other notifications about new Audio Gateway state might be sent,
- * like <code>ACTION_AG_EVENT</code> with <code>EXTRA_VOICE_RECOGNITION</code> value
- * when for example user started voice recognition from HF unit.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_RESULT =
- "android.bluetooth.headsetclient.profile.action.RESULT";
-
- /**
- * Intent that notifies about vendor specific event arrival. Events not defined in
- * HFP spec will be matched with supported vendor event list and this intent will
- * be broadcasted upon a match. Supported vendor events are of format of
- * of "+eventCode" or "+eventCode=xxxx" or "+eventCode:=xxxx".
- * Vendor event can be a response to an vendor specific command or unsolicited.
- *
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_VENDOR_SPECIFIC_HEADSETCLIENT_EVENT =
- "android.bluetooth.headsetclient.profile.action.VENDOR_SPECIFIC_EVENT";
-
- /**
- * Intent that notifies about the number attached to the last voice tag
- * recorded on AG.
- *
- * <p>It contains:
- * {@link #EXTRA_NUMBER},
- * with a <code>String</code> value representing phone number.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_LAST_VTAG =
- "android.bluetooth.headsetclient.profile.action.LAST_VTAG";
-
- public static final int STATE_AUDIO_DISCONNECTED = 0;
- public static final int STATE_AUDIO_CONNECTING = 1;
- public static final int STATE_AUDIO_CONNECTED = 2;
-
- /**
- * Extra with information if connected audio is WBS.
- * <p>Possible values: <code>true</code>,
- * <code>false</code>.</p>
- */
- public static final String EXTRA_AUDIO_WBS =
- "android.bluetooth.headsetclient.extra.AUDIO_WBS";
-
- /**
- * Extra for AG_EVENT indicates network status.
- * <p>Value: 0 - network unavailable,
- * 1 - network available </p>
- */
- public static final String EXTRA_NETWORK_STATUS =
- "android.bluetooth.headsetclient.extra.NETWORK_STATUS";
- /**
- * Extra for AG_EVENT intent indicates network signal strength.
- * <p>Value: <code>Integer</code> representing signal strength.</p>
- */
- public static final String EXTRA_NETWORK_SIGNAL_STRENGTH =
- "android.bluetooth.headsetclient.extra.NETWORK_SIGNAL_STRENGTH";
- /**
- * Extra for AG_EVENT intent indicates roaming state.
- * <p>Value: 0 - no roaming
- * 1 - active roaming</p>
- */
- public static final String EXTRA_NETWORK_ROAMING =
- "android.bluetooth.headsetclient.extra.NETWORK_ROAMING";
- /**
- * Extra for AG_EVENT intent indicates the battery level.
- * <p>Value: <code>Integer</code> representing signal strength.</p>
- */
- public static final String EXTRA_BATTERY_LEVEL =
- "android.bluetooth.headsetclient.extra.BATTERY_LEVEL";
- /**
- * Extra for AG_EVENT intent indicates operator name.
- * <p>Value: <code>String</code> representing operator name.</p>
- */
- public static final String EXTRA_OPERATOR_NAME =
- "android.bluetooth.headsetclient.extra.OPERATOR_NAME";
- /**
- * Extra for AG_EVENT intent indicates voice recognition state.
- * <p>Value:
- * 0 - voice recognition stopped,
- * 1 - voice recognition started.</p>
- */
- public static final String EXTRA_VOICE_RECOGNITION =
- "android.bluetooth.headsetclient.extra.VOICE_RECOGNITION";
- /**
- * Extra for AG_EVENT intent indicates in band ring state.
- * <p>Value:
- * 0 - in band ring tone not supported, or
- * 1 - in band ring tone supported.</p>
- */
- public static final String EXTRA_IN_BAND_RING =
- "android.bluetooth.headsetclient.extra.IN_BAND_RING";
-
- /**
- * Extra for AG_EVENT intent indicates subscriber info.
- * <p>Value: <code>String</code> containing subscriber information.</p>
- */
- public static final String EXTRA_SUBSCRIBER_INFO =
- "android.bluetooth.headsetclient.extra.SUBSCRIBER_INFO";
-
- /**
- * Extra for AG_CALL_CHANGED intent indicates the
- * {@link BluetoothHeadsetClientCall} object that has changed.
- */
- public static final String EXTRA_CALL =
- "android.bluetooth.headsetclient.extra.CALL";
-
- /**
- * Extra for ACTION_LAST_VTAG intent.
- * <p>Value: <code>String</code> representing phone number
- * corresponding to last voice tag recorded on AG</p>
- */
- public static final String EXTRA_NUMBER =
- "android.bluetooth.headsetclient.extra.NUMBER";
-
- /**
- * Extra for ACTION_RESULT intent that shows the result code of
- * last issued action.
- * <p>Possible results:
- * {@link #ACTION_RESULT_OK},
- * {@link #ACTION_RESULT_ERROR},
- * {@link #ACTION_RESULT_ERROR_NO_CARRIER},
- * {@link #ACTION_RESULT_ERROR_BUSY},
- * {@link #ACTION_RESULT_ERROR_NO_ANSWER},
- * {@link #ACTION_RESULT_ERROR_DELAYED},
- * {@link #ACTION_RESULT_ERROR_BLACKLISTED},
- * {@link #ACTION_RESULT_ERROR_CME}</p>
- */
- public static final String EXTRA_RESULT_CODE =
- "android.bluetooth.headsetclient.extra.RESULT_CODE";
-
- /**
- * Extra for ACTION_RESULT intent that shows the extended result code of
- * last issued action.
- * <p>Value: <code>Integer</code> - error code.</p>
- */
- public static final String EXTRA_CME_CODE =
- "android.bluetooth.headsetclient.extra.CME_CODE";
-
- /**
- * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
- * indicates vendor ID.
- */
- public static final String EXTRA_VENDOR_ID =
- "android.bluetooth.headsetclient.extra.VENDOR_ID";
-
- /**
- * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
- * indicates vendor event code.
- */
- public static final String EXTRA_VENDOR_EVENT_CODE =
- "android.bluetooth.headsetclient.extra.VENDOR_EVENT_CODE";
-
- /**
- * Extra for VENDOR_SPECIFIC_HEADSETCLIENT_EVENT intent that
- * contains full vendor event including event code and full arguments.
- */
- public static final String EXTRA_VENDOR_EVENT_FULL_ARGS =
- "android.bluetooth.headsetclient.extra.VENDOR_EVENT_FULL_ARGS";
-
-
- /* Extras for AG_FEATURES, extras type is boolean */
- // TODO verify if all of those are actually useful
- /**
- * AG feature: three way calling.
- */
- public static final String EXTRA_AG_FEATURE_3WAY_CALLING =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_3WAY_CALLING";
- /**
- * AG feature: voice recognition.
- */
- public static final String EXTRA_AG_FEATURE_VOICE_RECOGNITION =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_VOICE_RECOGNITION";
- /**
- * AG feature: fetching phone number for voice tagging procedure.
- */
- public static final String EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT";
- /**
- * AG feature: ability to reject incoming call.
- */
- public static final String EXTRA_AG_FEATURE_REJECT_CALL =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_REJECT_CALL";
- /**
- * AG feature: enhanced call handling (terminate specific call, private consultation).
- */
- public static final String EXTRA_AG_FEATURE_ECC =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ECC";
- /**
- * AG feature: response and hold.
- */
- public static final String EXTRA_AG_FEATURE_RESPONSE_AND_HOLD =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RESPONSE_AND_HOLD";
- /**
- * AG call handling feature: accept held or waiting call in three way calling scenarios.
- */
- public static final String EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_ACCEPT_HELD_OR_WAITING_CALL";
- /**
- * AG call handling feature: release held or waiting call in three way calling scenarios.
- */
- public static final String EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_HELD_OR_WAITING_CALL";
- /**
- * AG call handling feature: release active call and accept held or waiting call in three way
- * calling scenarios.
- */
- public static final String EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_RELEASE_AND_ACCEPT";
- /**
- * AG call handling feature: merge two calls, held and active - multi party conference mode.
- */
- public static final String EXTRA_AG_FEATURE_MERGE =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE";
- /**
- * AG call handling feature: merge calls and disconnect from multi party
- * conversation leaving peers connected to each other.
- * Note that this feature needs to be supported by mobile network operator
- * as it requires connection and billing transfer.
- */
- public static final String EXTRA_AG_FEATURE_MERGE_AND_DETACH =
- "android.bluetooth.headsetclient.extra.EXTRA_AG_FEATURE_MERGE_AND_DETACH";
-
- /* Action result codes */
- public static final int ACTION_RESULT_OK = 0;
- public static final int ACTION_RESULT_ERROR = 1;
- public static final int ACTION_RESULT_ERROR_NO_CARRIER = 2;
- public static final int ACTION_RESULT_ERROR_BUSY = 3;
- public static final int ACTION_RESULT_ERROR_NO_ANSWER = 4;
- public static final int ACTION_RESULT_ERROR_DELAYED = 5;
- public static final int ACTION_RESULT_ERROR_BLACKLISTED = 6;
- public static final int ACTION_RESULT_ERROR_CME = 7;
-
- /* Detailed CME error codes */
- public static final int CME_PHONE_FAILURE = 0;
- public static final int CME_NO_CONNECTION_TO_PHONE = 1;
- public static final int CME_OPERATION_NOT_ALLOWED = 3;
- public static final int CME_OPERATION_NOT_SUPPORTED = 4;
- public static final int CME_PHSIM_PIN_REQUIRED = 5;
- public static final int CME_PHFSIM_PIN_REQUIRED = 6;
- public static final int CME_PHFSIM_PUK_REQUIRED = 7;
- public static final int CME_SIM_NOT_INSERTED = 10;
- public static final int CME_SIM_PIN_REQUIRED = 11;
- public static final int CME_SIM_PUK_REQUIRED = 12;
- public static final int CME_SIM_FAILURE = 13;
- public static final int CME_SIM_BUSY = 14;
- public static final int CME_SIM_WRONG = 15;
- public static final int CME_INCORRECT_PASSWORD = 16;
- public static final int CME_SIM_PIN2_REQUIRED = 17;
- public static final int CME_SIM_PUK2_REQUIRED = 18;
- public static final int CME_MEMORY_FULL = 20;
- public static final int CME_INVALID_INDEX = 21;
- public static final int CME_NOT_FOUND = 22;
- public static final int CME_MEMORY_FAILURE = 23;
- public static final int CME_TEXT_STRING_TOO_LONG = 24;
- public static final int CME_INVALID_CHARACTER_IN_TEXT_STRING = 25;
- public static final int CME_DIAL_STRING_TOO_LONG = 26;
- public static final int CME_INVALID_CHARACTER_IN_DIAL_STRING = 27;
- public static final int CME_NO_NETWORK_SERVICE = 30;
- public static final int CME_NETWORK_TIMEOUT = 31;
- public static final int CME_EMERGENCY_SERVICE_ONLY = 32;
- public static final int CME_NO_SIMULTANOUS_VOIP_CS_CALLS = 33;
- public static final int CME_NOT_SUPPORTED_FOR_VOIP = 34;
- public static final int CME_SIP_RESPONSE_CODE = 35;
- public static final int CME_NETWORK_PERSONALIZATION_PIN_REQUIRED = 40;
- public static final int CME_NETWORK_PERSONALIZATION_PUK_REQUIRED = 41;
- public static final int CME_NETWORK_SUBSET_PERSONALIZATION_PIN_REQUIRED = 42;
- public static final int CME_NETWORK_SUBSET_PERSONALIZATION_PUK_REQUIRED = 43;
- public static final int CME_SERVICE_PROVIDER_PERSONALIZATION_PIN_REQUIRED = 44;
- public static final int CME_SERVICE_PROVIDER_PERSONALIZATION_PUK_REQUIRED = 45;
- public static final int CME_CORPORATE_PERSONALIZATION_PIN_REQUIRED = 46;
- public static final int CME_CORPORATE_PERSONALIZATION_PUK_REQUIRED = 47;
- public static final int CME_HIDDEN_KEY_REQUIRED = 48;
- public static final int CME_EAP_NOT_SUPPORTED = 49;
- public static final int CME_INCORRECT_PARAMETERS = 50;
-
- /* Action policy for other calls when accepting call */
- public static final int CALL_ACCEPT_NONE = 0;
- public static final int CALL_ACCEPT_HOLD = 1;
- public static final int CALL_ACCEPT_TERMINATE = 2;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothHeadsetClient> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.HEADSET_CLIENT,
- "BluetoothHeadsetClient", IBluetoothHeadsetClient.class.getName()) {
- @Override
- public IBluetoothHeadsetClient getServiceInterface(IBinder service) {
- return IBluetoothHeadsetClient.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothHeadsetClient proxy object.
- */
- /* package */ BluetoothHeadsetClient(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- /**
- * Close the connection to the backing service.
- * Other public functions of BluetoothHeadsetClient will return default error
- * results once close() has been called. Multiple invocations of close()
- * are ok.
- */
- /*package*/ void close() {
- if (VDBG) log("close()");
- mProfileConnector.disconnect();
- }
-
- private IBluetoothHeadsetClient getService() {
- return mProfileConnector.getService();
- }
-
- /**
- * Connects to remote device.
- *
- * Currently, the system supports only 1 connection. So, in case of the
- * second connection, this implementation will disconnect already connected
- * device automatically and will process the new one.
- *
- * @param device a remote device we want connect to
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED} intent.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Disconnects remote device
- *
- * @param device a remote device we want disconnect
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_CONNECTION_STATE_CHANGED} intent.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Return the list of connected remote devices
- *
- * @return list of connected devices; empty list if nothing is connected.
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothHeadsetClient service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns list of remote devices in a particular state
- *
- * @param states collection of states
- * @return list of devices that state matches the states listed in <code>states</code>; empty
- * list if nothing matches the <code>states</code>
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothHeadsetClient service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns state of the <code>device</code>
- *
- * @param device a remote device
- * @return the state of connection of the device
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (VDBG) log("getConnectionState(" + device + ")");
- final IBluetoothHeadsetClient service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF}
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) log("setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothHeadsetClient service = getService();
- final @ConnectionPolicy int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Starts voice recognition.
- *
- * @param device remote device
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_AG_EVENT} intent.
- *
- * <p>Feature required for successful execution is being reported by: {@link
- * #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. This method invocation will fail silently when feature
- * is not supported.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean startVoiceRecognition(BluetoothDevice device) {
- if (DBG) log("startVoiceRecognition()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.startVoiceRecognition(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send vendor specific AT command.
- *
- * @param device remote device
- * @param vendorId vendor number by Bluetooth SIG
- * @param atCommand command to be sent. It start with + prefix and only one command at one time.
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean sendVendorAtCommand(BluetoothDevice device, int vendorId, String atCommand) {
- if (DBG) log("sendVendorSpecificCommand()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.sendVendorAtCommand(device, vendorId, atCommand, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Stops voice recognition.
- *
- * @param device remote device
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_AG_EVENT} intent.
- *
- * <p>Feature required for successful execution is being reported by: {@link
- * #EXTRA_AG_FEATURE_VOICE_RECOGNITION}. This method invocation will fail silently when feature
- * is not supported.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean stopVoiceRecognition(BluetoothDevice device) {
- if (DBG) log("stopVoiceRecognition()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.stopVoiceRecognition(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns list of all calls in any state.
- *
- * @param device remote device
- * @return list of calls; empty list if none call exists
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothHeadsetClientCall> getCurrentCalls(BluetoothDevice device) {
- if (DBG) log("getCurrentCalls()");
- final IBluetoothHeadsetClient service = getService();
- final List<BluetoothHeadsetClientCall> defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<List<BluetoothHeadsetClientCall>> recv =
- new SynchronousResultReceiver();
- service.getCurrentCalls(device, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns list of current values of AG indicators.
- *
- * @param device remote device
- * @return bundle of AG indicators; null if device is not in CONNECTED state
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public Bundle getCurrentAgEvents(BluetoothDevice device) {
- if (DBG) log("getCurrentAgEvents()");
- final IBluetoothHeadsetClient service = getService();
- final Bundle defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Bundle> recv = new SynchronousResultReceiver();
- service.getCurrentAgEvents(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Accepts a call
- *
- * @param device remote device
- * @param flag action policy while accepting a call. Possible values {@link #CALL_ACCEPT_NONE},
- * {@link #CALL_ACCEPT_HOLD}, {@link #CALL_ACCEPT_TERMINATE}
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean acceptCall(BluetoothDevice device, int flag) {
- if (DBG) log("acceptCall()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.acceptCall(device, flag, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Holds a call.
- *
- * @param device remote device
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean holdCall(BluetoothDevice device) {
- if (DBG) log("holdCall()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.holdCall(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Rejects a call.
- *
- * @param device remote device
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
- *
- * <p>Feature required for successful execution is being reported by: {@link
- * #EXTRA_AG_FEATURE_REJECT_CALL}. This method invocation will fail silently when feature is not
- * supported.</p>
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean rejectCall(BluetoothDevice device) {
- if (DBG) log("rejectCall()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.rejectCall(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Terminates a specified call.
- *
- * Works only when Extended Call Control is supported by Audio Gateway.
- *
- * @param device remote device
- * @param call Handle of call obtained in {@link #dial(BluetoothDevice, String)} or obtained via
- * {@link #ACTION_CALL_CHANGED}. {@code call} may be null in which case we will hangup all active
- * calls.
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
- *
- * <p>Feature required for successful execution is being reported by: {@link
- * #EXTRA_AG_FEATURE_ECC}. This method invocation will fail silently when feature is not
- * supported.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean terminateCall(BluetoothDevice device, BluetoothHeadsetClientCall call) {
- if (DBG) log("terminateCall()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.terminateCall(device, call, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Enters private mode with a specified call.
- *
- * Works only when Extended Call Control is supported by Audio Gateway.
- *
- * @param device remote device
- * @param index index of the call to connect in private mode
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
- *
- * <p>Feature required for successful execution is being reported by: {@link
- * #EXTRA_AG_FEATURE_ECC}. This method invocation will fail silently when feature is not
- * supported.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean enterPrivateMode(BluetoothDevice device, int index) {
- if (DBG) log("enterPrivateMode()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.enterPrivateMode(device, index, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Performs explicit call transfer.
- *
- * That means connect other calls and disconnect.
- *
- * @param device remote device
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_CALL_CHANGED} intent.
- *
- * <p>Feature required for successful execution is being reported by: {@link
- * #EXTRA_AG_FEATURE_MERGE_AND_DETACH}. This method invocation will fail silently when feature
- * is not supported.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean explicitCallTransfer(BluetoothDevice device) {
- if (DBG) log("explicitCallTransfer()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.explicitCallTransfer(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Places a call with specified number.
- *
- * @param device remote device
- * @param number valid phone number
- * @return <code>{@link BluetoothHeadsetClientCall} call</code> if command has been issued
- * successfully; <code>{@link null}</code> otherwise; upon completion HFP sends {@link
- * #ACTION_CALL_CHANGED} intent in case of success; {@link #ACTION_RESULT} is sent otherwise;
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothHeadsetClientCall dial(BluetoothDevice device, String number) {
- if (DBG) log("dial()");
- final IBluetoothHeadsetClient service = getService();
- final BluetoothHeadsetClientCall defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<BluetoothHeadsetClientCall> recv =
- new SynchronousResultReceiver();
- service.dial(device, number, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Sends DTMF code.
- *
- * Possible code values : 0,1,2,3,4,5,6,7,8,9,A,B,C,D,*,#
- *
- * @param device remote device
- * @param code ASCII code
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_RESULT} intent;
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean sendDTMF(BluetoothDevice device, byte code) {
- if (DBG) log("sendDTMF()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.sendDTMF(device, code, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get a number corresponding to last voice tag recorded on AG.
- *
- * @param device remote device
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_LAST_VTAG} or {@link #ACTION_RESULT}
- * intent;
- *
- * <p>Feature required for successful execution is being reported by: {@link
- * #EXTRA_AG_FEATURE_ATTACH_NUMBER_TO_VT}. This method invocation will fail silently when
- * feature is not supported.</p>
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean getLastVoiceTagNumber(BluetoothDevice device) {
- if (DBG) log("getLastVoiceTagNumber()");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.getLastVoiceTagNumber(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns current audio state of Audio Gateway.
- *
- * Note: This is an internal function and shouldn't be exposed
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getAudioState(BluetoothDevice device) {
- if (VDBG) log("getAudioState");
- final IBluetoothHeadsetClient service = getService();
- final int defaultValue = BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getAudioState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- } else {
- return defaultValue;
- }
- return BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED;
- }
-
- /**
- * Sets whether audio routing is allowed.
- *
- * @param device remote device
- * @param allowed if routing is allowed to the device Note: This is an internal function and
- * shouldn't be exposed
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setAudioRouteAllowed(BluetoothDevice device, boolean allowed) {
- if (VDBG) log("setAudioRouteAllowed");
- final IBluetoothHeadsetClient service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.setAudioRouteAllowed(device, allowed, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Returns whether audio routing is allowed.
- *
- * @param device remote device
- * @return whether the command succeeded Note: This is an internal function and shouldn't be
- * exposed
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean getAudioRouteAllowed(BluetoothDevice device) {
- if (VDBG) log("getAudioRouteAllowed");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.getAudioRouteAllowed(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiates a connection of audio channel.
- *
- * It setup SCO channel with remote connected Handsfree AG device.
- *
- * @param device remote device
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean connectAudio(BluetoothDevice device) {
- if (VDBG) log("connectAudio");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connectAudio(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Disconnects audio channel.
- *
- * It tears down the SCO channel from remote AG device.
- *
- * @param device remote device
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise; upon completion HFP sends {@link #ACTION_AUDIO_STATE_CHANGED} intent;
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnectAudio(BluetoothDevice device) {
- if (VDBG) log("disconnectAudio");
- final IBluetoothHeadsetClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnectAudio(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get Audio Gateway features
- *
- * @param device remote device
- * @return bundle of AG features; null if no service or AG not connected
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public Bundle getCurrentAgFeatures(BluetoothDevice device) {
- if (VDBG) log("getCurrentAgFeatures");
- final IBluetoothHeadsetClient service = getService();
- final Bundle defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Bundle> recv = new SynchronousResultReceiver();
- service.getCurrentAgFeatures(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private boolean isEnabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_ON;
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
deleted file mode 100644
index 032b507..0000000
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.NonNull;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-
-import java.util.UUID;
-
-/**
- * This class represents a single call, its state and properties.
- * It implements {@link Parcelable} for inter-process message passing.
- *
- * @hide
- */
-public final class BluetoothHeadsetClientCall implements Parcelable, Attributable {
-
- /* Call state */
- /**
- * Call is active.
- */
- public static final int CALL_STATE_ACTIVE = 0;
- /**
- * Call is in held state.
- */
- public static final int CALL_STATE_HELD = 1;
- /**
- * Outgoing call that is being dialed right now.
- */
- public static final int CALL_STATE_DIALING = 2;
- /**
- * Outgoing call that remote party has already been alerted about.
- */
- public static final int CALL_STATE_ALERTING = 3;
- /**
- * Incoming call that can be accepted or rejected.
- */
- public static final int CALL_STATE_INCOMING = 4;
- /**
- * Waiting call state when there is already an active call.
- */
- public static final int CALL_STATE_WAITING = 5;
- /**
- * Call that has been held by response and hold
- * (see Bluetooth specification for further references).
- */
- public static final int CALL_STATE_HELD_BY_RESPONSE_AND_HOLD = 6;
- /**
- * Call that has been already terminated and should not be referenced as a valid call.
- */
- public static final int CALL_STATE_TERMINATED = 7;
-
- private final BluetoothDevice mDevice;
- private final int mId;
- private int mState;
- private String mNumber;
- private boolean mMultiParty;
- private final boolean mOutgoing;
- private final UUID mUUID;
- private final long mCreationElapsedMilli;
- private final boolean mInBandRing;
-
- /**
- * Creates BluetoothHeadsetClientCall instance.
- */
- public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number,
- boolean multiParty, boolean outgoing, boolean inBandRing) {
- this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing, inBandRing);
- }
-
- public BluetoothHeadsetClientCall(BluetoothDevice device, int id, UUID uuid, int state,
- String number, boolean multiParty, boolean outgoing, boolean inBandRing) {
- mDevice = device;
- mId = id;
- mUUID = uuid;
- mState = state;
- mNumber = number != null ? number : "";
- mMultiParty = multiParty;
- mOutgoing = outgoing;
- mInBandRing = inBandRing;
- mCreationElapsedMilli = SystemClock.elapsedRealtime();
- }
-
- /** {@hide} */
- public void setAttributionSource(@NonNull AttributionSource attributionSource) {
- Attributable.setAttributionSource(mDevice, attributionSource);
- }
-
- /**
- * Sets call's state.
- *
- * <p>Note: This is an internal function and shouldn't be exposed</p>
- *
- * @param state new call state.
- */
- public void setState(int state) {
- mState = state;
- }
-
- /**
- * Sets call's number.
- *
- * <p>Note: This is an internal function and shouldn't be exposed</p>
- *
- * @param number String representing phone number.
- */
- public void setNumber(String number) {
- mNumber = number;
- }
-
- /**
- * Sets this call as multi party call.
- *
- * <p>Note: This is an internal function and shouldn't be exposed</p>
- *
- * @param multiParty if <code>true</code> sets this call as a part of multi party conference.
- */
- public void setMultiParty(boolean multiParty) {
- mMultiParty = multiParty;
- }
-
- /**
- * Gets call's device.
- *
- * @return call device.
- */
- public BluetoothDevice getDevice() {
- return mDevice;
- }
-
- /**
- * Gets call's Id.
- *
- * @return call id.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public int getId() {
- return mId;
- }
-
- /**
- * Gets call's UUID.
- *
- * @return call uuid
- * @hide
- */
- public UUID getUUID() {
- return mUUID;
- }
-
- /**
- * Gets call's current state.
- *
- * @return state of this particular phone call.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public int getState() {
- return mState;
- }
-
- /**
- * Gets call's number.
- *
- * @return string representing phone number.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public String getNumber() {
- return mNumber;
- }
-
- /**
- * Gets call's creation time in millis since epoch.
- *
- * @return long representing the creation time.
- */
- public long getCreationElapsedMilli() {
- return mCreationElapsedMilli;
- }
-
- /**
- * Checks if call is an active call in a conference mode (aka multi party).
- *
- * @return <code>true</code> if call is a multi party call, <code>false</code> otherwise.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public boolean isMultiParty() {
- return mMultiParty;
- }
-
- /**
- * Checks if this call is an outgoing call.
- *
- * @return <code>true</code> if its outgoing call, <code>false</code> otherwise.
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public boolean isOutgoing() {
- return mOutgoing;
- }
-
- /**
- * Checks if the ringtone will be generated by the connected phone
- *
- * @return <code>true</code> if in band ring is enabled, <code>false</code> otherwise.
- */
- public boolean isInBandRing() {
- return mInBandRing;
- }
-
-
- @Override
- public String toString() {
- return toString(false);
- }
-
- /**
- * Generate a log string for this call
- * @param loggable whether device address should be logged
- * @return log string
- */
- public String toString(boolean loggable) {
- StringBuilder builder = new StringBuilder("BluetoothHeadsetClientCall{mDevice: ");
- builder.append(loggable ? mDevice : mDevice.hashCode());
- builder.append(", mId: ");
- builder.append(mId);
- builder.append(", mUUID: ");
- builder.append(mUUID);
- builder.append(", mState: ");
- switch (mState) {
- case CALL_STATE_ACTIVE:
- builder.append("ACTIVE");
- break;
- case CALL_STATE_HELD:
- builder.append("HELD");
- break;
- case CALL_STATE_DIALING:
- builder.append("DIALING");
- break;
- case CALL_STATE_ALERTING:
- builder.append("ALERTING");
- break;
- case CALL_STATE_INCOMING:
- builder.append("INCOMING");
- break;
- case CALL_STATE_WAITING:
- builder.append("WAITING");
- break;
- case CALL_STATE_HELD_BY_RESPONSE_AND_HOLD:
- builder.append("HELD_BY_RESPONSE_AND_HOLD");
- break;
- case CALL_STATE_TERMINATED:
- builder.append("TERMINATED");
- break;
- default:
- builder.append(mState);
- break;
- }
- builder.append(", mNumber: ");
- builder.append(loggable ? mNumber : mNumber.hashCode());
- builder.append(", mMultiParty: ");
- builder.append(mMultiParty);
- builder.append(", mOutgoing: ");
- builder.append(mOutgoing);
- builder.append(", mInBandRing: ");
- builder.append(mInBandRing);
- builder.append("}");
- return builder.toString();
- }
-
- /**
- * {@link Parcelable.Creator} interface implementation.
- */
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothHeadsetClientCall> CREATOR =
- new Parcelable.Creator<BluetoothHeadsetClientCall>() {
- @Override
- public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
- return new BluetoothHeadsetClientCall((BluetoothDevice) in.readParcelable(null),
- in.readInt(), UUID.fromString(in.readString()), in.readInt(),
- in.readString(), in.readInt() == 1, in.readInt() == 1,
- in.readInt() == 1);
- }
-
- @Override
- public BluetoothHeadsetClientCall[] newArray(int size) {
- return new BluetoothHeadsetClientCall[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeParcelable(mDevice, 0);
- out.writeInt(mId);
- out.writeString(mUUID.toString());
- out.writeInt(mState);
- out.writeString(mNumber);
- out.writeInt(mMultiParty ? 1 : 0);
- out.writeInt(mOutgoing ? 1 : 0);
- out.writeInt(mInBandRing ? 1 : 0);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
deleted file mode 100644
index 65f68a9..0000000
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Public API for Bluetooth Health Profile.
- *
- * <p>BluetoothHealth is a proxy object for controlling the Bluetooth
- * Service via IPC.
- *
- * <p> How to connect to a health device which is acting in the source role.
- * <li> Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHealth proxy object. </li>
- * <li> Create an {@link BluetoothHealth} callback and call
- * {@link #registerSinkAppConfiguration} to register an application
- * configuration </li>
- * <li> Pair with the remote device. This currently needs to be done manually
- * from Bluetooth Settings </li>
- * <li> Connect to a health device using {@link #connectChannelToSource}. Some
- * devices will connect the channel automatically. The {@link BluetoothHealth}
- * callback will inform the application of channel state change. </li>
- * <li> Use the file descriptor provided with a connected channel to read and
- * write data to the health channel. </li>
- * <li> The received data needs to be interpreted using a health manager which
- * implements the IEEE 11073-xxxxx specifications.
- * <li> When done, close the health channel by calling {@link #disconnectChannel}
- * and unregister the application configuration calling
- * {@link #unregisterAppConfiguration}
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New apps
- * should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
-@Deprecated
-public final class BluetoothHealth implements BluetoothProfile {
- private static final String TAG = "BluetoothHealth";
- /**
- * Health Profile Source Role - the health device.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int SOURCE_ROLE = 1 << 0;
-
- /**
- * Health Profile Sink Role the device talking to the health device.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int SINK_ROLE = 1 << 1;
-
- /**
- * Health Profile - Channel Type used - Reliable
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int CHANNEL_TYPE_RELIABLE = 10;
-
- /**
- * Health Profile - Channel Type used - Streaming
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int CHANNEL_TYPE_STREAMING = 11;
-
- /**
- * Hide auto-created default constructor
- * @hide
- */
- BluetoothHealth() {}
-
- /**
- * Register an application configuration that acts as a Health SINK.
- * This is the configuration that will be used to communicate with health devices
- * which will act as the {@link #SOURCE_ROLE}. This is an asynchronous call and so
- * the callback is used to notify success or failure if the function returns true.
- *
- * @param name The friendly name associated with the application or configuration.
- * @param dataType The dataType of the Source role of Health Profile to which the sink wants to
- * connect to.
- * @param callback A callback to indicate success or failure of the registration and all
- * operations done on this application configuration.
- * @return If true, callback will be called.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public boolean registerSinkAppConfiguration(String name, int dataType,
- BluetoothHealthCallback callback) {
- Log.e(TAG, "registerSinkAppConfiguration(): BluetoothHealth is deprecated");
- return false;
- }
-
- /**
- * Unregister an application configuration that has been registered using
- * {@link #registerSinkAppConfiguration}
- *
- * @param config The health app configuration
- * @return Success or failure.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
- Log.e(TAG, "unregisterAppConfiguration(): BluetoothHealth is deprecated");
- return false;
- }
-
- /**
- * Connect to a health device which has the {@link #SOURCE_ROLE}.
- * This is an asynchronous call. If this function returns true, the callback
- * associated with the application configuration will be called.
- *
- * @param device The remote Bluetooth device.
- * @param config The application configuration which has been registered using {@link
- * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
- * @return If true, the callback associated with the application config will be called.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public boolean connectChannelToSource(BluetoothDevice device,
- BluetoothHealthAppConfiguration config) {
- Log.e(TAG, "connectChannelToSource(): BluetoothHealth is deprecated");
- return false;
- }
-
- /**
- * Disconnect a connected health channel.
- * This is an asynchronous call. If this function returns true, the callback
- * associated with the application configuration will be called.
- *
- * @param device The remote Bluetooth device.
- * @param config The application configuration which has been registered using {@link
- * #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
- * @param channelId The channel id associated with the channel
- * @return If true, the callback associated with the application config will be called.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public boolean disconnectChannel(BluetoothDevice device,
- BluetoothHealthAppConfiguration config, int channelId) {
- Log.e(TAG, "disconnectChannel(): BluetoothHealth is deprecated");
- return false;
- }
-
- /**
- * Get the file descriptor of the main channel associated with the remote device
- * and application configuration.
- *
- * <p> Its the responsibility of the caller to close the ParcelFileDescriptor
- * when done.
- *
- * @param device The remote Bluetooth health device
- * @param config The application configuration
- * @return null on failure, ParcelFileDescriptor on success.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
- BluetoothHealthAppConfiguration config) {
- Log.e(TAG, "getMainChannelFd(): BluetoothHealth is deprecated");
- return null;
- }
-
- /**
- * Get the current connection state of the profile.
- *
- * This is not specific to any application configuration but represents the connection
- * state of the local Bluetooth adapter with the remote device. This can be used
- * by applications like status bar which would just like to know the state of the
- * local adapter.
- *
- * @param device Remote bluetooth device.
- * @return State of the profile connection. One of {@link #STATE_CONNECTED}, {@link
- * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
- */
- @Override
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public int getConnectionState(BluetoothDevice device) {
- Log.e(TAG, "getConnectionState(): BluetoothHealth is deprecated");
- return STATE_DISCONNECTED;
- }
-
- /**
- * Get connected devices for the health profile.
- *
- * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
- *
- * This is not specific to any application configuration but represents the connection
- * state of the local Bluetooth adapter for this profile. This can be used
- * by applications like status bar which would just like to know the state of the
- * local adapter.
- *
- * @return List of devices. The list will be empty on error.
- */
- @Override
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public List<BluetoothDevice> getConnectedDevices() {
- Log.e(TAG, "getConnectedDevices(): BluetoothHealth is deprecated");
- return new ArrayList<>();
- }
-
- /**
- * Get a list of devices that match any of the given connection
- * states.
- *
- * <p> If none of the devices match any of the given states,
- * an empty list will be returned.
- *
- * <p>This is not specific to any application configuration but represents the connection
- * state of the local Bluetooth adapter for this profile. This can be used
- * by applications like status bar which would just like to know the state of the
- * local adapter.
- *
- * @param states Array of states. States can be one of {@link #STATE_CONNECTED}, {@link
- * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
- * @return List of devices. The list will be empty on error.
- */
- @Override
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- Log.e(TAG, "getDevicesMatchingConnectionStates(): BluetoothHealth is deprecated");
- return new ArrayList<>();
- }
-
- /** Health Channel Connection State - Disconnected
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int STATE_CHANNEL_DISCONNECTED = 0;
- /** Health Channel Connection State - Connecting
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int STATE_CHANNEL_CONNECTING = 1;
- /** Health Channel Connection State - Connected
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int STATE_CHANNEL_CONNECTED = 2;
- /** Health Channel Connection State - Disconnecting
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int STATE_CHANNEL_DISCONNECTING = 3;
-
- /** Health App Configuration registration success
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int APP_CONFIG_REGISTRATION_SUCCESS = 0;
- /** Health App Configuration registration failure
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int APP_CONFIG_REGISTRATION_FAILURE = 1;
- /** Health App Configuration un-registration success
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int APP_CONFIG_UNREGISTRATION_SUCCESS = 2;
- /** Health App Configuration un-registration failure
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final int APP_CONFIG_UNREGISTRATION_FAILURE = 3;
-}
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
deleted file mode 100644
index 2f66df2..0000000
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * The Bluetooth Health Application Configuration that is used in conjunction with
- * the {@link BluetoothHealth} class. This class represents an application configuration
- * that the Bluetooth Health third party application will register to communicate with the
- * remote Bluetooth health device.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
-@Deprecated
-public final class BluetoothHealthAppConfiguration implements Parcelable {
-
- /**
- * Hide auto-created default constructor
- * @hide
- */
- BluetoothHealthAppConfiguration() {}
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Return the data type associated with this application configuration.
- *
- * @return dataType
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public int getDataType() {
- return 0;
- }
-
- /**
- * Return the name of the application configuration.
- *
- * @return String name
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public String getName() {
- return null;
- }
-
- /**
- * Return the role associated with this application configuration.
- *
- * @return One of {@link BluetoothHealth#SOURCE_ROLE} or {@link BluetoothHealth#SINK_ROLE}
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public int getRole() {
- return 0;
- }
-
- /**
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
- new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
- @Override
- public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
- return new BluetoothHealthAppConfiguration();
- }
-
- @Override
- public BluetoothHealthAppConfiguration[] newArray(int size) {
- return new BluetoothHealthAppConfiguration[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {}
-}
diff --git a/core/java/android/bluetooth/BluetoothHealthCallback.java b/core/java/android/bluetooth/BluetoothHealthCallback.java
deleted file mode 100644
index 4769212..0000000
--- a/core/java/android/bluetooth/BluetoothHealthCallback.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.bluetooth;
-
-import android.annotation.BinderThread;
-import android.os.ParcelFileDescriptor;
-import android.util.Log;
-
-/**
- * This abstract class is used to implement {@link BluetoothHealth} callbacks.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
-@Deprecated
-public abstract class BluetoothHealthCallback {
- private static final String TAG = "BluetoothHealthCallback";
-
- /**
- * Callback to inform change in registration state of the health
- * application.
- * <p> This callback is called on the binder thread (not on the UI thread)
- *
- * @param config Bluetooth Health app configuration
- * @param status Success or failure of the registration or unregistration calls. Can be one of
- * {@link BluetoothHealth#APP_CONFIG_REGISTRATION_SUCCESS} or {@link
- * BluetoothHealth#APP_CONFIG_REGISTRATION_FAILURE} or
- * {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_SUCCESS}
- * or {@link BluetoothHealth#APP_CONFIG_UNREGISTRATION_FAILURE}
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @BinderThread
- @Deprecated
- public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
- int status) {
- Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + "Status: " + status);
- }
-
- /**
- * Callback to inform change in channel state.
- * <p> Its the responsibility of the implementor of this callback to close the
- * parcel file descriptor when done. This callback is called on the Binder
- * thread (not the UI thread)
- *
- * @param config The Health app configutation
- * @param device The Bluetooth Device
- * @param prevState The previous state of the channel
- * @param newState The new state of the channel.
- * @param fd The Parcel File Descriptor when the channel state is connected.
- * @param channelId The id associated with the channel. This id will be used in future calls
- * like when disconnecting the channel.
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()(int)}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @BinderThread
- @Deprecated
- public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
- BluetoothDevice device, int prevState, int newState, ParcelFileDescriptor fd,
- int channelId) {
- Log.d(TAG, "onHealthChannelStateChange: " + config + "Device: " + device
- + "prevState:" + prevState + "newState:" + newState + "ParcelFd:" + fd
- + "ChannelId:" + channelId);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
deleted file mode 100644
index 339a75f..0000000
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ /dev/null
@@ -1,691 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the public APIs to control the Hearing Aid profile.
- *
- * <p>BluetoothHearingAid is a proxy object for controlling the Bluetooth Hearing Aid
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHearingAid proxy object.
- *
- * <p> Android only supports one set of connected Bluetooth Hearing Aid device at a time. Each
- * method is protected with its appropriate permission.
- */
-public final class BluetoothHearingAid implements BluetoothProfile {
- private static final String TAG = "BluetoothHearingAid";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the Hearing Aid
- * profile. Please note that in the binaural case, there will be two different LE devices for
- * the left and right side and each device will have their own connection state changes.S
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.hearingaid.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * Intent used to broadcast the selection of a connected device as active.
- *
- * <p>This intent will have one extra:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
- * be null if no device is active. </li>
- * </ul>
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_ACTIVE_DEVICE_CHANGED =
- "android.bluetooth.hearingaid.profile.action.ACTIVE_DEVICE_CHANGED";
-
- /**
- * This device represents Left Hearing Aid.
- *
- * @hide
- */
- public static final int SIDE_LEFT = IBluetoothHearingAid.SIDE_LEFT;
-
- /**
- * This device represents Right Hearing Aid.
- *
- * @hide
- */
- public static final int SIDE_RIGHT = IBluetoothHearingAid.SIDE_RIGHT;
-
- /**
- * This device is Monaural.
- *
- * @hide
- */
- public static final int MODE_MONAURAL = IBluetoothHearingAid.MODE_MONAURAL;
-
- /**
- * This device is Binaural (should receive only left or right audio).
- *
- * @hide
- */
- public static final int MODE_BINAURAL = IBluetoothHearingAid.MODE_BINAURAL;
-
- /**
- * Indicates the HiSyncID could not be read and is unavailable.
- *
- * @hide
- */
- public static final long HI_SYNC_ID_INVALID = IBluetoothHearingAid.HI_SYNC_ID_INVALID;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothHearingAid> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.HEARING_AID,
- "BluetoothHearingAid", IBluetoothHearingAid.class.getName()) {
- @Override
- public IBluetoothHearingAid getServiceInterface(IBinder service) {
- return IBluetoothHearingAid.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothHearingAid proxy object for interacting with the local
- * Bluetooth Hearing Aid service.
- */
- /* package */ BluetoothHearingAid(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- /*package*/ void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothHearingAid getService() {
- return mProfileConnector.getService();
- }
-
- /**
- * Initiate connection to a profile of the remote bluetooth device.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is already connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that
- * connection state intent for the profile will be broadcasted with
- * the state. Users can get the connection state of the profile
- * from this intent.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- final IBluetoothHearingAid service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnection from a profile
- *
- * <p> This API will return false in scenarios like the profile on the
- * Bluetooth device is not in connected state etc. When this API returns,
- * true, it is guaranteed that the connection state change
- * intent will be broadcasted with the state. Users can get the
- * disconnection state of the profile from this intent.
- *
- * <p> If the disconnection is initiated by a remote device, the state
- * will transition from {@link #STATE_CONNECTED} to
- * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
- * host (local) device the state will transition from
- * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
- * state {@link #STATE_DISCONNECTED}. The transition to
- * {@link #STATE_DISCONNECTING} can be used to distinguish between the
- * two scenarios.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothHearingAid service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothHearingAid service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
- @NonNull int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothHearingAid service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @BluetoothProfile.BtProfileState int getConnectionState(
- @NonNull BluetoothDevice device) {
- if (VDBG) log("getState(" + device + ")");
- final IBluetoothHearingAid service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Select a connected device as active.
- *
- * The active device selection is per profile. An active device's
- * purpose is profile-specific. For example, Hearing Aid audio
- * streaming is to the active Hearing Aid device. If a remote device
- * is not connected, it cannot be selected as active.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is not connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that the
- * {@link #ACTION_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
- * with the active device.
- *
- * @param device the remote Bluetooth device. Could be null to clear
- * the active device and stop streaming audio to a Bluetooth device.
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public boolean setActiveDevice(@Nullable BluetoothDevice device) {
- if (DBG) log("setActiveDevice(" + device + ")");
- final IBluetoothHearingAid service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && ((device == null) || isValidDevice(device))) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setActiveDevice(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the connected physical Hearing Aid devices that are active
- *
- * @return the list of active devices. The first element is the left active
- * device; the second element is the right active device. If either or both side
- * is not active, it will be null on that position. Returns empty list on error.
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull List<BluetoothDevice> getActiveDevices() {
- if (VDBG) log("getActiveDevices()");
- final IBluetoothHearingAid service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getActiveDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) log("setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- verifyDeviceNotNull(device, "setConnectionPolicy");
- final IBluetoothHearingAid service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- verifyDeviceNotNull(device, "getConnectionPolicy");
- final IBluetoothHearingAid service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Helper for converting a state to a string.
- *
- * For debug use only - strings are not internationalized.
- *
- * @hide
- */
- public static String stateToString(int state) {
- switch (state) {
- case STATE_DISCONNECTED:
- return "disconnected";
- case STATE_CONNECTING:
- return "connecting";
- case STATE_CONNECTED:
- return "connected";
- case STATE_DISCONNECTING:
- return "disconnecting";
- default:
- return "<unknown state " + state + ">";
- }
- }
-
- /**
- * Tells remote device to set an absolute volume.
- *
- * @param volume Absolute volume to be set on remote
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void setVolume(int volume) {
- if (DBG) Log.d(TAG, "setVolume(" + volume + ")");
- final IBluetoothHearingAid service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.setVolume(volume, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Get the HiSyncId (unique hearing aid device identifier) of the device.
- *
- * <a href=https://source.android.com/devices/bluetooth/asha#hisyncid>HiSyncId documentation
- * can be found here</a>
- *
- * @param device Bluetooth device
- * @return the HiSyncId of the device
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public long getHiSyncId(@NonNull BluetoothDevice device) {
- if (VDBG) log("getHiSyncId(" + device + ")");
- verifyDeviceNotNull(device, "getConnectionPolicy");
- final IBluetoothHearingAid service = getService();
- final long defaultValue = HI_SYNC_ID_INVALID;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Long> recv = new SynchronousResultReceiver();
- service.getHiSyncId(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the side of the device.
- *
- * @param device Bluetooth device.
- * @return SIDE_LEFT or SIDE_RIGHT
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getDeviceSide(BluetoothDevice device) {
- if (VDBG) log("getDeviceSide(" + device + ")");
- final IBluetoothHearingAid service = getService();
- final int defaultValue = SIDE_LEFT;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getDeviceSide(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the mode of the device.
- *
- * @param device Bluetooth device
- * @return MODE_MONAURAL or MODE_BINAURAL
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getDeviceMode(BluetoothDevice device) {
- if (VDBG) log("getDeviceMode(" + device + ")");
- final IBluetoothHearingAid service = getService();
- final int defaultValue = MODE_MONAURAL;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getDeviceMode(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private boolean isEnabled() {
- if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
- return false;
- }
-
- private void verifyDeviceNotNull(BluetoothDevice device, String methodName) {
- if (device == null) {
- Log.e(TAG, methodName + ": device param is null");
- throw new IllegalArgumentException("Device cannot be null");
- }
- }
-
- private boolean isValidDevice(BluetoothDevice device) {
- if (device == null) return false;
-
- if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
- return false;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
deleted file mode 100644
index 44a355b..0000000
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ /dev/null
@@ -1,848 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Provides the public APIs to control the Bluetooth HID Device profile.
- *
- * <p>BluetoothHidDevice is a proxy object for controlling the Bluetooth HID Device Service via IPC.
- * Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object.
- */
-public final class BluetoothHidDevice implements BluetoothProfile {
- private static final String TAG = BluetoothHidDevice.class.getSimpleName();
- private static final boolean DBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the Input Host profile.
- *
- * <p>This intent will have 3 extras:
- *
- * <ul>
- * <li>{@link #EXTRA_STATE} - The current state of the profile.
- * <li>{@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
- * <li>{@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link
- * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link
- * #STATE_DISCONNECTING}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * Constant representing unspecified HID device subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS1_NONE = (byte) 0x00;
- /**
- * Constant representing keyboard subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
- /**
- * Constant representing mouse subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS1_MOUSE = (byte) 0x80;
- /**
- * Constant representing combo keyboard and mouse subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS1_COMBO = (byte) 0xC0;
-
- /**
- * Constant representing uncategorized HID device subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00;
- /**
- * Constant representing joystick subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01;
- /**
- * Constant representing gamepad subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02;
- /**
- * Constant representing remote control subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03;
- /**
- * Constant representing sensing device subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04;
- /**
- * Constant representing digitizer tablet subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05;
- /**
- * Constant representing card reader subclass.
- *
- * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)
- */
- public static final byte SUBCLASS2_CARD_READER = (byte) 0x06;
-
- /**
- * Constant representing HID Input Report type.
- *
- * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
- */
- public static final byte REPORT_TYPE_INPUT = (byte) 1;
- /**
- * Constant representing HID Output Report type.
- *
- * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
- */
- public static final byte REPORT_TYPE_OUTPUT = (byte) 2;
- /**
- * Constant representing HID Feature Report type.
- *
- * @see Callback#onGetReport(BluetoothDevice, byte, byte, int)
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- * @see Callback#onInterruptData(BluetoothDevice, byte, byte[])
- */
- public static final byte REPORT_TYPE_FEATURE = (byte) 3;
-
- /**
- * Constant representing success response for Set Report.
- *
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- */
- public static final byte ERROR_RSP_SUCCESS = (byte) 0;
- /**
- * Constant representing error response for Set Report due to "not ready".
- *
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- */
- public static final byte ERROR_RSP_NOT_READY = (byte) 1;
- /**
- * Constant representing error response for Set Report due to "invalid report ID".
- *
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- */
- public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2;
- /**
- * Constant representing error response for Set Report due to "unsupported request".
- *
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- */
- public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3;
- /**
- * Constant representing error response for Set Report due to "invalid parameter".
- *
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- */
- public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4;
- /**
- * Constant representing error response for Set Report with unknown reason.
- *
- * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[])
- */
- public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
-
- /**
- * Constant representing boot protocol mode used set by host. Default is always {@link
- * #PROTOCOL_REPORT_MODE} unless notified otherwise.
- *
- * @see Callback#onSetProtocol(BluetoothDevice, byte)
- */
- public static final byte PROTOCOL_BOOT_MODE = (byte) 0;
- /**
- * Constant representing report protocol mode used set by host. Default is always {@link
- * #PROTOCOL_REPORT_MODE} unless notified otherwise.
- *
- * @see Callback#onSetProtocol(BluetoothDevice, byte)
- */
- public static final byte PROTOCOL_REPORT_MODE = (byte) 1;
-
- /**
- * The template class that applications use to call callback functions on events from the HID
- * host. Callback functions are wrapped in this class and registered to the Android system
- * during app registration.
- */
- public abstract static class Callback {
-
- private static final String TAG = "BluetoothHidDevCallback";
-
- /**
- * Callback called when application registration state changes. Usually it's called due to
- * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[],
- * Executor, Callback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also
- * unsolicited in case e.g. Bluetooth was turned off in which case application is
- * unregistered automatically.
- *
- * @param pluggedDevice {@link BluetoothDevice} object which represents host that currently
- * has Virtual Cable established with device. Only valid when application is registered,
- * can be <code>null</code>.
- * @param registered <code>true</code> if application is registered, <code>false</code>
- * otherwise.
- */
- public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
- Log.d(
- TAG,
- "onAppStatusChanged: pluggedDevice="
- + pluggedDevice
- + " registered="
- + registered);
- }
-
- /**
- * Callback called when connection state with remote host was changed. Application can
- * assume than Virtual Cable is established when called with {@link
- * BluetoothProfile#STATE_CONNECTED} <code>state</code>.
- *
- * @param device {@link BluetoothDevice} object representing host device which connection
- * state was changed.
- * @param state Connection state as defined in {@link BluetoothProfile}.
- */
- public void onConnectionStateChanged(BluetoothDevice device, int state) {
- Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state);
- }
-
- /**
- * Callback called when GET_REPORT is received from remote host. Should be replied by
- * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte,
- * byte[])}.
- *
- * @param type Requested Report Type.
- * @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor.
- * @param bufferSize Requested buffer size, application shall respond with at least given
- * number of bytes.
- */
- public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
- Log.d(
- TAG,
- "onGetReport: device="
- + device
- + " type="
- + type
- + " id="
- + id
- + " bufferSize="
- + bufferSize);
- }
-
- /**
- * Callback called when SET_REPORT is received from remote host. In case received data are
- * invalid, application shall respond with {@link
- * BluetoothHidDevice#reportError(BluetoothDevice, byte)}.
- *
- * @param type Report Type.
- * @param id Report Id.
- * @param data Report data.
- */
- public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
- Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id);
- }
-
- /**
- * Callback called when SET_PROTOCOL is received from remote host. Application shall use
- * this information to send only reports valid for given protocol mode. By default, {@link
- * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed.
- *
- * @param protocol Protocol Mode.
- */
- public void onSetProtocol(BluetoothDevice device, byte protocol) {
- Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol);
- }
-
- /**
- * Callback called when report data is received over interrupt channel. Report Type is
- * assumed to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
- *
- * @param reportId Report Id.
- * @param data Report data.
- */
- public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
- Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId);
- }
-
- /**
- * Callback called when Virtual Cable is removed. After this callback is received connection
- * will be disconnected automatically.
- */
- public void onVirtualCableUnplug(BluetoothDevice device) {
- Log.d(TAG, "onVirtualCableUnplug: device=" + device);
- }
- }
-
- private static class CallbackWrapper extends IBluetoothHidDeviceCallback.Stub {
-
- private final Executor mExecutor;
- private final Callback mCallback;
- private final AttributionSource mAttributionSource;
-
- CallbackWrapper(Executor executor, Callback callback, AttributionSource attributionSource) {
- mExecutor = executor;
- mCallback = callback;
- mAttributionSource = attributionSource;
- }
-
- @Override
- public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
- Attributable.setAttributionSource(pluggedDevice, mAttributionSource);
- final long token = clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered));
- } finally {
- restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onConnectionStateChanged(BluetoothDevice device, int state) {
- Attributable.setAttributionSource(device, mAttributionSource);
- final long token = clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state));
- } finally {
- restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
- Attributable.setAttributionSource(device, mAttributionSource);
- final long token = clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize));
- } finally {
- restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
- Attributable.setAttributionSource(device, mAttributionSource);
- final long token = clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data));
- } finally {
- restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onSetProtocol(BluetoothDevice device, byte protocol) {
- Attributable.setAttributionSource(device, mAttributionSource);
- final long token = clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol));
- } finally {
- restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
- Attributable.setAttributionSource(device, mAttributionSource);
- final long token = clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data));
- } finally {
- restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onVirtualCableUnplug(BluetoothDevice device) {
- Attributable.setAttributionSource(device, mAttributionSource);
- final long token = clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device));
- } finally {
- restoreCallingIdentity(token);
- }
- }
- }
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothHidDevice> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.HID_DEVICE,
- "BluetoothHidDevice", IBluetoothHidDevice.class.getName()) {
- @Override
- public IBluetoothHidDevice getServiceInterface(IBinder service) {
- return IBluetoothHidDevice.Stub.asInterface(service);
- }
- };
-
- BluetoothHidDevice(Context context, ServiceListener listener, BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothHidDevice getService() {
- return mProfileConnector.getService();
- }
-
- /** {@inheritDoc} */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- final IBluetoothHidDevice service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /** {@inheritDoc} */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- final IBluetoothHidDevice service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /** {@inheritDoc} */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- final IBluetoothHidDevice service = getService();
- final int defaultValue = STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Registers application to be used for HID device. Connections to HID Device are only possible
- * when application is registered. Only one application can be registered at one time. When an
- * application is registered, the HID Host service will be disabled until it is unregistered.
- * When no longer used, application should be unregistered using {@link #unregisterApp()}. The
- * app will be automatically unregistered if it is not foreground. The registration status
- * should be tracked by the application by handling callback from Callback#onAppStatusChanged.
- * The app registration status is not related to the return value of this method.
- *
- * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID
- * Device SDP record is required.
- * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings. The
- * Incoming QoS Settings is not required. Use null or default
- * BluetoothHidDeviceAppQosSettings.Builder for default values.
- * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings. The
- * Outgoing QoS Settings is not required. Use null or default
- * BluetoothHidDeviceAppQosSettings.Builder for default values.
- * @param executor {@link Executor} object on which callback will be executed. The Executor
- * object is required.
- * @param callback {@link Callback} object to which callback messages will be sent. The Callback
- * object is required.
- * @return true if the command is successfully sent; otherwise false.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean registerApp(
- BluetoothHidDeviceAppSdpSettings sdp,
- BluetoothHidDeviceAppQosSettings inQos,
- BluetoothHidDeviceAppQosSettings outQos,
- Executor executor,
- Callback callback) {
- boolean result = false;
-
- if (sdp == null) {
- throw new IllegalArgumentException("sdp parameter cannot be null");
- }
-
- if (executor == null) {
- throw new IllegalArgumentException("executor parameter cannot be null");
- }
-
- if (callback == null) {
- throw new IllegalArgumentException("callback parameter cannot be null");
- }
-
- final IBluetoothHidDevice service = getService();
- final boolean defaultValue = result;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- CallbackWrapper cbw = new CallbackWrapper(executor, callback, mAttributionSource);
- service.registerApp(sdp, inQos, outQos, cbw, mAttributionSource, recv);
- result = recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Unregisters application. Active connection will be disconnected and no new connections will
- * be allowed until registered again using {@link #registerApp
- * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, Executor, Callback)}. The registration status should be
- * tracked by the application by handling callback from Callback#onAppStatusChanged. The app
- * registration status is not related to the return value of this method.
- *
- * @return true if the command is successfully sent; otherwise false.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean unregisterApp() {
- final IBluetoothHidDevice service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.unregisterApp(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Sends report to remote host using interrupt channel.
- *
- * @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
- * descriptor.
- * @param data Report data, not including Report Id.
- * @return true if the command is successfully sent; otherwise false.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean sendReport(BluetoothDevice device, int id, byte[] data) {
- final IBluetoothHidDevice service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.sendReport(device, id, data, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Sends report to remote host as reply for GET_REPORT request from {@link
- * Callback#onGetReport(BluetoothDevice, byte, byte, int)}.
- *
- * @param type Report Type, as in request.
- * @param id Report Id, as in request.
- * @param data Report data, not including Report Id.
- * @return true if the command is successfully sent; otherwise false.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) {
- final IBluetoothHidDevice service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.replyReport(device, type, id, data, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Sends error handshake message as reply for invalid SET_REPORT request from {@link
- * Callback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
- *
- * @param error Error to be sent for SET_REPORT via HANDSHAKE.
- * @return true if the command is successfully sent; otherwise false.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean reportError(BluetoothDevice device, byte error) {
- final IBluetoothHidDevice service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.reportError(device, error, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Gets the application name of the current HidDeviceService user.
- *
- * @return the current user name, or empty string if cannot get the name
- * {@hide}
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public String getUserAppName() {
- final IBluetoothHidDevice service = getService();
- final String defaultValue = "";
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<String> recv = new SynchronousResultReceiver();
- service.getUserAppName(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiates connection to host which is currently paired with this device. If the application
- * is not registered, #connect(BluetoothDevice) will fail. The connection state should be
- * tracked by the application by handling callback from Callback#onConnectionStateChanged. The
- * connection state is not related to the return value of this method.
- *
- * @return true if the command is successfully sent; otherwise false.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean connect(BluetoothDevice device) {
- final IBluetoothHidDevice service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Disconnects from currently connected host. The connection state should be tracked by the
- * application by handling callback from Callback#onConnectionStateChanged. The connection state
- * is not related to the return value of this method.
- *
- * @return true if the command is successfully sent; otherwise false.
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(BluetoothDevice device) {
- final IBluetoothHidDevice service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Connects Hid Device if connectionPolicy is {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED}
- * and disconnects Hid device if connectionPolicy is
- * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}.
- *
- * <p> The device should already be paired.
- * Connection policy can be one of:
- * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED},
- * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN},
- * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy determines whether hid device should be connected or disconnected
- * @return true if hid device is connected or disconnected, false otherwise
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothHidDevice service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private boolean isEnabled() {
- if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
- return false;
- }
-
- private boolean isValidDevice(BluetoothDevice device) {
- if (device == null) return false;
-
- if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
- return false;
- }
-
- private static void log(String msg) {
- if (DBG) {
- Log.d(TAG, msg);
- }
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
deleted file mode 100644
index b21ebe5..0000000
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents the Quality of Service (QoS) settings for a Bluetooth HID Device application.
- *
- * <p>The BluetoothHidDevice framework will update the L2CAP QoS settings for the app during
- * registration.
- *
- * <p>{@see BluetoothHidDevice}
- */
-public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
-
- private final int mServiceType;
- private final int mTokenRate;
- private final int mTokenBucketSize;
- private final int mPeakBandwidth;
- private final int mLatency;
- private final int mDelayVariation;
-
- public static final int SERVICE_NO_TRAFFIC = 0x00;
- public static final int SERVICE_BEST_EFFORT = 0x01;
- public static final int SERVICE_GUARANTEED = 0x02;
-
- public static final int MAX = (int) 0xffffffff;
-
- /**
- * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS
- * Settings is optional. Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and
- * Appendix D for parameters.
- *
- * @param serviceType L2CAP service type, default = SERVICE_BEST_EFFORT
- * @param tokenRate L2CAP token rate, default = 0
- * @param tokenBucketSize L2CAP token bucket size, default = 0
- * @param peakBandwidth L2CAP peak bandwidth, default = 0
- * @param latency L2CAP latency, default = MAX
- * @param delayVariation L2CAP delay variation, default = MAX
- */
- public BluetoothHidDeviceAppQosSettings(
- int serviceType,
- int tokenRate,
- int tokenBucketSize,
- int peakBandwidth,
- int latency,
- int delayVariation) {
- mServiceType = serviceType;
- mTokenRate = tokenRate;
- mTokenBucketSize = tokenBucketSize;
- mPeakBandwidth = peakBandwidth;
- mLatency = latency;
- mDelayVariation = delayVariation;
- }
-
- public int getServiceType() {
- return mServiceType;
- }
-
- public int getTokenRate() {
- return mTokenRate;
- }
-
- public int getTokenBucketSize() {
- return mTokenBucketSize;
- }
-
- public int getPeakBandwidth() {
- return mPeakBandwidth;
- }
-
- public int getLatency() {
- return mLatency;
- }
-
- public int getDelayVariation() {
- return mDelayVariation;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothHidDeviceAppQosSettings> CREATOR =
- new Parcelable.Creator<BluetoothHidDeviceAppQosSettings>() {
-
- @Override
- public BluetoothHidDeviceAppQosSettings createFromParcel(Parcel in) {
-
- return new BluetoothHidDeviceAppQosSettings(
- in.readInt(),
- in.readInt(),
- in.readInt(),
- in.readInt(),
- in.readInt(),
- in.readInt());
- }
-
- @Override
- public BluetoothHidDeviceAppQosSettings[] newArray(int size) {
- return new BluetoothHidDeviceAppQosSettings[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mServiceType);
- out.writeInt(mTokenRate);
- out.writeInt(mTokenBucketSize);
- out.writeInt(mPeakBandwidth);
- out.writeInt(mLatency);
- out.writeInt(mDelayVariation);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
deleted file mode 100644
index 4e1a2aa..0000000
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.EventLog;
-
-
-/**
- * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth HID Device application.
- *
- * <p>The BluetoothHidDevice framework adds the SDP record during app registration, so that the
- * Android device can be discovered as a Bluetooth HID Device.
- *
- * <p>{@see BluetoothHidDevice}
- */
-public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
-
- private static final int MAX_DESCRIPTOR_SIZE = 2048;
-
- private final String mName;
- private final String mDescription;
- private final String mProvider;
- private final byte mSubclass;
- private final byte[] mDescriptors;
-
- /**
- * Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
- *
- * @param name Name of this Bluetooth HID device. Maximum length is 50 bytes.
- * @param description Description for this Bluetooth HID device. Maximum length is 50 bytes.
- * @param provider Provider of this Bluetooth HID device. Maximum length is 50 bytes.
- * @param subclass Subclass of this Bluetooth HID device. See <a
- * href="www.usb.org/developers/hidpage/HID1_11.pdf">
- * www.usb.org/developers/hidpage/HID1_11.pdf Section 4.2</a>
- * @param descriptors Descriptors of this Bluetooth HID device. See <a
- * href="www.usb.org/developers/hidpage/HID1_11.pdf">
- * www.usb.org/developers/hidpage/HID1_11.pdf Chapter 6</a> Maximum length is 2048 bytes.
- */
- public BluetoothHidDeviceAppSdpSettings(
- String name, String description, String provider, byte subclass, byte[] descriptors) {
- mName = name;
- mDescription = description;
- mProvider = provider;
- mSubclass = subclass;
-
- if (descriptors == null || descriptors.length > MAX_DESCRIPTOR_SIZE) {
- EventLog.writeEvent(0x534e4554, "119819889", -1, "");
- throw new IllegalArgumentException("descriptors must be not null and shorter than "
- + MAX_DESCRIPTOR_SIZE);
- }
- mDescriptors = descriptors.clone();
- }
-
- public String getName() {
- return mName;
- }
-
- public String getDescription() {
- return mDescription;
- }
-
- public String getProvider() {
- return mProvider;
- }
-
- public byte getSubclass() {
- return mSubclass;
- }
-
- public byte[] getDescriptors() {
- return mDescriptors;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothHidDeviceAppSdpSettings> CREATOR =
- new Parcelable.Creator<BluetoothHidDeviceAppSdpSettings>() {
-
- @Override
- public BluetoothHidDeviceAppSdpSettings createFromParcel(Parcel in) {
-
- return new BluetoothHidDeviceAppSdpSettings(
- in.readString(),
- in.readString(),
- in.readString(),
- in.readByte(),
- in.createByteArray());
- }
-
- @Override
- public BluetoothHidDeviceAppSdpSettings[] newArray(int size) {
- return new BluetoothHidDeviceAppSdpSettings[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(mName);
- out.writeString(mDescription);
- out.writeString(mProvider);
- out.writeByte(mSubclass);
- out.writeByteArray(mDescriptors);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHidHost.java b/core/java/android/bluetooth/BluetoothHidHost.java
deleted file mode 100644
index ecbeddf..0000000
--- a/core/java/android/bluetooth/BluetoothHidHost.java
+++ /dev/null
@@ -1,831 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-
-/**
- * This class provides the public APIs to control the Bluetooth Input
- * Device Profile.
- *
- * <p>BluetoothHidHost is a proxy object for controlling the Bluetooth
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHidHost proxy object.
- *
- * <p>Each method is protected with its appropriate permission.
- *
- * @hide
- */
-@SystemApi
-public final class BluetoothHidHost implements BluetoothProfile {
- private static final String TAG = "BluetoothHidHost";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the Input
- * Device profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- */
- @SuppressLint("ActionValue")
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.input.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PROTOCOL_MODE_CHANGED =
- "android.bluetooth.input.profile.action.PROTOCOL_MODE_CHANGED";
-
- /**
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_HANDSHAKE =
- "android.bluetooth.input.profile.action.HANDSHAKE";
-
- /**
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_REPORT =
- "android.bluetooth.input.profile.action.REPORT";
-
- /**
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_VIRTUAL_UNPLUG_STATUS =
- "android.bluetooth.input.profile.action.VIRTUAL_UNPLUG_STATUS";
-
- /**
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_IDLE_TIME_CHANGED =
- "android.bluetooth.input.profile.action.IDLE_TIME_CHANGED";
-
- /**
- * Return codes for the connect and disconnect Bluez / Dbus calls.
- *
- * @hide
- */
- public static final int INPUT_DISCONNECT_FAILED_NOT_CONNECTED = 5000;
-
- /**
- * @hide
- */
- public static final int INPUT_CONNECT_FAILED_ALREADY_CONNECTED = 5001;
-
- /**
- * @hide
- */
- public static final int INPUT_CONNECT_FAILED_ATTEMPT_FAILED = 5002;
-
- /**
- * @hide
- */
- public static final int INPUT_OPERATION_GENERIC_FAILURE = 5003;
-
- /**
- * @hide
- */
- public static final int INPUT_OPERATION_SUCCESS = 5004;
-
- /**
- * @hide
- */
- public static final int PROTOCOL_REPORT_MODE = 0;
-
- /**
- * @hide
- */
- public static final int PROTOCOL_BOOT_MODE = 1;
-
- /**
- * @hide
- */
- public static final int PROTOCOL_UNSUPPORTED_MODE = 255;
-
- /* int reportType, int reportType, int bufferSize */
- /**
- * @hide
- */
- public static final byte REPORT_TYPE_INPUT = 1;
-
- /**
- * @hide
- */
- public static final byte REPORT_TYPE_OUTPUT = 2;
-
- /**
- * @hide
- */
- public static final byte REPORT_TYPE_FEATURE = 3;
-
- /**
- * @hide
- */
- public static final int VIRTUAL_UNPLUG_STATUS_SUCCESS = 0;
-
- /**
- * @hide
- */
- public static final int VIRTUAL_UNPLUG_STATUS_FAIL = 1;
-
- /**
- * @hide
- */
- public static final String EXTRA_PROTOCOL_MODE =
- "android.bluetooth.BluetoothHidHost.extra.PROTOCOL_MODE";
-
- /**
- * @hide
- */
- public static final String EXTRA_REPORT_TYPE =
- "android.bluetooth.BluetoothHidHost.extra.REPORT_TYPE";
-
- /**
- * @hide
- */
- public static final String EXTRA_REPORT_ID =
- "android.bluetooth.BluetoothHidHost.extra.REPORT_ID";
-
- /**
- * @hide
- */
- public static final String EXTRA_REPORT_BUFFER_SIZE =
- "android.bluetooth.BluetoothHidHost.extra.REPORT_BUFFER_SIZE";
-
- /**
- * @hide
- */
- public static final String EXTRA_REPORT = "android.bluetooth.BluetoothHidHost.extra.REPORT";
-
- /**
- * @hide
- */
- public static final String EXTRA_STATUS = "android.bluetooth.BluetoothHidHost.extra.STATUS";
-
- /**
- * @hide
- */
- public static final String EXTRA_VIRTUAL_UNPLUG_STATUS =
- "android.bluetooth.BluetoothHidHost.extra.VIRTUAL_UNPLUG_STATUS";
-
- /**
- * @hide
- */
- public static final String EXTRA_IDLE_TIME =
- "android.bluetooth.BluetoothHidHost.extra.IDLE_TIME";
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothHidHost> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.HID_HOST,
- "BluetoothHidHost", IBluetoothHidHost.class.getName()) {
- @Override
- public IBluetoothHidHost getServiceInterface(IBinder service) {
- return IBluetoothHidHost.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothHidHost proxy object for interacting with the local
- * Bluetooth Service which handles the InputDevice profile
- */
- /* package */ BluetoothHidHost(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- /*package*/ void close() {
- if (VDBG) log("close()");
- mProfileConnector.disconnect();
- }
-
- private IBluetoothHidHost getService() {
- return mProfileConnector.getService();
- }
-
- /**
- * Initiate connection to a profile of the remote bluetooth device.
- *
- * <p> The system supports connection to multiple input devices.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is already connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that
- * connection state intent for the profile will be broadcasted with
- * the state. Users can get the connection state of the profile
- * from this intent.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnection from a profile
- *
- * <p> This API will return false in scenarios like the profile on the
- * Bluetooth device is not in connected state etc. When this API returns,
- * true, it is guaranteed that the connection state change
- * intent will be broadcasted with the state. Users can get the
- * disconnection state of the profile from this intent.
- *
- * <p> If the disconnection is initiated by a remote device, the state
- * will transition from {@link #STATE_CONNECTED} to
- * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
- * host (local) device the state will transition from
- * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
- * state {@link #STATE_DISCONNECTED}. The transition to
- * {@link #STATE_DISCONNECTING} can be used to distinguish between the
- * two scenarios.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @SystemApi
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothHidHost service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothHidHost service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @SystemApi
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(@NonNull BluetoothDevice device) {
- if (VDBG) log("getState(" + device + ")");
- if (device == null) {
- throw new IllegalArgumentException("device must not be null");
- }
- final IBluetoothHidHost service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) log("setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- if (device == null) {
- throw new IllegalArgumentException("device must not be null");
- }
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- if (device == null) {
- throw new IllegalArgumentException("device must not be null");
- }
- final IBluetoothHidHost service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private boolean isEnabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_ON;
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- /**
- * Initiate virtual unplug for a HID input device.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean virtualUnplug(BluetoothDevice device) {
- if (DBG) log("virtualUnplug(" + device + ")");
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.virtualUnplug(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send Get_Protocol_Mode command to the connected HID input device.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean getProtocolMode(BluetoothDevice device) {
- if (VDBG) log("getProtocolMode(" + device + ")");
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.getProtocolMode(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send Set_Protocol_Mode command to the connected HID input device.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setProtocolMode(BluetoothDevice device, int protocolMode) {
- if (DBG) log("setProtocolMode(" + device + ")");
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setProtocolMode(device, protocolMode, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send Get_Report command to the connected HID input device.
- *
- * @param device Remote Bluetooth Device
- * @param reportType Report type
- * @param reportId Report ID
- * @param bufferSize Report receiving buffer size
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean getReport(BluetoothDevice device, byte reportType, byte reportId,
- int bufferSize) {
- if (VDBG) {
- log("getReport(" + device + "), reportType=" + reportType + " reportId=" + reportId
- + "bufferSize=" + bufferSize);
- }
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.getReport(device, reportType, reportId, bufferSize, mAttributionSource,
- recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send Set_Report command to the connected HID input device.
- *
- * @param device Remote Bluetooth Device
- * @param reportType Report type
- * @param report Report receiving buffer size
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setReport(BluetoothDevice device, byte reportType, String report) {
- if (VDBG) log("setReport(" + device + "), reportType=" + reportType + " report=" + report);
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setReport(device, reportType, report, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send Send_Data command to the connected HID input device.
- *
- * @param device Remote Bluetooth Device
- * @param report Report to send
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean sendData(BluetoothDevice device, String report) {
- if (DBG) log("sendData(" + device + "), report=" + report);
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.sendData(device, report, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send Get_Idle_Time command to the connected HID input device.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean getIdleTime(BluetoothDevice device) {
- if (DBG) log("getIdletime(" + device + ")");
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.getIdleTime(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send Set_Idle_Time command to the connected HID input device.
- *
- * @param device Remote Bluetooth Device
- * @param idleTime Idle time to be set on HID Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setIdleTime(BluetoothDevice device, byte idleTime) {
- if (DBG) log("setIdletime(" + device + "), idleTime=" + idleTime);
- final IBluetoothHidHost service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setIdleTime(device, idleTime, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothInputStream.java b/core/java/android/bluetooth/BluetoothInputStream.java
deleted file mode 100644
index 95f9229..0000000
--- a/core/java/android/bluetooth/BluetoothInputStream.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.SuppressLint;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * BluetoothInputStream.
- *
- * Used to write to a Bluetooth socket.
- *
- * @hide
- */
-@SuppressLint("AndroidFrameworkBluetoothPermission")
-/*package*/ final class BluetoothInputStream extends InputStream {
- private BluetoothSocket mSocket;
-
- /*package*/ BluetoothInputStream(BluetoothSocket s) {
- mSocket = s;
- }
-
- /**
- * Return number of bytes available before this stream will block.
- */
- public int available() throws IOException {
- return mSocket.available();
- }
-
- public void close() throws IOException {
- mSocket.close();
- }
-
- /**
- * Reads a single byte from this stream and returns it as an integer in the
- * range from 0 to 255. Returns -1 if the end of the stream has been
- * reached. Blocks until one byte has been read, the end of the source
- * stream is detected or an exception is thrown.
- *
- * @return the byte read or -1 if the end of stream has been reached.
- * @throws IOException if the stream is closed or another IOException occurs.
- * @since Android 1.5
- */
- public int read() throws IOException {
- byte[] b = new byte[1];
- int ret = mSocket.read(b, 0, 1);
- if (ret == 1) {
- return (int) b[0] & 0xff;
- } else {
- return -1;
- }
- }
-
- /**
- * Reads at most {@code length} bytes from this stream and stores them in
- * the byte array {@code b} starting at {@code offset}.
- *
- * @param b the byte array in which to store the bytes read.
- * @param offset the initial position in {@code buffer} to store the bytes read from this
- * stream.
- * @param length the maximum number of bytes to store in {@code b}.
- * @return the number of bytes actually read or -1 if the end of the stream has been reached.
- * @throws IndexOutOfBoundsException if {@code offset < 0} or {@code length < 0}, or if {@code
- * offset + length} is greater than the length of {@code b}.
- * @throws IOException if the stream is closed or another IOException occurs.
- * @since Android 1.5
- */
- public int read(byte[] b, int offset, int length) throws IOException {
- if (b == null) {
- throw new NullPointerException("byte array is null");
- }
- if ((offset | length) < 0 || length > b.length - offset) {
- throw new ArrayIndexOutOfBoundsException("invalid offset or length");
- }
- return mSocket.read(b, offset, length);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothLeAudio.java b/core/java/android/bluetooth/BluetoothLeAudio.java
deleted file mode 100644
index 15db686..0000000
--- a/core/java/android/bluetooth/BluetoothLeAudio.java
+++ /dev/null
@@ -1,829 +0,0 @@
-/*
- * Copyright 2020 HIMSA II K/S - www.himsa.com.
- * Represented by EHIMA - www.ehima.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.CloseGuard;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the public APIs to control the LeAudio profile.
- *
- * <p>BluetoothLeAudio is a proxy object for controlling the Bluetooth LE Audio
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothLeAudio proxy object.
- *
- * <p> Android only supports one set of connected Bluetooth LeAudio device at a time. Each
- * method is protected with its appropriate permission.
- */
-public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
- private static final String TAG = "BluetoothLeAudio";
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
-
- private CloseGuard mCloseGuard;
-
- /**
- * Intent used to broadcast the change in connection state of the LeAudio
- * profile. Please note that in the binaural case, there will be two different LE devices for
- * the left and right side and each device will have their own connection state changes.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED =
- "android.bluetooth.action.LE_AUDIO_CONNECTION_STATE_CHANGED";
-
- /**
- * Intent used to broadcast the selection of a connected device as active.
- *
- * <p>This intent will have one extra:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
- * be null if no device is active. </li>
- * </ul>
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED =
- "android.bluetooth.action.LE_AUDIO_ACTIVE_DEVICE_CHANGED";
-
- /**
- * Intent used to broadcast group node status information.
- *
- * <p>This intent will have 3 extra:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
- * be null if no device is active. </li>
- * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
- * <li> {@link #EXTRA_LE_AUDIO_GROUP_NODE_STATUS} - Group node status. </li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_LE_AUDIO_GROUP_NODE_STATUS_CHANGED =
- "android.bluetooth.action.LE_AUDIO_GROUP_NODE_STATUS_CHANGED";
-
-
- /**
- * Intent used to broadcast group status information.
- *
- * <p>This intent will have 4 extra:
- * <ul>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. It can
- * be null if no device is active. </li>
- * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
- * <li> {@link #EXTRA_LE_AUDIO_GROUP_STATUS} - Group status. </li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_LE_AUDIO_GROUP_STATUS_CHANGED =
- "android.bluetooth.action.LE_AUDIO_GROUP_STATUS_CHANGED";
-
- /**
- * Intent used to broadcast group audio configuration changed information.
- *
- * <p>This intent will have 5 extra:
- * <ul>
- * <li> {@link #EXTRA_LE_AUDIO_GROUP_ID} - Group id. </li>
- * <li> {@link #EXTRA_LE_AUDIO_DIRECTION} - Direction as bit mask. </li>
- * <li> {@link #EXTRA_LE_AUDIO_SINK_LOCATION} - Sink location as per Bluetooth Assigned
- * Numbers </li>
- * <li> {@link #EXTRA_LE_AUDIO_SOURCE_LOCATION} - Source location as per Bluetooth Assigned
- * Numbers </li>
- * <li> {@link #EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS} - Available contexts for group as per
- * Bluetooth Assigned Numbers </li>
- * </ul>
- *
- * @hide
- */
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_LE_AUDIO_CONF_CHANGED =
- "android.bluetooth.action.LE_AUDIO_CONF_CHANGED";
-
- /**
- * Indicates unspecified audio content.
- * @hide
- */
- public static final int CONTEXT_TYPE_UNSPECIFIED = 0x0001;
-
- /**
- * Indicates conversation between humans as, for example, in telephony or video calls.
- * @hide
- */
- public static final int CONTEXT_TYPE_COMMUNICATION = 0x0002;
-
- /**
- * Indicates media as, for example, in music, public radio, podcast or video soundtrack.
- * @hide
- */
- public static final int CONTEXT_TYPE_MEDIA = 0x0004;
-
- /**
- * Indicates instructional audio as, for example, in navigation, traffic announcements
- * or user guidance.
- * @hide
- */
- public static final int CONTEXT_TYPE_INSTRUCTIONAL = 0x0008;
-
- /**
- * Indicates attention seeking audio as, for example, in beeps signalling arrival of a message
- * or keyboard clicks.
- * @hide
- */
- public static final int CONTEXT_TYPE_ATTENTION_SEEKING = 0x0010;
-
- /**
- * Indicates immediate alerts as, for example, in a low battery alarm, timer expiry or alarm
- * clock.
- * @hide
- */
- public static final int CONTEXT_TYPE_IMMEDIATE_ALERT = 0x0020;
-
- /**
- * Indicates man machine communication as, for example, with voice recognition or virtual
- * assistant.
- * @hide
- */
- public static final int CONTEXT_TYPE_MAN_MACHINE = 0x0040;
-
- /**
- * Indicates emergency alerts as, for example, with fire alarms or other urgent alerts.
- * @hide
- */
- public static final int CONTEXT_TYPE_EMERGENCY_ALERT = 0x0080;
-
- /**
- * Indicates ringtone as in a call alert.
- * @hide
- */
- public static final int CONTEXT_TYPE_RINGTONE = 0x0100;
-
- /**
- * Indicates audio associated with a television program and/or with metadata conforming to the
- * Bluetooth Broadcast TV profile.
- * @hide
- */
- public static final int CONTEXT_TYPE_TV = 0x0200;
-
- /**
- * Indicates audio associated with a low latency live audio stream.
- *
- * @hide
- */
- public static final int CONTEXT_TYPE_LIVE = 0x0400;
-
- /**
- * Indicates audio associated with a video game stream.
- * @hide
- */
- public static final int CONTEXT_TYPE_GAME = 0x0800;
-
- /**
- * This represents an invalid group ID.
- *
- * @hide
- */
- public static final int GROUP_ID_INVALID = IBluetoothLeAudio.LE_AUDIO_GROUP_ID_INVALID;
-
- /**
- * Contains group id.
- * @hide
- */
- public static final String EXTRA_LE_AUDIO_GROUP_ID =
- "android.bluetooth.extra.LE_AUDIO_GROUP_ID";
-
- /**
- * Contains group node status, can be any of
- * <p>
- * <ul>
- * <li> {@link #GROUP_NODE_ADDED} </li>
- * <li> {@link #GROUP_NODE_REMOVED} </li>
- * </ul>
- * <p>
- * @hide
- */
- public static final String EXTRA_LE_AUDIO_GROUP_NODE_STATUS =
- "android.bluetooth.extra.LE_AUDIO_GROUP_NODE_STATUS";
-
- /**
- * Contains group status, can be any of
- *
- * <p>
- * <ul>
- * <li> {@link #GROUP_STATUS_ACTIVE} </li>
- * <li> {@link #GROUP_STATUS_INACTIVE} </li>
- * </ul>
- * <p>
- * @hide
- */
- public static final String EXTRA_LE_AUDIO_GROUP_STATUS =
- "android.bluetooth.extra.LE_AUDIO_GROUP_STATUS";
-
- /**
- * Contains bit mask for direction, bit 0 set when Sink, bit 1 set when Source.
- * @hide
- */
- public static final String EXTRA_LE_AUDIO_DIRECTION =
- "android.bluetooth.extra.LE_AUDIO_DIRECTION";
-
- /**
- * Contains source location as per Bluetooth Assigned Numbers
- * @hide
- */
- public static final String EXTRA_LE_AUDIO_SOURCE_LOCATION =
- "android.bluetooth.extra.LE_AUDIO_SOURCE_LOCATION";
-
- /**
- * Contains sink location as per Bluetooth Assigned Numbers
- * @hide
- */
- public static final String EXTRA_LE_AUDIO_SINK_LOCATION =
- "android.bluetooth.extra.LE_AUDIO_SINK_LOCATION";
-
- /**
- * Contains available context types for group as per Bluetooth Assigned Numbers
- * @hide
- */
- public static final String EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS =
- "android.bluetooth.extra.LE_AUDIO_AVAILABLE_CONTEXTS";
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- /**
- * Indicating that group is Active ( Audio device is available )
- * @hide
- */
- public static final int GROUP_STATUS_ACTIVE = IBluetoothLeAudio.GROUP_STATUS_ACTIVE;
-
- /**
- * Indicating that group is Inactive ( Audio device is not available )
- * @hide
- */
- public static final int GROUP_STATUS_INACTIVE = IBluetoothLeAudio.GROUP_STATUS_INACTIVE;
-
- /**
- * Indicating that node has been added to the group.
- * @hide
- */
- public static final int GROUP_NODE_ADDED = IBluetoothLeAudio.GROUP_NODE_ADDED;
-
- /**
- * Indicating that node has been removed from the group.
- * @hide
- */
- public static final int GROUP_NODE_REMOVED = IBluetoothLeAudio.GROUP_NODE_REMOVED;
-
- private final BluetoothProfileConnector<IBluetoothLeAudio> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.LE_AUDIO, "BluetoothLeAudio",
- IBluetoothLeAudio.class.getName()) {
- @Override
- public IBluetoothLeAudio getServiceInterface(IBinder service) {
- return IBluetoothLeAudio.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothLeAudio proxy object for interacting with the local
- * Bluetooth LeAudio service.
- */
- /* package */ BluetoothLeAudio(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- mCloseGuard = new CloseGuard();
- mCloseGuard.open("close");
- }
-
- /**
- * @hide
- */
- public void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothLeAudio getService() {
- return mProfileConnector.getService();
- }
-
- protected void finalize() {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- close();
- }
-
- /**
- * Initiate connection to a profile of the remote bluetooth device.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is already connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that
- * connection state intent for the profile will be broadcasted with
- * the state. Users can get the connection state of the profile
- * from this intent.
- *
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean connect(@Nullable BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- final IBluetoothLeAudio service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnection from a profile
- *
- * <p> This API will return false in scenarios like the profile on the
- * Bluetooth device is not in connected state etc. When this API returns,
- * true, it is guaranteed that the connection state change
- * intent will be broadcasted with the state. Users can get the
- * disconnection state of the profile from this intent.
- *
- * <p> If the disconnection is initiated by a remote device, the state
- * will transition from {@link #STATE_CONNECTED} to
- * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
- * host (local) device the state will transition from
- * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
- * state {@link #STATE_DISCONNECTED}. The transition to
- * {@link #STATE_DISCONNECTING} can be used to distinguish between the
- * two scenarios.
- *
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(@Nullable BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothLeAudio service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothLeAudio service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
- @NonNull int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothLeAudio service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
- if (VDBG) log("getState(" + device + ")");
- final IBluetoothLeAudio service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Select a connected device as active.
- *
- * The active device selection is per profile. An active device's
- * purpose is profile-specific. For example, LeAudio audio
- * streaming is to the active LeAudio device. If a remote device
- * is not connected, it cannot be selected as active.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is not connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that the
- * {@link #ACTION_LE_AUDIO_ACTIVE_DEVICE_CHANGED} intent will be broadcasted
- * with the active device.
- *
- *
- * @param device the remote Bluetooth device. Could be null to clear
- * the active device and stop streaming audio to a Bluetooth device.
- * @return false on immediate error, true otherwise
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean setActiveDevice(@Nullable BluetoothDevice device) {
- if (DBG) log("setActiveDevice(" + device + ")");
- final IBluetoothLeAudio service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled() && ((device == null) || isValidDevice(device))) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setActiveDevice(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the connected LeAudio devices that are active
- *
- * @return the list of active devices. Returns empty list on error.
- * @hide
- */
- @NonNull
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getActiveDevices() {
- if (VDBG) log("getActiveDevice()");
- final IBluetoothLeAudio service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getActiveDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get device group id. Devices with same group id belong to same group (i.e left and right
- * earbud)
- * @param device LE Audio capable device
- * @return group id that this device currently belongs to
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getGroupId(@NonNull BluetoothDevice device) {
- if (VDBG) log("getGroupId()");
- final IBluetoothLeAudio service = getService();
- final int defaultValue = GROUP_ID_INVALID;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getGroupId(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set volume for the streaming devices
- *
- * @param volume volume to set
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.BLUETOOTH_PRIVILEGED})
- public void setVolume(int volume) {
- if (VDBG) log("setVolume(vol: " + volume + " )");
- final IBluetoothLeAudio service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.setVolume(volume, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Add device to the given group.
- * @param group_id group ID the device is being added to
- * @param device the active device
- * @return true on success, otherwise false
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED
- })
- public boolean groupAddNode(int group_id, @NonNull BluetoothDevice device) {
- if (VDBG) log("groupAddNode()");
- final IBluetoothLeAudio service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.groupAddNode(group_id, device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Remove device from a given group.
- * @param group_id group ID the device is being removed from
- * @param device the active device
- * @return true on success, otherwise false
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED
- })
- public boolean groupRemoveNode(int group_id, @NonNull BluetoothDevice device) {
- if (VDBG) log("groupRemoveNode()");
- final IBluetoothLeAudio service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.groupRemoveNode(group_id, device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothLeAudio service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public @ConnectionPolicy int getConnectionPolicy(@Nullable BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothLeAudio service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (mAdapter.isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
-
- /**
- * Helper for converting a state to a string.
- *
- * For debug use only - strings are not internationalized.
- *
- * @hide
- */
- public static String stateToString(int state) {
- switch (state) {
- case STATE_DISCONNECTED:
- return "disconnected";
- case STATE_CONNECTING:
- return "connecting";
- case STATE_CONNECTED:
- return "connected";
- case STATE_DISCONNECTING:
- return "disconnecting";
- default:
- return "<unknown state " + state + ">";
- }
- }
-
- private boolean isValidDevice(@Nullable BluetoothDevice device) {
- if (device == null) return false;
-
- if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
- return false;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java b/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java
deleted file mode 100644
index dcaf4b6..0000000
--- a/core/java/android/bluetooth/BluetoothLeAudioCodecConfig.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Represents the codec configuration for a Bluetooth LE Audio source device.
- * <p>Contains the source codec type.
- * <p>The source codec type values are the same as those supported by the
- * device hardware.
- *
- * {@see BluetoothLeAudioCodecConfig}
- */
-public final class BluetoothLeAudioCodecConfig {
- // Add an entry for each source codec here.
-
- /** @hide */
- @IntDef(prefix = "SOURCE_CODEC_TYPE_", value = {
- SOURCE_CODEC_TYPE_LC3,
- SOURCE_CODEC_TYPE_INVALID
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface SourceCodecType {};
-
- public static final int SOURCE_CODEC_TYPE_LC3 = 0;
- public static final int SOURCE_CODEC_TYPE_INVALID = 1000 * 1000;
-
- /**
- * Represents the count of valid source codec types. Can be accessed via
- * {@link #getMaxCodecType}.
- */
- private static final int SOURCE_CODEC_TYPE_MAX = 1;
-
- private final @SourceCodecType int mCodecType;
-
- /**
- * Creates a new BluetoothLeAudioCodecConfig.
- *
- * @param codecType the source codec type
- */
- private BluetoothLeAudioCodecConfig(@SourceCodecType int codecType) {
- mCodecType = codecType;
- }
-
- @Override
- public String toString() {
- return "{codecName:" + getCodecName() + "}";
- }
-
- /**
- * Gets the codec type.
- *
- * @return the codec type
- */
- public @SourceCodecType int getCodecType() {
- return mCodecType;
- }
-
- /**
- * Returns the valid codec types count.
- */
- public static int getMaxCodecType() {
- return SOURCE_CODEC_TYPE_MAX;
- }
-
- /**
- * Gets the codec name.
- *
- * @return the codec name
- */
- public @NonNull String getCodecName() {
- switch (mCodecType) {
- case SOURCE_CODEC_TYPE_LC3:
- return "LC3";
- case SOURCE_CODEC_TYPE_INVALID:
- return "INVALID CODEC";
- default:
- break;
- }
- return "UNKNOWN CODEC(" + mCodecType + ")";
- }
-
- /**
- * Builder for {@link BluetoothLeAudioCodecConfig}.
- * <p> By default, the codec type will be set to
- * {@link BluetoothLeAudioCodecConfig#SOURCE_CODEC_TYPE_INVALID}
- */
- public static final class Builder {
- private int mCodecType = BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID;
-
- /**
- * Set codec type for Bluetooth codec config.
- *
- * @param codecType of this codec
- * @return the same Builder instance
- */
- public @NonNull Builder setCodecType(@SourceCodecType int codecType) {
- mCodecType = codecType;
- return this;
- }
-
- /**
- * Build {@link BluetoothLeAudioCodecConfig}.
- * @return new BluetoothLeAudioCodecConfig built
- */
- public @NonNull BluetoothLeAudioCodecConfig build() {
- return new BluetoothLeAudioCodecConfig(mCodecType);
- }
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothLeBroadcast.java b/core/java/android/bluetooth/BluetoothLeBroadcast.java
deleted file mode 100644
index fed9f91..0000000
--- a/core/java/android/bluetooth/BluetoothLeBroadcast.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.content.Context;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/**
- * This class provides the public APIs to control the Bluetooth LE Broadcast Source profile.
- *
- * <p>BluetoothLeBroadcast is a proxy object for controlling the Bluetooth LE Broadcast
- * Source Service via IPC. Use {@link BluetoothAdapter#getProfileProxy}
- * to get the BluetoothLeBroadcast proxy object.
- *
- * @hide
- */
-public final class BluetoothLeBroadcast implements BluetoothProfile {
- private static final String TAG = "BluetoothLeBroadcast";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Constants used by the LE Audio Broadcast profile for the Broadcast state
- *
- * @hide
- */
- @IntDef(prefix = {"LE_AUDIO_BROADCAST_STATE_"}, value = {
- LE_AUDIO_BROADCAST_STATE_DISABLED,
- LE_AUDIO_BROADCAST_STATE_ENABLING,
- LE_AUDIO_BROADCAST_STATE_ENABLED,
- LE_AUDIO_BROADCAST_STATE_DISABLING,
- LE_AUDIO_BROADCAST_STATE_PLAYING,
- LE_AUDIO_BROADCAST_STATE_NOT_PLAYING
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LeAudioBroadcastState {}
-
- /**
- * Indicates that LE Audio Broadcast mode is currently disabled
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_STATE_DISABLED = 10;
-
- /**
- * Indicates that LE Audio Broadcast mode is being enabled
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_STATE_ENABLING = 11;
-
- /**
- * Indicates that LE Audio Broadcast mode is currently enabled
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_STATE_ENABLED = 12;
- /**
- * Indicates that LE Audio Broadcast mode is being disabled
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_STATE_DISABLING = 13;
-
- /**
- * Indicates that an LE Audio Broadcast mode is currently playing
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_STATE_PLAYING = 14;
-
- /**
- * Indicates that LE Audio Broadcast is currently not playing
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_STATE_NOT_PLAYING = 15;
-
- /**
- * Constants used by the LE Audio Broadcast profile for encryption key length
- *
- * @hide
- */
- @IntDef(prefix = {"LE_AUDIO_BROADCAST_ENCRYPTION_KEY_"}, value = {
- LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT,
- LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LeAudioEncryptionKeyLength {}
-
- /**
- * Indicates that the LE Audio Broadcast encryption key size is 32 bits.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_32BIT = 16;
-
- /**
- * Indicates that the LE Audio Broadcast encryption key size is 128 bits.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_ENCRYPTION_KEY_128BIT = 17;
-
- /**
- * Interface for receiving events related to broadcasts
- */
- public interface Callback {
- /**
- * Called when broadcast state has changed
- *
- * @param prevState broadcast state before the change
- * @param newState broadcast state after the change
- */
- @LeAudioBroadcastState
- void onBroadcastStateChange(int prevState, int newState);
- /**
- * Called when encryption key has been updated
- *
- * @param success true if the key was updated successfully, false otherwise
- */
- void onEncryptionKeySet(boolean success);
- }
-
- /**
- * Create a BluetoothLeBroadcast proxy object for interacting with the local
- * LE Audio Broadcast Source service.
- *
- * @hide
- */
- /*package*/ BluetoothLeBroadcast(Context context,
- BluetoothProfile.ServiceListener listener) {
- }
-
- /**
- * Not supported since LE Audio Broadcasts do not establish a connection
- *
- * @throws UnsupportedOperationException
- *
- * @hide
- */
- @Override
- public int getConnectionState(BluetoothDevice device) {
- throw new UnsupportedOperationException(
- "LE Audio Broadcasts are not connection-oriented.");
- }
-
- /**
- * Not supported since LE Audio Broadcasts do not establish a connection
- *
- * @throws UnsupportedOperationException
- *
- * @hide
- */
- @Override
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- throw new UnsupportedOperationException(
- "LE Audio Broadcasts are not connection-oriented.");
- }
-
- /**
- * Not supported since LE Audio Broadcasts do not establish a connection
- *
- * @throws UnsupportedOperationException
- *
- * @hide
- */
- @Override
- public List<BluetoothDevice> getConnectedDevices() {
- throw new UnsupportedOperationException(
- "LE Audio Broadcasts are not connection-oriented.");
- }
-
- /**
- * Enable LE Audio Broadcast mode.
- *
- * Generates a new broadcast ID and enables sending of encrypted or unencrypted
- * isochronous PDUs
- *
- * @hide
- */
- public int enableBroadcastMode() {
- if (DBG) log("enableBroadcastMode");
- return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED;
- }
-
- /**
- * Disable LE Audio Broadcast mode.
- *
- * @hide
- */
- public int disableBroadcastMode() {
- if (DBG) log("disableBroadcastMode");
- return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED;
- }
-
- /**
- * Get the current LE Audio broadcast state
- *
- * @hide
- */
- @LeAudioBroadcastState
- public int getBroadcastState() {
- if (DBG) log("getBroadcastState");
- return LE_AUDIO_BROADCAST_STATE_DISABLED;
- }
-
- /**
- * Enable LE Audio broadcast encryption
- *
- * @param keyLength if useExisting is true, this specifies the length of the key that should
- * be generated
- * @param useExisting true, if an existing key should be used
- * false, if a new key should be generated
- *
- * @hide
- */
- @LeAudioEncryptionKeyLength
- public int enableEncryption(boolean useExisting, int keyLength) {
- if (DBG) log("enableEncryption useExisting=" + useExisting + " keyLength=" + keyLength);
- return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED;
- }
-
- /**
- * Disable LE Audio broadcast encryption
- *
- * @param removeExisting true, if the existing key should be removed
- * false, otherwise
- *
- * @hide
- */
- public int disableEncryption(boolean removeExisting) {
- if (DBG) log("disableEncryption removeExisting=" + removeExisting);
- return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED;
- }
-
- /**
- * Enable or disable LE Audio broadcast encryption
- *
- * @param key use the provided key if non-null, generate a new key if null
- * @param keyLength 0 if encryption is disabled, 4 bytes (low security),
- * 16 bytes (high security)
- *
- * @hide
- */
- @LeAudioEncryptionKeyLength
- public int setEncryptionKey(byte[] key, int keyLength) {
- if (DBG) log("setEncryptionKey key=" + key + " keyLength=" + keyLength);
- return BluetoothStatusCodes.ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED;
- }
-
-
- /**
- * Get the encryption key that was set before
- *
- * @return encryption key as a byte array or null if no encryption key was set
- *
- * @hide
- */
- public byte[] getEncryptionKey() {
- if (DBG) log("getEncryptionKey");
- return null;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java b/core/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java
deleted file mode 100644
index b866cce..0000000
--- a/core/java/android/bluetooth/BluetoothLeBroadcastAssistantCallback.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.bluetooth.le.ScanResult;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * This class provides a set of callbacks that are invoked when scanning for Broadcast Sources is
- * offloaded to a Broadcast Assistant.
- *
- * <p>An LE Audio Broadcast Assistant can help a Broadcast Sink to scan for available Broadcast
- * Sources. The Broadcast Sink achieves this by offloading the scan to a Broadcast Assistant. This
- * is facilitated by the Broadcast Audio Scan Service (BASS). A BASS server is a GATT server that is
- * part of the Scan Delegator on a Broadcast Sink. A BASS client instead runs on the Broadcast
- * Assistant.
- *
- * <p>Once a GATT connection is established between the BASS client and the BASS server, the
- * Broadcast Sink can offload the scans to the Broadcast Assistant. Upon finding new Broadcast
- * Sources, the Broadcast Assistant then notifies the Broadcast Sink about these over the
- * established GATT connection. The Scan Delegator on the Broadcast Sink can also notify the
- * Assistant about changes such as addition and removal of Broadcast Sources.
- *
- * @hide
- */
-public abstract class BluetoothLeBroadcastAssistantCallback {
-
- /**
- * Broadcast Audio Scan Service (BASS) codes returned by a BASS Server
- *
- * @hide
- */
- @IntDef(
- prefix = "BASS_STATUS_",
- value = {
- BASS_STATUS_SUCCESS,
- BASS_STATUS_FAILURE,
- BASS_STATUS_INVALID_GATT_HANDLE,
- BASS_STATUS_TXN_TIMEOUT,
- BASS_STATUS_INVALID_SOURCE_ID,
- BASS_STATUS_COLOCATED_SRC_UNAVAILABLE,
- BASS_STATUS_INVALID_SOURCE_SELECTED,
- BASS_STATUS_SOURCE_UNAVAILABLE,
- BASS_STATUS_DUPLICATE_ADDITION,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface BassStatus {}
-
- public static final int BASS_STATUS_SUCCESS = 0x00;
- public static final int BASS_STATUS_FAILURE = 0x01;
- public static final int BASS_STATUS_INVALID_GATT_HANDLE = 0x02;
- public static final int BASS_STATUS_TXN_TIMEOUT = 0x03;
-
- public static final int BASS_STATUS_INVALID_SOURCE_ID = 0x04;
- public static final int BASS_STATUS_COLOCATED_SRC_UNAVAILABLE = 0x05;
- public static final int BASS_STATUS_INVALID_SOURCE_SELECTED = 0x06;
- public static final int BASS_STATUS_SOURCE_UNAVAILABLE = 0x07;
- public static final int BASS_STATUS_DUPLICATE_ADDITION = 0x08;
- public static final int BASS_STATUS_NO_EMPTY_SLOT = 0x09;
- public static final int BASS_STATUS_INVALID_GROUP_OP = 0x10;
-
- /**
- * Callback invoked when a new LE Audio Broadcast Source is found.
- *
- * @param result {@link ScanResult} scan result representing a Broadcast Source
- */
- public void onBluetoothLeBroadcastSourceFound(@NonNull ScanResult result) {}
-
- /**
- * Callback invoked when the Broadcast Assistant synchronizes with Periodic Advertisements (PAs)
- * of an LE Audio Broadcast Source.
- *
- * @param source the selected Broadcast Source
- */
- public void onBluetoothLeBroadcastSourceSelected(
- @NonNull BluetoothLeBroadcastSourceInfo source, @BassStatus int status) {}
-
- /**
- * Callback invoked when the Broadcast Assistant loses synchronization with an LE Audio
- * Broadcast Source.
- *
- * @param source the Broadcast Source with which synchronization was lost
- */
- public void onBluetoothLeBroadcastSourceLost(
- @NonNull BluetoothLeBroadcastSourceInfo source, @BassStatus int status) {}
-
- /**
- * Callback invoked when a new LE Audio Broadcast Source has been successfully added to the Scan
- * Delegator (within a Broadcast Sink, for example).
- *
- * @param sink Scan Delegator device on which a new Broadcast Source has been added
- * @param source the added Broadcast Source
- */
- public void onBluetoothLeBroadcastSourceAdded(
- @NonNull BluetoothDevice sink,
- @NonNull BluetoothLeBroadcastSourceInfo source,
- @BassStatus int status) {}
-
- /**
- * Callback invoked when an existing LE Audio Broadcast Source within a remote Scan Delegator
- * has been updated.
- *
- * @param sink Scan Delegator device on which a Broadcast Source has been updated
- * @param source the updated Broadcast Source
- */
- public void onBluetoothLeBroadcastSourceUpdated(
- @NonNull BluetoothDevice sink,
- @NonNull BluetoothLeBroadcastSourceInfo source,
- @BassStatus int status) {}
-
- /**
- * Callback invoked when an LE Audio Broadcast Source has been successfully removed from the
- * Scan Delegator (within a Broadcast Sink, for example).
- *
- * @param sink Scan Delegator device from which a Broadcast Source has been removed
- * @param source the removed Broadcast Source
- */
- public void onBluetoothLeBroadcastSourceRemoved(
- @NonNull BluetoothDevice sink,
- @NonNull BluetoothLeBroadcastSourceInfo source,
- @BassStatus int status) {}
-}
diff --git a/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java b/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java
deleted file mode 100644
index cb47280..0000000
--- a/core/java/android/bluetooth/BluetoothLeBroadcastSourceInfo.java
+++ /dev/null
@@ -1,788 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * This class represents an LE Audio Broadcast Source and the associated information that is needed
- * by Broadcast Audio Scan Service (BASS) residing on a Scan Delegator.
- *
- * <p>For example, the Scan Delegator on an LE Audio Broadcast Sink can use the information
- * contained within an instance of this class to synchronize with an LE Audio Broadcast Source in
- * order to listen to a Broadcast Audio Stream.
- *
- * <p>BroadcastAssistant has a BASS client which facilitates scanning and discovery of Broadcast
- * Sources on behalf of say a Broadcast Sink. Upon successful discovery of one or more Broadcast
- * sources, this information needs to be communicated to the BASS Server residing within the Scan
- * Delegator on a Broadcast Sink. This is achieved using the Periodic Advertising Synchronization
- * Transfer (PAST) procedure. This procedure uses information contained within an instance of this
- * class.
- *
- * @hide
- */
-public final class BluetoothLeBroadcastSourceInfo implements Parcelable {
- private static final String TAG = "BluetoothLeBroadcastSourceInfo";
- private static final boolean DBG = true;
-
- /**
- * Constants representing Broadcast Source address types
- *
- * @hide
- */
- @IntDef(
- prefix = "LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_",
- value = {
- LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC,
- LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM,
- LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LeAudioBroadcastSourceAddressType {}
-
- /**
- * Represents a public address used by an LE Audio Broadcast Source
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_PUBLIC = 0;
-
- /**
- * Represents a random address used by an LE Audio Broadcast Source
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_RANDOM = 1;
-
- /**
- * Represents an invalid address used by an LE Audio Broadcast Seurce
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID = 0xFFFF;
-
- /**
- * Periodic Advertising Synchronization state
- *
- * <p>Periodic Advertising (PA) enables the LE Audio Broadcast Assistant to discover broadcast
- * audio streams as well as the audio stream configuration on behalf of an LE Audio Broadcast
- * Sink. This information can then be transferred to the LE Audio Broadcast Sink using the
- * Periodic Advertising Synchronizaton Transfer (PAST) procedure.
- *
- * @hide
- */
- @IntDef(
- prefix = "LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_",
- value = {
- LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE,
- LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ,
- LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC,
- LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL,
- LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LeAudioBroadcastSinkPaSyncState {}
-
- /**
- * Indicates that the Broadcast Sink is not synchronized with the Periodic Advertisements (PA)
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IDLE = 0;
-
- /**
- * Indicates that the Broadcast Sink requested the Broadcast Assistant to synchronize with the
- * Periodic Advertisements (PA).
- *
- * <p>This is also known as scan delegation or scan offloading.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNCINFO_REQ = 1;
-
- /**
- * Indicates that the Broadcast Sink is synchronized with the Periodic Advertisements (PA).
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_IN_SYNC = 2;
-
- /**
- * Indicates that the Broadcast Sink was unable to synchronize with the Periodic Advertisements
- * (PA).
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_SYNC_FAIL = 3;
-
- /**
- * Indicates that the Broadcast Sink should be synchronized with the Periodic Advertisements
- * (PA) using the Periodic Advertisements Synchronization Transfert (PAST) procedure.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_NO_PAST = 4;
-
- /**
- * Indicates that the Broadcast Sink synchornization state is invalid.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID = 0xFFFF;
-
- /** @hide */
- @IntDef(
- prefix = "LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_",
- value = {
- LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED,
- LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LeAudioBroadcastSinkAudioSyncState {}
-
- /**
- * Indicates that the Broadcast Sink is not synchronized with a Broadcast Audio Stream.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_NOT_SYNCHRONIZED = 0;
-
- /**
- * Indicates that the Broadcast Sink is synchronized with a Broadcast Audio Stream.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_SYNCHRONIZED = 1;
-
- /**
- * Indicates that the Broadcast Sink audio synchronization state is invalid.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID = 0xFFFF;
-
- /** @hide */
- @IntDef(
- prefix = "LE_AUDIO_BROADCAST_SINK_ENC_STATE_",
- value = {
- LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED,
- LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED,
- LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING,
- LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LeAudioBroadcastSinkEncryptionState {}
-
- /**
- * Indicates that the Broadcast Sink is synchronized with an unencrypted audio stream.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_NOT_ENCRYPTED = 0;
-
- /**
- * Indicates that the Broadcast Sink needs a Broadcast Code to synchronize with the audio
- * stream.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_CODE_REQUIRED = 1;
-
- /**
- * Indicates that the Broadcast Sink is synchronized with an encrypted audio stream.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_DECRYPTING = 2;
-
- /**
- * Indicates that the Broadcast Sink is unable to decrypt an audio stream due to an incorrect
- * Broadcast Code
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE = 3;
-
- /**
- * Indicates that the Broadcast Sink encryption state is invalid.
- *
- * @hide
- */
- public static final int LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID = 0xFF;
-
- /**
- * Represents an invalid LE Audio Broadcast Source ID
- *
- * @hide
- */
- public static final byte LE_AUDIO_BROADCAST_SINK_INVALID_SOURCE_ID = (byte) 0x00;
-
- /**
- * Represents an invalid Broadcast ID of a Broadcast Source
- *
- * @hide
- */
- public static final int INVALID_BROADCAST_ID = 0xFFFFFF;
-
- private byte mSourceId;
- private @LeAudioBroadcastSourceAddressType int mSourceAddressType;
- private BluetoothDevice mSourceDevice;
- private byte mSourceAdvSid;
- private int mBroadcastId;
- private @LeAudioBroadcastSinkPaSyncState int mPaSyncState;
- private @LeAudioBroadcastSinkEncryptionState int mEncryptionStatus;
- private @LeAudioBroadcastSinkAudioSyncState int mAudioSyncState;
- private byte[] mBadBroadcastCode;
- private byte mNumSubGroups;
- private Map<Integer, Integer> mSubgroupBisSyncState = new HashMap<Integer, Integer>();
- private Map<Integer, byte[]> mSubgroupMetadata = new HashMap<Integer, byte[]>();
-
- private String mBroadcastCode;
- private static final int BIS_NO_PREF = 0xFFFFFFFF;
- private static final int BROADCAST_CODE_SIZE = 16;
-
- /**
- * Constructor to create an Empty object of {@link BluetoothLeBroadcastSourceInfo } with the
- * given Source Id.
- *
- * <p>This is mainly used to represent the Empty Broadcast Source entries
- *
- * @param sourceId Source Id for this Broadcast Source info object
- * @hide
- */
- public BluetoothLeBroadcastSourceInfo(byte sourceId) {
- mSourceId = sourceId;
- mSourceAddressType = LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID;
- mSourceDevice = null;
- mSourceAdvSid = (byte) 0x00;
- mBroadcastId = INVALID_BROADCAST_ID;
- mPaSyncState = LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID;
- mAudioSyncState = LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID;
- mEncryptionStatus = LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID;
- mBadBroadcastCode = null;
- mNumSubGroups = 0;
- mBroadcastCode = null;
- }
-
- /*package*/ BluetoothLeBroadcastSourceInfo(
- byte sourceId,
- @LeAudioBroadcastSourceAddressType int addressType,
- @NonNull BluetoothDevice device,
- byte advSid,
- int broadcastId,
- @LeAudioBroadcastSinkPaSyncState int paSyncstate,
- @LeAudioBroadcastSinkEncryptionState int encryptionStatus,
- @LeAudioBroadcastSinkAudioSyncState int audioSyncstate,
- @Nullable byte[] badCode,
- byte numSubGroups,
- @NonNull Map<Integer, Integer> bisSyncState,
- @Nullable Map<Integer, byte[]> subgroupMetadata,
- @NonNull String broadcastCode) {
- mSourceId = sourceId;
- mSourceAddressType = addressType;
- mSourceDevice = device;
- mSourceAdvSid = advSid;
- mBroadcastId = broadcastId;
- mPaSyncState = paSyncstate;
- mEncryptionStatus = encryptionStatus;
- mAudioSyncState = audioSyncstate;
-
- if (badCode != null && badCode.length != 0) {
- mBadBroadcastCode = new byte[badCode.length];
- System.arraycopy(badCode, 0, mBadBroadcastCode, 0, badCode.length);
- }
- mNumSubGroups = numSubGroups;
- mSubgroupBisSyncState = new HashMap<Integer, Integer>(bisSyncState);
- mSubgroupMetadata = new HashMap<Integer, byte[]>(subgroupMetadata);
- mBroadcastCode = broadcastCode;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof BluetoothLeBroadcastSourceInfo) {
- BluetoothLeBroadcastSourceInfo other = (BluetoothLeBroadcastSourceInfo) o;
- return (other.mSourceId == mSourceId
- && other.mSourceAddressType == mSourceAddressType
- && other.mSourceDevice == mSourceDevice
- && other.mSourceAdvSid == mSourceAdvSid
- && other.mBroadcastId == mBroadcastId
- && other.mPaSyncState == mPaSyncState
- && other.mEncryptionStatus == mEncryptionStatus
- && other.mAudioSyncState == mAudioSyncState
- && Arrays.equals(other.mBadBroadcastCode, mBadBroadcastCode)
- && other.mNumSubGroups == mNumSubGroups
- && mSubgroupBisSyncState.equals(other.mSubgroupBisSyncState)
- && mSubgroupMetadata.equals(other.mSubgroupMetadata)
- && other.mBroadcastCode == mBroadcastCode);
- }
- return false;
- }
-
- /**
- * Checks if an instance of {@link BluetoothLeBroadcastSourceInfo} is empty.
- *
- * @hide
- */
- public boolean isEmpty() {
- boolean ret = false;
- if (mSourceAddressType == LE_AUDIO_BROADCAST_SOURCE_ADDRESS_TYPE_INVALID
- && mSourceDevice == null
- && mSourceAdvSid == (byte) 0
- && mPaSyncState == LE_AUDIO_BROADCAST_SINK_PA_SYNC_STATE_INVALID
- && mEncryptionStatus == LE_AUDIO_BROADCAST_SINK_ENC_STATE_INVALID
- && mAudioSyncState == LE_AUDIO_BROADCAST_SINK_AUDIO_SYNC_STATE_INVALID
- && mBadBroadcastCode == null
- && mNumSubGroups == 0
- && mSubgroupBisSyncState.size() == 0
- && mSubgroupMetadata.size() == 0
- && mBroadcastCode == null) {
- ret = true;
- }
- return ret;
- }
-
- /**
- * Compares an instance of {@link BluetoothLeBroadcastSourceInfo} with the provided instance.
- *
- * @hide
- */
- public boolean matches(BluetoothLeBroadcastSourceInfo srcInfo) {
- boolean ret = false;
- if (srcInfo == null) {
- ret = false;
- } else {
- if (mSourceDevice == null) {
- if (mSourceAdvSid == srcInfo.getAdvertisingSid()
- && mSourceAddressType == srcInfo.getAdvAddressType()) {
- ret = true;
- }
- } else {
- if (mSourceDevice.equals(srcInfo.getSourceDevice())
- && mSourceAdvSid == srcInfo.getAdvertisingSid()
- && mSourceAddressType == srcInfo.getAdvAddressType()
- && mBroadcastId == srcInfo.getBroadcastId()) {
- ret = true;
- }
- }
- }
- return ret;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(
- mSourceId,
- mSourceAddressType,
- mSourceDevice,
- mSourceAdvSid,
- mBroadcastId,
- mPaSyncState,
- mEncryptionStatus,
- mAudioSyncState,
- mBadBroadcastCode,
- mNumSubGroups,
- mSubgroupBisSyncState,
- mSubgroupMetadata,
- mBroadcastCode);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public String toString() {
- return "{BluetoothLeBroadcastSourceInfo : mSourceId"
- + mSourceId
- + " addressType: "
- + mSourceAddressType
- + " sourceDevice: "
- + mSourceDevice
- + " mSourceAdvSid:"
- + mSourceAdvSid
- + " mBroadcastId:"
- + mBroadcastId
- + " mPaSyncState:"
- + mPaSyncState
- + " mEncryptionStatus:"
- + mEncryptionStatus
- + " mAudioSyncState:"
- + mAudioSyncState
- + " mBadBroadcastCode:"
- + mBadBroadcastCode
- + " mNumSubGroups:"
- + mNumSubGroups
- + " mSubgroupBisSyncState:"
- + mSubgroupBisSyncState
- + " mSubgroupMetadata:"
- + mSubgroupMetadata
- + " mBroadcastCode:"
- + mBroadcastCode
- + "}";
- }
-
- /**
- * Get the Source Id
- *
- * @return byte representing the Source Id, {@link
- * #LE_AUDIO_BROADCAST_ASSISTANT_INVALID_SOURCE_ID} if invalid
- * @hide
- */
- public byte getSourceId() {
- return mSourceId;
- }
-
- /**
- * Set the Source Id
- *
- * @param sourceId source Id
- * @hide
- */
- public void setSourceId(byte sourceId) {
- mSourceId = sourceId;
- }
-
- /**
- * Set the Broadcast Source device
- *
- * @param sourceDevice the Broadcast Source BluetoothDevice
- * @hide
- */
- public void setSourceDevice(@NonNull BluetoothDevice sourceDevice) {
- mSourceDevice = sourceDevice;
- }
-
- /**
- * Get the Broadcast Source BluetoothDevice
- *
- * @return Broadcast Source BluetoothDevice
- * @hide
- */
- public @NonNull BluetoothDevice getSourceDevice() {
- return mSourceDevice;
- }
-
- /**
- * Set the address type of the Broadcast Source advertisements
- *
- * @hide
- */
- public void setAdvAddressType(@LeAudioBroadcastSourceAddressType int addressType) {
- mSourceAddressType = addressType;
- }
-
- /**
- * Get the address type used by advertisements from the Broadcast Source.
- * BluetoothLeBroadcastSourceInfo Object
- *
- * @hide
- */
- @LeAudioBroadcastSourceAddressType
- public int getAdvAddressType() {
- return mSourceAddressType;
- }
-
- /**
- * Set the advertising SID of the Broadcast Source advertisement.
- *
- * @param advSid advertising SID of the Broadcast Source
- * @hide
- */
- public void setAdvertisingSid(byte advSid) {
- mSourceAdvSid = advSid;
- }
-
- /**
- * Get the advertising SID of the Broadcast Source advertisement.
- *
- * @return advertising SID of the Broadcast Source
- * @hide
- */
- public byte getAdvertisingSid() {
- return mSourceAdvSid;
- }
-
- /**
- * Get the Broadcast ID of the Broadcast Source.
- *
- * @return broadcast ID
- * @hide
- */
- public int getBroadcastId() {
- return mBroadcastId;
- }
-
- /**
- * Set the Periodic Advertising (PA) Sync State.
- *
- * @hide
- */
- /*package*/ void setPaSyncState(@LeAudioBroadcastSinkPaSyncState int paSyncState) {
- mPaSyncState = paSyncState;
- }
-
- /**
- * Get the Periodic Advertising (PA) Sync State
- *
- * @hide
- */
- public @LeAudioBroadcastSinkPaSyncState int getMetadataSyncState() {
- return mPaSyncState;
- }
-
- /**
- * Set the audio sync state
- *
- * @hide
- */
- /*package*/ void setAudioSyncState(@LeAudioBroadcastSinkAudioSyncState int audioSyncState) {
- mAudioSyncState = audioSyncState;
- }
-
- /**
- * Get the audio sync state
- *
- * @hide
- */
- public @LeAudioBroadcastSinkAudioSyncState int getAudioSyncState() {
- return mAudioSyncState;
- }
-
- /**
- * Set the encryption status
- *
- * @hide
- */
- /*package*/ void setEncryptionStatus(
- @LeAudioBroadcastSinkEncryptionState int encryptionStatus) {
- mEncryptionStatus = encryptionStatus;
- }
-
- /**
- * Get the encryption status
- *
- * @hide
- */
- public @LeAudioBroadcastSinkEncryptionState int getEncryptionStatus() {
- return mEncryptionStatus;
- }
-
- /**
- * Get the incorrect broadcast code that the Scan delegator used to decrypt the Broadcast Audio
- * Stream and failed.
- *
- * <p>This code is valid only if {@link #getEncryptionStatus} returns {@link
- * #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE}
- *
- * @return byte array containing bad broadcast value, null if the current encryption status is
- * not {@link #LE_AUDIO_BROADCAST_SINK_ENC_STATE_BAD_CODE}
- * @hide
- */
- public @Nullable byte[] getBadBroadcastCode() {
- return mBadBroadcastCode;
- }
-
- /**
- * Get the number of subgroups.
- *
- * @return number of subgroups
- * @hide
- */
- public byte getNumberOfSubGroups() {
- return mNumSubGroups;
- }
-
- public @NonNull Map<Integer, Integer> getSubgroupBisSyncState() {
- return mSubgroupBisSyncState;
- }
-
- public void setSubgroupBisSyncState(@NonNull Map<Integer, Integer> bisSyncState) {
- mSubgroupBisSyncState = new HashMap<Integer, Integer>(bisSyncState);
- }
-
- /*package*/ void setBroadcastCode(@NonNull String broadcastCode) {
- mBroadcastCode = broadcastCode;
- }
-
- /**
- * Get the broadcast code
- *
- * @return
- * @hide
- */
- public @NonNull String getBroadcastCode() {
- return mBroadcastCode;
- }
-
- /**
- * Set the broadcast ID
- *
- * @param broadcastId broadcast ID of the Broadcast Source
- * @hide
- */
- public void setBroadcastId(int broadcastId) {
- mBroadcastId = broadcastId;
- }
-
- private void writeSubgroupBisSyncStateToParcel(
- @NonNull Parcel dest, @NonNull Map<Integer, Integer> subgroupBisSyncState) {
- dest.writeInt(subgroupBisSyncState.size());
- for (Map.Entry<Integer, Integer> entry : subgroupBisSyncState.entrySet()) {
- dest.writeInt(entry.getKey());
- dest.writeInt(entry.getValue());
- }
- }
-
- private static void readSubgroupBisSyncStateFromParcel(
- @NonNull Parcel in, @NonNull Map<Integer, Integer> subgroupBisSyncState) {
- int size = in.readInt();
-
- for (int i = 0; i < size; i++) {
- Integer key = in.readInt();
- Integer value = in.readInt();
- subgroupBisSyncState.put(key, value);
- }
- }
-
- private void writeSubgroupMetadataToParcel(
- @NonNull Parcel dest, @Nullable Map<Integer, byte[]> subgroupMetadata) {
- if (subgroupMetadata == null) {
- dest.writeInt(0);
- return;
- }
-
- dest.writeInt(subgroupMetadata.size());
- for (Map.Entry<Integer, byte[]> entry : subgroupMetadata.entrySet()) {
- dest.writeInt(entry.getKey());
- byte[] metadata = entry.getValue();
- if (metadata != null) {
- dest.writeInt(metadata.length);
- dest.writeByteArray(metadata);
- }
- }
- }
-
- private static void readSubgroupMetadataFromParcel(
- @NonNull Parcel in, @NonNull Map<Integer, byte[]> subgroupMetadata) {
- int size = in.readInt();
-
- for (int i = 0; i < size; i++) {
- Integer key = in.readInt();
- Integer metaDataLen = in.readInt();
- byte[] metadata = null;
- if (metaDataLen != 0) {
- metadata = new byte[metaDataLen];
- in.readByteArray(metadata);
- }
- subgroupMetadata.put(key, metadata);
- }
- }
-
- public static final @NonNull Parcelable.Creator<BluetoothLeBroadcastSourceInfo> CREATOR =
- new Parcelable.Creator<BluetoothLeBroadcastSourceInfo>() {
- public @NonNull BluetoothLeBroadcastSourceInfo createFromParcel(
- @NonNull Parcel in) {
- final byte sourceId = in.readByte();
- final int sourceAddressType = in.readInt();
- final BluetoothDevice sourceDevice =
- in.readTypedObject(BluetoothDevice.CREATOR);
- final byte sourceAdvSid = in.readByte();
- final int broadcastId = in.readInt();
- final int paSyncState = in.readInt();
- final int audioSyncState = in.readInt();
- final int encryptionStatus = in.readInt();
- final int badBroadcastLen = in.readInt();
- byte[] badBroadcastCode = null;
-
- if (badBroadcastLen > 0) {
- badBroadcastCode = new byte[badBroadcastLen];
- in.readByteArray(badBroadcastCode);
- }
- final byte numSubGroups = in.readByte();
- final String broadcastCode = in.readString();
- Map<Integer, Integer> subgroupBisSyncState = new HashMap<Integer, Integer>();
- readSubgroupBisSyncStateFromParcel(in, subgroupBisSyncState);
- Map<Integer, byte[]> subgroupMetadata = new HashMap<Integer, byte[]>();
- readSubgroupMetadataFromParcel(in, subgroupMetadata);
-
- BluetoothLeBroadcastSourceInfo srcInfo =
- new BluetoothLeBroadcastSourceInfo(
- sourceId,
- sourceAddressType,
- sourceDevice,
- sourceAdvSid,
- broadcastId,
- paSyncState,
- encryptionStatus,
- audioSyncState,
- badBroadcastCode,
- numSubGroups,
- subgroupBisSyncState,
- subgroupMetadata,
- broadcastCode);
- return srcInfo;
- }
-
- public @NonNull BluetoothLeBroadcastSourceInfo[] newArray(int size) {
- return new BluetoothLeBroadcastSourceInfo[size];
- }
- };
-
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeByte(mSourceId);
- out.writeInt(mSourceAddressType);
- out.writeTypedObject(mSourceDevice, 0);
- out.writeByte(mSourceAdvSid);
- out.writeInt(mBroadcastId);
- out.writeInt(mPaSyncState);
- out.writeInt(mAudioSyncState);
- out.writeInt(mEncryptionStatus);
-
- if (mBadBroadcastCode != null) {
- out.writeInt(mBadBroadcastCode.length);
- out.writeByteArray(mBadBroadcastCode);
- } else {
- // zero indicates that there is no "bad broadcast code"
- out.writeInt(0);
- }
- out.writeByte(mNumSubGroups);
- out.writeString(mBroadcastCode);
- writeSubgroupBisSyncStateToParcel(out, mSubgroupBisSyncState);
- writeSubgroupMetadataToParcel(out, mSubgroupMetadata);
- }
-
- private static void log(@NonNull String msg) {
- if (DBG) {
- Log.d(TAG, msg);
- }
- }
-}
-;
diff --git a/core/java/android/bluetooth/BluetoothLeCall.java b/core/java/android/bluetooth/BluetoothLeCall.java
deleted file mode 100644
index fb7789d..0000000
--- a/core/java/android/bluetooth/BluetoothLeCall.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * Copyright 2021 HIMSA II K/S - www.himsa.com.
- * Represented by EHIMA - www.ehima.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.ParcelUuid;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-import java.util.UUID;
-
-/**
- * Representation of Call
- *
- * @hide
- */
-public final class BluetoothLeCall implements Parcelable {
-
- /** @hide */
- @IntDef(prefix = "STATE_", value = {
- STATE_INCOMING,
- STATE_DIALING,
- STATE_ALERTING,
- STATE_ACTIVE,
- STATE_LOCALLY_HELD,
- STATE_REMOTELY_HELD,
- STATE_LOCALLY_AND_REMOTELY_HELD
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface State {
- }
-
- /**
- * A remote party is calling (incoming call).
- *
- * @hide
- */
- public static final int STATE_INCOMING = 0x00;
-
- /**
- * The process to call the remote party has started but the remote party is not
- * being alerted (outgoing call).
- *
- * @hide
- */
- public static final int STATE_DIALING = 0x01;
-
- /**
- * A remote party is being alerted (outgoing call).
- *
- * @hide
- */
- public static final int STATE_ALERTING = 0x02;
-
- /**
- * The call is in an active conversation.
- *
- * @hide
- */
- public static final int STATE_ACTIVE = 0x03;
-
- /**
- * The call is connected but held locally. “Locally Held” implies that either
- * the server or the client can affect the state.
- *
- * @hide
- */
- public static final int STATE_LOCALLY_HELD = 0x04;
-
- /**
- * The call is connected but held remotely. “Remotely Held” means that the state
- * is controlled by the remote party of a call.
- *
- * @hide
- */
- public static final int STATE_REMOTELY_HELD = 0x05;
-
- /**
- * The call is connected but held both locally and remotely.
- *
- * @hide
- */
- public static final int STATE_LOCALLY_AND_REMOTELY_HELD = 0x06;
-
- /**
- * Whether the call direction is outgoing.
- *
- * @hide
- */
- public static final int FLAG_OUTGOING_CALL = 0x00000001;
-
- /**
- * Whether the call URI and Friendly Name are withheld by server.
- *
- * @hide
- */
- public static final int FLAG_WITHHELD_BY_SERVER = 0x00000002;
-
- /**
- * Whether the call URI and Friendly Name are withheld by network.
- *
- * @hide
- */
- public static final int FLAG_WITHHELD_BY_NETWORK = 0x00000004;
-
- /** Unique UUID that identifies this call */
- private UUID mUuid;
-
- /** Remote Caller URI */
- private String mUri;
-
- /** Caller friendly name */
- private String mFriendlyName;
-
- /** Call state */
- private @State int mState;
-
- /** Call flags */
- private int mCallFlags;
-
- /** @hide */
- public BluetoothLeCall(@NonNull BluetoothLeCall that) {
- mUuid = new UUID(that.getUuid().getMostSignificantBits(),
- that.getUuid().getLeastSignificantBits());
- mUri = that.mUri;
- mFriendlyName = that.mFriendlyName;
- mState = that.mState;
- mCallFlags = that.mCallFlags;
- }
-
- /** @hide */
- public BluetoothLeCall(@NonNull UUID uuid, @NonNull String uri, @NonNull String friendlyName,
- @State int state, int callFlags) {
- mUuid = uuid;
- mUri = uri;
- mFriendlyName = friendlyName;
- mState = state;
- mCallFlags = callFlags;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
- BluetoothLeCall that = (BluetoothLeCall) o;
- return mUuid.equals(that.mUuid) && mUri.equals(that.mUri)
- && mFriendlyName.equals(that.mFriendlyName) && mState == that.mState
- && mCallFlags == that.mCallFlags;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mUuid, mUri, mFriendlyName, mState, mCallFlags);
- }
-
- /**
- * Returns a string representation of this BluetoothLeCall.
- *
- * <p>
- * Currently this is the UUID.
- *
- * @return string representation of this BluetoothLeCall
- */
- @Override
- public String toString() {
- return mUuid.toString();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeParcelable(new ParcelUuid(mUuid), 0);
- out.writeString(mUri);
- out.writeString(mFriendlyName);
- out.writeInt(mState);
- out.writeInt(mCallFlags);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothLeCall> CREATOR =
- new Parcelable.Creator<BluetoothLeCall>() {
- public BluetoothLeCall createFromParcel(Parcel in) {
- return new BluetoothLeCall(in);
- }
-
- public BluetoothLeCall[] newArray(int size) {
- return new BluetoothLeCall[size];
- }
- };
-
- private BluetoothLeCall(Parcel in) {
- mUuid = ((ParcelUuid) in.readParcelable(null)).getUuid();
- mUri = in.readString();
- mFriendlyName = in.readString();
- mState = in.readInt();
- mCallFlags = in.readInt();
- }
-
- /**
- * Returns an UUID of this BluetoothLeCall.
- *
- * <p>
- * An UUID is unique identifier of a BluetoothLeCall.
- *
- * @return UUID of this BluetoothLeCall
- * @hide
- */
- public @NonNull UUID getUuid() {
- return mUuid;
- }
-
- /**
- * Returns a URI of the remote party of this BluetoothLeCall.
- *
- * @return string representation of this BluetoothLeCall
- * @hide
- */
- public @NonNull String getUri() {
- return mUri;
- }
-
- /**
- * Returns a friendly name of the call.
- *
- * @return friendly name representation of this BluetoothLeCall
- * @hide
- */
- public @NonNull String getFriendlyName() {
- return mFriendlyName;
- }
-
- /**
- * Returns the call state.
- *
- * @return the state of this BluetoothLeCall
- * @hide
- */
- public @State int getState() {
- return mState;
- }
-
- /**
- * Returns the call flags.
- *
- * @return call flags
- * @hide
- */
- public int getCallFlags() {
- return mCallFlags;
- }
-
- /**
- * Whether the call direction is incoming.
- *
- * @return true if incoming call, false otherwise
- * @hide
- */
- public boolean isIncomingCall() {
- return (mCallFlags & FLAG_OUTGOING_CALL) == 0;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothLeCallControl.java b/core/java/android/bluetooth/BluetoothLeCallControl.java
deleted file mode 100644
index fb080c9..0000000
--- a/core/java/android/bluetooth/BluetoothLeCallControl.java
+++ /dev/null
@@ -1,899 +0,0 @@
-/*
- * Copyright 2019 HIMSA II K/S - www.himsa.com.
- * Represented by EHIMA - www.ehima.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.Manifest;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.content.ComponentName;
-import android.content.Context;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.ParcelUuid;
-import android.os.RemoteException;
-import android.util.Log;
-import android.annotation.SuppressLint;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.Executor;
-
-/**
- * This class provides the APIs to control the Call Control profile.
- *
- * <p>
- * This class provides Bluetooth Telephone Bearer Service functionality,
- * allowing applications to expose a GATT Service based interface to control the
- * state of the calls by remote devices such as LE audio devices.
- *
- * <p>
- * BluetoothLeCallControl is a proxy object for controlling the Bluetooth Telephone Bearer
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get the
- * BluetoothLeCallControl proxy object.
- *
- * @hide
- */
-public final class BluetoothLeCallControl implements BluetoothProfile {
- private static final String TAG = "BluetoothLeCallControl";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /** @hide */
- @IntDef(prefix = "RESULT_", value = {
- RESULT_SUCCESS,
- RESULT_ERROR_UNKNOWN_CALL_ID,
- RESULT_ERROR_INVALID_URI,
- RESULT_ERROR_APPLICATION
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Result {
- }
-
- /**
- * Opcode write was successful.
- *
- * @hide
- */
- public static final int RESULT_SUCCESS = 0;
-
- /**
- * Unknown call Id has been used in the operation.
- *
- * @hide
- */
- public static final int RESULT_ERROR_UNKNOWN_CALL_ID = 1;
-
- /**
- * The URI provided in {@link Callback#onPlaceCallRequest} is invalid.
- *
- * @hide
- */
- public static final int RESULT_ERROR_INVALID_URI = 2;
-
- /**
- * Application internal error.
- *
- * @hide
- */
- public static final int RESULT_ERROR_APPLICATION = 3;
-
- /** @hide */
- @IntDef(prefix = "TERMINATION_REASON_", value = {
- TERMINATION_REASON_INVALID_URI,
- TERMINATION_REASON_FAIL,
- TERMINATION_REASON_REMOTE_HANGUP,
- TERMINATION_REASON_SERVER_HANGUP,
- TERMINATION_REASON_LINE_BUSY,
- TERMINATION_REASON_NETWORK_CONGESTION,
- TERMINATION_REASON_CLIENT_HANGUP,
- TERMINATION_REASON_NO_SERVICE,
- TERMINATION_REASON_NO_ANSWER
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TerminationReason {
- }
-
- /**
- * Remote Caller ID value used to place a call was formed improperly.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_INVALID_URI = 0x00;
-
- /**
- * Call fail.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_FAIL = 0x01;
-
- /**
- * Remote party ended call.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_REMOTE_HANGUP = 0x02;
-
- /**
- * Call ended from the server.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_SERVER_HANGUP = 0x03;
-
- /**
- * Line busy.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_LINE_BUSY = 0x04;
-
- /**
- * Network congestion.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_NETWORK_CONGESTION = 0x05;
-
- /**
- * Client terminated.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_CLIENT_HANGUP = 0x06;
-
- /**
- * No service.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_NO_SERVICE = 0x07;
-
- /**
- * No answer.
- *
- * @hide
- */
- public static final int TERMINATION_REASON_NO_ANSWER = 0x08;
-
- /*
- * Flag indicating support for hold/unhold call feature.
- *
- * @hide
- */
- public static final int CAPABILITY_HOLD_CALL = 0x00000001;
-
- /**
- * Flag indicating support for joining calls feature.
- *
- * @hide
- */
- public static final int CAPABILITY_JOIN_CALLS = 0x00000002;
-
- private static final int MESSAGE_TBS_SERVICE_CONNECTED = 102;
- private static final int MESSAGE_TBS_SERVICE_DISCONNECTED = 103;
-
- private static final int REG_TIMEOUT = 10000;
-
- /**
- * The template class is used to call callback functions on events from the TBS
- * server. Callback functions are wrapped in this class and registered to the
- * Android system during app registration.
- *
- * @hide
- */
- public abstract static class Callback {
-
- private static final String TAG = "BluetoothLeCallControl.Callback";
-
- /**
- * Called when a remote client requested to accept the call.
- *
- * <p>
- * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
- * request.
- *
- * @param requestId The Id of the request
- * @param callId The call Id requested to be accepted
- * @hide
- */
- public abstract void onAcceptCall(int requestId, @NonNull UUID callId);
-
- /**
- * A remote client has requested to terminate the call.
- *
- * <p>
- * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
- * request.
- *
- * @param requestId The Id of the request
- * @param callId The call Id requested to terminate
- * @hide
- */
- public abstract void onTerminateCall(int requestId, @NonNull UUID callId);
-
- /**
- * A remote client has requested to hold the call.
- *
- * <p>
- * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
- * request.
- *
- * @param requestId The Id of the request
- * @param callId The call Id requested to be put on hold
- * @hide
- */
- public void onHoldCall(int requestId, @NonNull UUID callId) {
- Log.e(TAG, "onHoldCall: unimplemented, however CAPABILITY_HOLD_CALL is set!");
- }
-
- /**
- * A remote client has requested to unhold the call.
- *
- * <p>
- * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
- * request.
- *
- * @param requestId The Id of the request
- * @param callId The call Id requested to unhold
- * @hide
- */
- public void onUnholdCall(int requestId, @NonNull UUID callId) {
- Log.e(TAG, "onUnholdCall: unimplemented, however CAPABILITY_HOLD_CALL is set!");
- }
-
- /**
- * A remote client has requested to place a call.
- *
- * <p>
- * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
- * request.
- *
- * @param requestId The Id of the request
- * @param callId The Id to be assigned for the new call
- * @param uri The caller URI requested
- * @hide
- */
- public abstract void onPlaceCall(int requestId, @NonNull UUID callId, @NonNull String uri);
-
- /**
- * A remote client has requested to join the calls.
- *
- * <p>
- * An application must call {@link BluetoothLeCallControl#requestResult} to complete the
- * request.
- *
- * @param requestId The Id of the request
- * @param callIds The call Id list requested to join
- * @hide
- */
- public void onJoinCalls(int requestId, @NonNull List<UUID> callIds) {
- Log.e(TAG, "onJoinCalls: unimplemented, however CAPABILITY_JOIN_CALLS is set!");
- }
- }
-
- private class CallbackWrapper extends IBluetoothLeCallControlCallback.Stub {
-
- private final Executor mExecutor;
- private final Callback mCallback;
-
- CallbackWrapper(Executor executor, Callback callback) {
- mExecutor = executor;
- mCallback = callback;
- }
-
- @Override
- public void onBearerRegistered(int ccid) {
- if (mCallback != null) {
- mCcid = ccid;
- } else {
- // registration timeout
- Log.e(TAG, "onBearerRegistered: mCallback is null");
- }
- }
-
- @Override
- public void onAcceptCall(int requestId, ParcelUuid uuid) {
- final long identityToken = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onAcceptCall(requestId, uuid.getUuid()));
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
-
- @Override
- public void onTerminateCall(int requestId, ParcelUuid uuid) {
- final long identityToken = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onTerminateCall(requestId, uuid.getUuid()));
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
-
- @Override
- public void onHoldCall(int requestId, ParcelUuid uuid) {
- final long identityToken = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onHoldCall(requestId, uuid.getUuid()));
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
-
- @Override
- public void onUnholdCall(int requestId, ParcelUuid uuid) {
- final long identityToken = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onUnholdCall(requestId, uuid.getUuid()));
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
-
- @Override
- public void onPlaceCall(int requestId, ParcelUuid uuid, String uri) {
- final long identityToken = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onPlaceCall(requestId, uuid.getUuid(), uri));
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
-
- @Override
- public void onJoinCalls(int requestId, List<ParcelUuid> parcelUuids) {
- List<UUID> uuids = new ArrayList<>();
- for (ParcelUuid parcelUuid : parcelUuids) {
- uuids.add(parcelUuid.getUuid());
- }
-
- final long identityToken = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(() -> mCallback.onJoinCalls(requestId, uuids));
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- }
- };
-
- private Context mContext;
- private ServiceListener mServiceListener;
- private volatile IBluetoothLeCallControl mService;
- private BluetoothAdapter mAdapter;
- private int mCcid = 0;
- private String mToken;
- private Callback mCallback = null;
-
- private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
- new IBluetoothStateChangeCallback.Stub() {
- public void onBluetoothStateChange(boolean up) {
- if (DBG)
- Log.d(TAG, "onBluetoothStateChange: up=" + up);
- if (!up) {
- doUnbind();
- } else {
- doBind();
- }
- }
- };
-
- /**
- * Create a BluetoothLeCallControl proxy object for interacting with the local Bluetooth
- * telephone bearer service.
- */
- /* package */ BluetoothLeCallControl(Context context, ServiceListener listener) {
- mContext = context;
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- mServiceListener = listener;
-
- IBluetoothManager mgr = mAdapter.getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
-
- doBind();
- }
-
- private boolean doBind() {
- synchronized (mConnection) {
- if (mService == null) {
- if (VDBG)
- Log.d(TAG, "Binding service...");
- try {
- return mAdapter.getBluetoothManager().
- bindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL,
- mConnection);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to bind TelephoneBearerService", e);
- }
- }
- }
- return false;
- }
-
- private void doUnbind() {
- synchronized (mConnection) {
- if (mService != null) {
- if (VDBG)
- Log.d(TAG, "Unbinding service...");
- try {
- mAdapter.getBluetoothManager().
- unbindBluetoothProfileService(BluetoothProfile.LE_CALL_CONTROL,
- mConnection);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to unbind TelephoneBearerService", e);
- } finally {
- mService = null;
- }
- }
- }
- }
-
- /* package */ void close() {
- if (VDBG)
- log("close()");
- unregisterBearer();
-
- IBluetoothManager mgr = mAdapter.getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException re) {
- Log.e(TAG, "", re);
- }
- }
- mServiceListener = null;
- doUnbind();
- }
-
- private IBluetoothLeCallControl getService() {
- return mService;
- }
-
- /**
- * Not supported
- *
- * @throws UnsupportedOperationException
- */
- @Override
- public int getConnectionState(@Nullable BluetoothDevice device) {
- throw new UnsupportedOperationException("not supported");
- }
-
- /**
- * Not supported
- *
- * @throws UnsupportedOperationException
- */
- @Override
- public @NonNull List<BluetoothDevice> getConnectedDevices() {
- throw new UnsupportedOperationException("not supported");
- }
-
- /**
- * Not supported
- *
- * @throws UnsupportedOperationException
- */
- @Override
- public @NonNull List<BluetoothDevice> getDevicesMatchingConnectionStates(
- @NonNull int[] states) {
- throw new UnsupportedOperationException("not supported");
- }
-
- /**
- * Register Telephone Bearer exposing the interface that allows remote devices
- * to track and control the call states.
- *
- * <p>
- * This is an asynchronous call. The callback is used to notify success or
- * failure if the function returns true.
- *
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
- * <!-- The UCI is a String identifier of the telephone bearer as defined at
- * https://www.bluetooth.com/specifications/assigned-numbers/uniform-caller-identifiers
- * (login required). -->
- *
- * <!-- The examples of common URI schemes can be found in
- * https://iana.org/assignments/uri-schemes/uri-schemes.xhtml -->
- *
- * <!-- The Technology is an integer value. The possible values are defined at
- * https://www.bluetooth.com/specifications/assigned-numbers (login required).
- * -->
- *
- * @param uci Bearer Unique Client Identifier
- * @param uriSchemes URI Schemes supported list
- * @param capabilities bearer capabilities
- * @param provider Network provider name
- * @param technology Network technology
- * @param executor {@link Executor} object on which callback will be
- * executed. The Executor object is required.
- * @param callback {@link Callback} object to which callback messages will
- * be sent. The Callback object is required.
- * @return true on success, false otherwise
- * @hide
- */
- @SuppressLint("ExecutorRegistration")
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean registerBearer(@Nullable String uci,
- @NonNull List<String> uriSchemes, int capabilities,
- @NonNull String provider, int technology,
- @NonNull Executor executor, @NonNull Callback callback) {
- if (DBG) {
- Log.d(TAG, "registerBearer");
- }
- if (callback == null) {
- throw new IllegalArgumentException("null parameter: " + callback);
- }
- if (mCcid != 0) {
- return false;
- }
-
- mToken = uci;
-
- final IBluetoothLeCallControl service = getService();
- if (service != null) {
- if (mCallback != null) {
- Log.e(TAG, "Bearer can be opened only once");
- return false;
- }
-
- mCallback = callback;
- try {
- CallbackWrapper callbackWrapper = new CallbackWrapper(executor, callback);
- service.registerBearer(mToken, callbackWrapper, uci, uriSchemes, capabilities,
- provider, technology);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- mCallback = null;
- return false;
- }
-
- if (mCcid == 0) {
- mCallback = null;
- return false;
- }
-
- return true;
- }
-
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- }
-
- return false;
- }
-
- /**
- * Unregister Telephone Bearer Service and destroy all the associated data.
- *
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void unregisterBearer() {
- if (DBG) {
- Log.d(TAG, "unregisterBearer");
- }
- if (mCcid == 0) {
- return;
- }
-
- int ccid = mCcid;
- mCcid = 0;
- mCallback = null;
-
- final IBluetoothLeCallControl service = getService();
- if (service != null) {
- try {
- service.unregisterBearer(mToken);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- }
- }
-
- /**
- * Get the Content Control ID (CCID) value.
- *
- * @return ccid Content Control ID value
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public int getContentControlId() {
- return mCcid;
- }
-
- /**
- * Notify about the newly added call.
- *
- * <p>
- * This shall be called as early as possible after the call has been added.
- *
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
- * @param call Newly added call
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void onCallAdded(@NonNull BluetoothLeCall call) {
- if (DBG) {
- Log.d(TAG, "onCallAdded: call=" + call);
- }
- if (mCcid == 0) {
- return;
- }
-
- final IBluetoothLeCallControl service = getService();
- if (service != null) {
- try {
- service.callAdded(mCcid, call);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- }
- }
-
- /**
- * Notify about the removed call.
- *
- * <p>
- * This shall be called as early as possible after the call has been removed.
- *
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
- * @param callId The Id of a call that has been removed
- * @param reason Call termination reason
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void onCallRemoved(@NonNull UUID callId, @TerminationReason int reason) {
- if (DBG) {
- Log.d(TAG, "callRemoved: callId=" + callId);
- }
- if (mCcid == 0) {
- return;
- }
-
- final IBluetoothLeCallControl service = getService();
- if (service != null) {
- try {
- service.callRemoved(mCcid, new ParcelUuid(callId), reason);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- }
- }
-
- /**
- * Notify the call state change
- *
- * <p>
- * This shall be called as early as possible after the state of the call has
- * changed.
- *
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
- * @param callId The call Id that state has been changed
- * @param state Call state
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void onCallStateChanged(@NonNull UUID callId, @BluetoothLeCall.State int state) {
- if (DBG) {
- Log.d(TAG, "callStateChanged: callId=" + callId + " state=" + state);
- }
- if (mCcid == 0) {
- return;
- }
-
- final IBluetoothLeCallControl service = getService();
- if (service != null) {
- try {
- service.callStateChanged(mCcid, new ParcelUuid(callId), state);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- }
- }
-
- /**
- * Provide the current calls list
- *
- * <p>
- * This function must be invoked after registration if application has any
- * calls.
- *
- * @param calls current calls list
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void currentCallsList(@NonNull List<BluetoothLeCall> calls) {
- final IBluetoothLeCallControl service = getService();
- if (service != null) {
- try {
- service.currentCallsList(mCcid, calls);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- }
-
- /**
- * Provide the network current status
- *
- * <p>
- * This function must be invoked on change of network state.
- *
- * <p>
- * Requires {@link android.Manifest.permission#BLUETOOTH} permission.
- *
- * <!-- The Technology is an integer value. The possible values are defined at
- * https://www.bluetooth.com/specifications/assigned-numbers (login required).
- * -->
- *
- * @param provider Network provider name
- * @param technology Network technology
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void networkStateChanged(@NonNull String provider, int technology) {
- if (DBG) {
- Log.d(TAG, "networkStateChanged: provider=" + provider + ", technology=" + technology);
- }
- if (mCcid == 0) {
- return;
- }
-
- final IBluetoothLeCallControl service = getService();
- if (service != null) {
- try {
- service.networkStateChanged(mCcid, provider, technology);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- }
- }
-
- /**
- * Send a response to a call control request to a remote device.
- *
- * <p>
- * This function must be invoked in when a request is received by one of these
- * callback methods:
- *
- * <ul>
- * <li>{@link Callback#onAcceptCall}
- * <li>{@link Callback#onTerminateCall}
- * <li>{@link Callback#onHoldCall}
- * <li>{@link Callback#onUnholdCall}
- * <li>{@link Callback#onPlaceCall}
- * <li>{@link Callback#onJoinCalls}
- * </ul>
- *
- * @param requestId The ID of the request that was received with the callback
- * @param result The result of the request to be sent to the remote devices
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void requestResult(int requestId, @Result int result) {
- if (DBG) {
- Log.d(TAG, "requestResult: requestId=" + requestId + " result=" + result);
- }
- if (mCcid == 0) {
- return;
- }
-
- final IBluetoothLeCallControl service = getService();
- if (service != null) {
- try {
- service.requestResult(mCcid, requestId, result);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
- }
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- private static boolean isValidDevice(@Nullable BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-
- private final IBluetoothProfileServiceConnection mConnection =
- new IBluetoothProfileServiceConnection.Stub() {
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- if (DBG) {
- Log.d(TAG, "Proxy object connected");
- }
- mService = IBluetoothLeCallControl.Stub.asInterface(Binder.allowBlocking(service));
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_CONNECTED));
- }
-
- @Override
- public void onServiceDisconnected(ComponentName className) {
- if (DBG) {
- Log.d(TAG, "Proxy object disconnected");
- }
- doUnbind();
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_TBS_SERVICE_DISCONNECTED));
- }
- };
-
- private final Handler mHandler = new Handler(Looper.getMainLooper()) {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_TBS_SERVICE_CONNECTED: {
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.LE_CALL_CONTROL,
- BluetoothLeCallControl.this);
- }
- break;
- }
- case MESSAGE_TBS_SERVICE_DISCONNECTED: {
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.LE_CALL_CONTROL);
- }
- break;
- }
- }
- }
- };
-}
diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java
deleted file mode 100644
index fef6f22..0000000
--- a/core/java/android/bluetooth/BluetoothManager.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.RequiresFeature;
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemService;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * High level manager used to obtain an instance of an {@link BluetoothAdapter}
- * and to conduct overall Bluetooth Management.
- * <p>
- * Use {@link android.content.Context#getSystemService(java.lang.String)}
- * with {@link Context#BLUETOOTH_SERVICE} to create an {@link BluetoothManager},
- * then call {@link #getAdapter} to obtain the {@link BluetoothAdapter}.
- * </p>
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>
- * For more information about using BLUETOOTH, read the <a href=
- * "{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer
- * guide.
- * </p>
- * </div>
- *
- * @see Context#getSystemService
- * @see BluetoothAdapter#getDefaultAdapter()
- */
-@SystemService(Context.BLUETOOTH_SERVICE)
-@RequiresFeature(PackageManager.FEATURE_BLUETOOTH)
-public final class BluetoothManager {
- private static final String TAG = "BluetoothManager";
- private static final boolean DBG = false;
-
- private final AttributionSource mAttributionSource;
- private final BluetoothAdapter mAdapter;
-
- /**
- * @hide
- */
- public BluetoothManager(Context context) {
- mAttributionSource = (context != null) ? context.getAttributionSource() :
- AttributionSource.myAttributionSource();
- mAdapter = BluetoothAdapter.createAdapter(mAttributionSource);
- }
-
- /**
- * Get the BLUETOOTH Adapter for this device.
- *
- * @return the BLUETOOTH Adapter
- */
- @RequiresNoPermission
- public BluetoothAdapter getAdapter() {
- return mAdapter;
- }
-
- /**
- * Get the current connection state of the profile to the remote device.
- *
- * <p>This is not specific to any application configuration but represents
- * the connection state of the local Bluetooth adapter for certain profile.
- * This can be used by applications like status bar which would just like
- * to know the state of Bluetooth.
- *
- * @param device Remote bluetooth device.
- * @param profile GATT or GATT_SERVER
- * @return State of the profile connection. One of {@link BluetoothProfile#STATE_CONNECTED},
- * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED},
- * {@link BluetoothProfile#STATE_DISCONNECTING}
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device, int profile) {
- if (DBG) Log.d(TAG, "getConnectionState()");
-
- List<BluetoothDevice> connectedDevices = getConnectedDevices(profile);
- for (BluetoothDevice connectedDevice : connectedDevices) {
- if (device.equals(connectedDevice)) {
- return BluetoothProfile.STATE_CONNECTED;
- }
- }
-
- return BluetoothProfile.STATE_DISCONNECTED;
- }
-
- /**
- * Get connected devices for the specified profile.
- *
- * <p> Return the set of devices which are in state {@link BluetoothProfile#STATE_CONNECTED}
- *
- * <p>This is not specific to any application configuration but represents
- * the connection state of Bluetooth for this profile.
- * This can be used by applications like status bar which would just like
- * to know the state of Bluetooth.
- *
- * @param profile GATT or GATT_SERVER
- * @return List of devices. The list will be empty on error.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices(int profile) {
- if (DBG) Log.d(TAG, "getConnectedDevices");
- return getDevicesMatchingConnectionStates(profile, new int[] {
- BluetoothProfile.STATE_CONNECTED
- });
- }
-
- /**
- * Get a list of devices that match any of the given connection
- * states.
- *
- * <p> If none of the devices match any of the given states,
- * an empty list will be returned.
- *
- * <p>This is not specific to any application configuration but represents
- * the connection state of the local Bluetooth adapter for this profile.
- * This can be used by applications like status bar which would just like
- * to know the state of the local adapter.
- *
- * @param profile GATT or GATT_SERVER
- * @param states Array of states. States can be one of {@link BluetoothProfile#STATE_CONNECTED},
- * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_DISCONNECTED},
- * {@link BluetoothProfile#STATE_DISCONNECTING},
- * @return List of devices. The list will be empty on error.
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int profile, int[] states) {
- if (DBG) Log.d(TAG, "getDevicesMatchingConnectionStates");
-
- if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
- throw new IllegalArgumentException("Profile not supported: " + profile);
- }
-
- List<BluetoothDevice> devices = new ArrayList<BluetoothDevice>();
-
- try {
- IBluetoothManager managerService = mAdapter.getBluetoothManager();
- IBluetoothGatt iGatt = managerService.getBluetoothGatt();
- if (iGatt == null) return devices;
- devices = Attributable.setAttributionSource(
- iGatt.getDevicesMatchingConnectionStates(states, mAttributionSource),
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- }
-
- return devices;
- }
-
- /**
- * Open a GATT Server
- * The callback is used to deliver results to Caller, such as connection status as well
- * as the results of any other GATT server operations.
- * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
- * to conduct GATT server operations.
- *
- * @param context App context
- * @param callback GATT server callback handler that will receive asynchronous callbacks.
- * @return BluetoothGattServer instance
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGattServer openGattServer(Context context,
- BluetoothGattServerCallback callback) {
-
- return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO));
- }
-
- /**
- * Open a GATT Server
- * The callback is used to deliver results to Caller, such as connection status as well
- * as the results of any other GATT server operations.
- * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
- * to conduct GATT server operations.
- *
- * @param context App context
- * @param callback GATT server callback handler that will receive asynchronous callbacks.
- * @param eatt_support idicates if server should use eatt channel for notifications.
- * @return BluetoothGattServer instance
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGattServer openGattServer(Context context,
- BluetoothGattServerCallback callback, boolean eatt_support) {
- return (openGattServer(context, callback, BluetoothDevice.TRANSPORT_AUTO, eatt_support));
- }
-
- /**
- * Open a GATT Server
- * The callback is used to deliver results to Caller, such as connection status as well
- * as the results of any other GATT server operations.
- * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
- * to conduct GATT server operations.
- *
- * @param context App context
- * @param callback GATT server callback handler that will receive asynchronous callbacks.
- * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
- * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
- * BluetoothDevice#TRANSPORT_LE}
- * @return BluetoothGattServer instance
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGattServer openGattServer(Context context,
- BluetoothGattServerCallback callback, int transport) {
- return (openGattServer(context, callback, transport, false));
- }
-
- /**
- * Open a GATT Server
- * The callback is used to deliver results to Caller, such as connection status as well
- * as the results of any other GATT server operations.
- * The method returns a BluetoothGattServer instance. You can use BluetoothGattServer
- * to conduct GATT server operations.
- *
- * @param context App context
- * @param callback GATT server callback handler that will receive asynchronous callbacks.
- * @param transport preferred transport for GATT connections to remote dual-mode devices {@link
- * BluetoothDevice#TRANSPORT_AUTO} or {@link BluetoothDevice#TRANSPORT_BREDR} or {@link
- * BluetoothDevice#TRANSPORT_LE}
- * @param eatt_support idicates if server should use eatt channel for notifications.
- * @return BluetoothGattServer instance
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothGattServer openGattServer(Context context,
- BluetoothGattServerCallback callback, int transport, boolean eatt_support) {
- if (context == null || callback == null) {
- throw new IllegalArgumentException("null parameter: " + context + " " + callback);
- }
-
- // TODO(Bluetooth) check whether platform support BLE
- // Do the check here or in GattServer?
-
- try {
- IBluetoothManager managerService = mAdapter.getBluetoothManager();
- IBluetoothGatt iGatt = managerService.getBluetoothGatt();
- if (iGatt == null) {
- Log.e(TAG, "Fail to get GATT Server connection");
- return null;
- }
- BluetoothGattServer mGattServer =
- new BluetoothGattServer(iGatt, transport, mAdapter);
- Boolean regStatus = mGattServer.registerCallback(callback, eatt_support);
- return regStatus ? mGattServer : null;
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- return null;
- }
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothMap.java b/core/java/android/bluetooth/BluetoothMap.java
deleted file mode 100644
index 56e4972..0000000
--- a/core/java/android/bluetooth/BluetoothMap.java
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.CloseGuard;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the APIs to control the Bluetooth MAP
- * Profile.
- *
- * @hide
- */
-@SystemApi
-public final class BluetoothMap implements BluetoothProfile, AutoCloseable {
-
- private static final String TAG = "BluetoothMap";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- private CloseGuard mCloseGuard;
-
- /** @hide */
- @SuppressLint("ActionValue")
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.map.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * There was an error trying to obtain the state
- *
- * @hide
- */
- public static final int STATE_ERROR = -1;
-
- /** @hide */
- public static final int RESULT_FAILURE = 0;
- /** @hide */
- public static final int RESULT_SUCCESS = 1;
- /**
- * Connection canceled before completion.
- *
- * @hide
- */
- public static final int RESULT_CANCELED = 2;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothMap> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.MAP,
- "BluetoothMap", IBluetoothMap.class.getName()) {
- @Override
- public IBluetoothMap getServiceInterface(IBinder service) {
- return IBluetoothMap.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothMap proxy object.
- */
- /* package */ BluetoothMap(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- if (DBG) Log.d(TAG, "Create BluetoothMap proxy object");
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- mCloseGuard = new CloseGuard();
- mCloseGuard.open("close");
- }
-
- protected void finalize() {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- close();
- }
-
- /**
- * Close the connection to the backing service.
- * Other public functions of BluetoothMap will return default error
- * results once close() has been called. Multiple invocations of close()
- * are ok.
- *
- * @hide
- */
- @SystemApi
- public void close() {
- if (VDBG) log("close()");
- mProfileConnector.disconnect();
- }
-
- private IBluetoothMap getService() {
- return mProfileConnector.getService();
- }
-
- /**
- * Get the current state of the BluetoothMap service.
- *
- * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not
- * connected to the Map service.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getState() {
- if (VDBG) log("getState()");
- final IBluetoothMap service = getService();
- final int defaultValue = BluetoothMap.STATE_ERROR;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getState(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the currently connected remote Bluetooth device (PCE).
- *
- * @return The remote Bluetooth device, or null if not in connected or connecting state, or if
- * this proxy object is not connected to the Map service.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothDevice getClient() {
- if (VDBG) log("getClient()");
- final IBluetoothMap service = getService();
- final BluetoothDevice defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<BluetoothDevice> recv =
- new SynchronousResultReceiver();
- service.getClient(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns true if the specified Bluetooth device is connected.
- * Returns false if not connected, or if this proxy object is not
- * currently connected to the Map service.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isConnected(BluetoothDevice device) {
- if (VDBG) log("isConnected(" + device + ")");
- final IBluetoothMap service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isConnected(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate connection. Initiation of outgoing connections is not
- * supported for MAP server.
- *
- * @hide
- */
- @RequiresNoPermission
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")" + "not supported for MAPS");
- return false;
- }
-
- /**
- * Initiate disconnect.
- *
- * @param device Remote Bluetooth Device
- * @return false on error, true otherwise
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothMap service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Check class bits for possible Map support.
- * This is a simple heuristic that tries to guess if a device with the
- * given class bits might support Map. It is not accurate for all
- * devices. It tries to err on the side of false positives.
- *
- * @return True if this device might support Map.
- *
- * @hide
- */
- public static boolean doesClassMatchSink(BluetoothClass btClass) {
- // TODO optimize the rule
- switch (btClass.getDeviceClass()) {
- case BluetoothClass.Device.COMPUTER_DESKTOP:
- case BluetoothClass.Device.COMPUTER_LAPTOP:
- case BluetoothClass.Device.COMPUTER_SERVER:
- case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Get the list of connected devices. Currently at most one.
- *
- * @return list of connected devices
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @NonNull List<BluetoothDevice> getConnectedDevices() {
- if (DBG) log("getConnectedDevices()");
- final IBluetoothMap service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the list of devices matching specified states. Currently at most one.
- *
- * @return list of matching devices
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (DBG) log("getDevicesMatchingStates()");
- final IBluetoothMap service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get connection state of device
- *
- * @return device connection state
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (DBG) log("getConnectionState(" + device + ")");
- final IBluetoothMap service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv =
- new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) log("setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothMap service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothMap service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-
- private boolean isEnabled() {
- return mAdapter.isEnabled();
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothMapClient.java b/core/java/android/bluetooth/BluetoothMapClient.java
deleted file mode 100644
index 03536f9a..0000000
--- a/core/java/android/bluetooth/BluetoothMapClient.java
+++ /dev/null
@@ -1,686 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
-import android.app.PendingIntent;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the APIs to control the Bluetooth MAP MCE Profile.
- *
- * @hide
- */
-@SystemApi
-public final class BluetoothMapClient implements BluetoothProfile {
-
- private static final String TAG = "BluetoothMapClient";
- private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
- private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
-
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED";
- /** @hide */
- @RequiresPermission(android.Manifest.permission.RECEIVE_SMS)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_MESSAGE_RECEIVED =
- "android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED";
- /* Actions to be used for pending intents */
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_MESSAGE_SENT_SUCCESSFULLY =
- "android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY";
- /** @hide */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY =
- "android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY";
-
- /**
- * Action to notify read status changed
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_MESSAGE_READ_STATUS_CHANGED =
- "android.bluetooth.mapmce.profile.action.MESSAGE_READ_STATUS_CHANGED";
-
- /**
- * Action to notify deleted status changed
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_MESSAGE_DELETED_STATUS_CHANGED =
- "android.bluetooth.mapmce.profile.action.MESSAGE_DELETED_STATUS_CHANGED";
-
- /**
- * Extras used in ACTION_MESSAGE_RECEIVED intent.
- * NOTE: HANDLE is only valid for a single session with the device.
- */
- /** @hide */
- public static final String EXTRA_MESSAGE_HANDLE =
- "android.bluetooth.mapmce.profile.extra.MESSAGE_HANDLE";
- /** @hide */
- public static final String EXTRA_MESSAGE_TIMESTAMP =
- "android.bluetooth.mapmce.profile.extra.MESSAGE_TIMESTAMP";
- /** @hide */
- public static final String EXTRA_MESSAGE_READ_STATUS =
- "android.bluetooth.mapmce.profile.extra.MESSAGE_READ_STATUS";
- /** @hide */
- public static final String EXTRA_SENDER_CONTACT_URI =
- "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_URI";
- /** @hide */
- public static final String EXTRA_SENDER_CONTACT_NAME =
- "android.bluetooth.mapmce.profile.extra.SENDER_CONTACT_NAME";
-
- /**
- * Used as a boolean extra in ACTION_MESSAGE_DELETED_STATUS_CHANGED
- * Contains the MAP message deleted status
- * Possible values are:
- * true: deleted
- * false: undeleted
- *
- * @hide
- */
- public static final String EXTRA_MESSAGE_DELETED_STATUS =
- "android.bluetooth.mapmce.profile.extra.MESSAGE_DELETED_STATUS";
-
- /**
- * Extra used in ACTION_MESSAGE_READ_STATUS_CHANGED or ACTION_MESSAGE_DELETED_STATUS_CHANGED
- * Possible values are:
- * 0: failure
- * 1: success
- *
- * @hide
- */
- public static final String EXTRA_RESULT_CODE =
- "android.bluetooth.device.extra.RESULT_CODE";
-
- /**
- * There was an error trying to obtain the state
- * @hide
- */
- public static final int STATE_ERROR = -1;
-
- /** @hide */
- public static final int RESULT_FAILURE = 0;
- /** @hide */
- public static final int RESULT_SUCCESS = 1;
- /**
- * Connection canceled before completion.
- * @hide
- */
- public static final int RESULT_CANCELED = 2;
- /** @hide */
- private static final int UPLOADING_FEATURE_BITMASK = 0x08;
-
- /*
- * UNREAD, READ, UNDELETED, DELETED are passed as parameters
- * to setMessageStatus to indicate the messages new state.
- */
-
- /** @hide */
- public static final int UNREAD = 0;
- /** @hide */
- public static final int READ = 1;
- /** @hide */
- public static final int UNDELETED = 2;
- /** @hide */
- public static final int DELETED = 3;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothMapClient> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.MAP_CLIENT,
- "BluetoothMapClient", IBluetoothMapClient.class.getName()) {
- @Override
- public IBluetoothMapClient getServiceInterface(IBinder service) {
- return IBluetoothMapClient.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothMapClient proxy object.
- */
- /* package */ BluetoothMapClient(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- if (DBG) Log.d(TAG, "Create BluetoothMapClient proxy object");
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- /**
- * Close the connection to the backing service.
- * Other public functions of BluetoothMap will return default error
- * results once close() has been called. Multiple invocations of close()
- * are ok.
- * @hide
- */
- public void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothMapClient getService() {
- return mProfileConnector.getService();
- }
-
- /**
- * Returns true if the specified Bluetooth device is connected.
- * Returns false if not connected, or if this proxy object is not
- * currently connected to the Map service.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isConnected(BluetoothDevice device) {
- if (VDBG) Log.d(TAG, "isConnected(" + device + ")");
- final IBluetoothMapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isConnected(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate connection. Initiation of outgoing connections is not
- * supported for MAP server.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean connect(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE");
- final IBluetoothMapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnect.
- *
- * @param device Remote Bluetooth Device
- * @return false on error, true otherwise
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "disconnect(" + device + ")");
- final IBluetoothMapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the list of connected devices. Currently at most one.
- *
- * @return list of connected devices
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- if (DBG) Log.d(TAG, "getConnectedDevices()");
- final IBluetoothMapClient service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the list of devices matching specified states. Currently at most one.
- *
- * @return list of matching devices
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (DBG) Log.d(TAG, "getDevicesMatchingStates()");
- final IBluetoothMapClient service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get connection state of device
- *
- * @return device connection state
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "getConnectionState(" + device + ")");
- final IBluetoothMapClient service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver<>();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) Log.d(TAG, "setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothMapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public int getPriority(BluetoothDevice device) {
- if (VDBG) Log.d(TAG, "getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) Log.d(TAG, "getConnectionPolicy(" + device + ")");
- final IBluetoothMapClient service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Send a message.
- *
- * Send an SMS message to either the contacts primary number or the telephone number specified.
- *
- * @param device Bluetooth device
- * @param contacts Uri Collection of the contacts
- * @param message Message to be sent
- * @param sentIntent intent issued when message is sent
- * @param deliveredIntent intent issued when message is delivered
- * @return true if the message is enqueued, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.SEND_SMS,
- })
- public boolean sendMessage(@NonNull BluetoothDevice device, @NonNull Collection<Uri> contacts,
- @NonNull String message, @Nullable PendingIntent sentIntent,
- @Nullable PendingIntent deliveredIntent) {
- return sendMessage(device, contacts.toArray(new Uri[contacts.size()]), message, sentIntent,
- deliveredIntent);
- }
-
- /**
- * Send a message.
- *
- * Send an SMS message to either the contacts primary number or the telephone number specified.
- *
- * @param device Bluetooth device
- * @param contacts Uri[] of the contacts
- * @param message Message to be sent
- * @param sentIntent intent issued when message is sent
- * @param deliveredIntent intent issued when message is delivered
- * @return true if the message is enqueued, false on error
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.SEND_SMS,
- })
- public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
- PendingIntent sentIntent, PendingIntent deliveredIntent) {
- if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message);
- final IBluetoothMapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.sendMessage(device, contacts, message, sentIntent, deliveredIntent,
- mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get unread messages. Unread messages will be published via {@link #ACTION_MESSAGE_RECEIVED}.
- *
- * @param device Bluetooth device
- * @return true if the message is enqueued, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.READ_SMS,
- })
- public boolean getUnreadMessages(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")");
- final IBluetoothMapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.getUnreadMessages(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns the "Uploading" feature bit value from the SDP record's
- * MapSupportedFeatures field (see Bluetooth MAP 1.4 spec, page 114).
- * @param device The Bluetooth device to get this value for.
- * @return Returns true if the Uploading bit value in SDP record's
- * MapSupportedFeatures field is set. False is returned otherwise.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isUploadingSupported(BluetoothDevice device) {
- if (DBG) Log.d(TAG, "isUploadingSupported(" + device + ")");
- final IBluetoothMapClient service = getService();
- final int defaultValue = 0;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getSupportedFeatures(device, mAttributionSource, recv);
- return (recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue)
- & UPLOADING_FEATURE_BITMASK) > 0;
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return false;
- }
-
- /**
- * Set message status of message on MSE
- * <p>
- * When read status changed, the result will be published via
- * {@link #ACTION_MESSAGE_READ_STATUS_CHANGED}
- * When deleted status changed, the result will be published via
- * {@link #ACTION_MESSAGE_DELETED_STATUS_CHANGED}
- *
- * @param device Bluetooth device
- * @param handle message handle
- * @param status <code>UNREAD</code> for "unread", <code>READ</code> for
- * "read", <code>UNDELETED</code> for "undeleted", <code>DELETED</code> for
- * "deleted", otherwise return error
- * @return <code>true</code> if request has been sent, <code>false</code> on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.READ_SMS,
- })
- public boolean setMessageStatus(BluetoothDevice device, String handle, int status) {
- if (DBG) Log.d(TAG, "setMessageStatus(" + device + ", " + handle + ", " + status + ")");
- final IBluetoothMapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device) && handle != null && (status == READ
- || status == UNREAD || status == UNDELETED || status == DELETED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setMessageStatus(device, handle, status, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private boolean isEnabled() {
- return mAdapter.isEnabled();
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothMasInstance.java b/core/java/android/bluetooth/BluetoothMasInstance.java
deleted file mode 100644
index eeaf085..0000000
--- a/core/java/android/bluetooth/BluetoothMasInstance.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public final class BluetoothMasInstance implements Parcelable {
- private final int mId;
- private final String mName;
- private final int mChannel;
- private final int mMsgTypes;
-
- public BluetoothMasInstance(int id, String name, int channel, int msgTypes) {
- mId = id;
- mName = name;
- mChannel = channel;
- mMsgTypes = msgTypes;
- }
-
- @Override
- public boolean equals(@Nullable Object o) {
- if (o instanceof BluetoothMasInstance) {
- return mId == ((BluetoothMasInstance) o).mId;
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- return mId + (mChannel << 8) + (mMsgTypes << 16);
- }
-
- @Override
- public String toString() {
- return Integer.toString(mId) + ":" + mName + ":" + mChannel + ":"
- + Integer.toHexString(mMsgTypes);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<BluetoothMasInstance> CREATOR =
- new Parcelable.Creator<BluetoothMasInstance>() {
- public BluetoothMasInstance createFromParcel(Parcel in) {
- return new BluetoothMasInstance(in.readInt(), in.readString(),
- in.readInt(), in.readInt());
- }
-
- public BluetoothMasInstance[] newArray(int size) {
- return new BluetoothMasInstance[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mId);
- out.writeString(mName);
- out.writeInt(mChannel);
- out.writeInt(mMsgTypes);
- }
-
- public static final class MessageType {
- public static final int EMAIL = 0x01;
- public static final int SMS_GSM = 0x02;
- public static final int SMS_CDMA = 0x04;
- public static final int MMS = 0x08;
- }
-
- public int getId() {
- return mId;
- }
-
- public String getName() {
- return mName;
- }
-
- public int getChannel() {
- return mChannel;
- }
-
- public int getMsgTypes() {
- return mMsgTypes;
- }
-
- public boolean msgSupported(int msg) {
- return (mMsgTypes & msg) != 0;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothOutputStream.java b/core/java/android/bluetooth/BluetoothOutputStream.java
deleted file mode 100644
index ac2b3ed..0000000
--- a/core/java/android/bluetooth/BluetoothOutputStream.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.SuppressLint;
-
-import java.io.IOException;
-import java.io.OutputStream;
-
-/**
- * BluetoothOutputStream.
- *
- * Used to read from a Bluetooth socket.
- *
- * @hide
- */
-@SuppressLint("AndroidFrameworkBluetoothPermission")
-/*package*/ final class BluetoothOutputStream extends OutputStream {
- private BluetoothSocket mSocket;
-
- /*package*/ BluetoothOutputStream(BluetoothSocket s) {
- mSocket = s;
- }
-
- /**
- * Close this output stream and the socket associated with it.
- */
- public void close() throws IOException {
- mSocket.close();
- }
-
- /**
- * Writes a single byte to this stream. Only the least significant byte of
- * the integer {@code oneByte} is written to the stream.
- *
- * @param oneByte the byte to be written.
- * @throws IOException if an error occurs while writing to this stream.
- * @since Android 1.0
- */
- public void write(int oneByte) throws IOException {
- byte[] b = new byte[1];
- b[0] = (byte) oneByte;
- mSocket.write(b, 0, 1);
- }
-
- /**
- * Writes {@code count} bytes from the byte array {@code buffer} starting
- * at position {@code offset} to this stream.
- *
- * @param b the buffer to be written.
- * @param offset the start position in {@code buffer} from where to get bytes.
- * @param count the number of bytes from {@code buffer} to write to this stream.
- * @throws IOException if an error occurs while writing to this stream.
- * @throws IndexOutOfBoundsException if {@code offset < 0} or {@code count < 0}, or if {@code
- * offset + count} is bigger than the length of {@code buffer}.
- * @since Android 1.0
- */
- public void write(byte[] b, int offset, int count) throws IOException {
- if (b == null) {
- throw new NullPointerException("buffer is null");
- }
- if ((offset | count) < 0 || count > b.length - offset) {
- throw new IndexOutOfBoundsException("invalid offset or length");
- }
- mSocket.write(b, offset, count);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothPan.java b/core/java/android/bluetooth/BluetoothPan.java
deleted file mode 100644
index d4ad4ef4..0000000
--- a/core/java/android/bluetooth/BluetoothPan.java
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the APIs to control the Bluetooth Pan
- * Profile.
- *
- * <p>BluetoothPan is a proxy object for controlling the Bluetooth
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothPan proxy object.
- *
- * <p>Each method is protected with its appropriate permission.
- *
- * @hide
- */
-@SystemApi
-public final class BluetoothPan implements BluetoothProfile {
- private static final String TAG = "BluetoothPan";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the Pan
- * profile.
- *
- * <p>This intent will have 4 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * <li> {@link #EXTRA_LOCAL_ROLE} - Which local role the remote device is
- * bound to. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * <p> {@link #EXTRA_LOCAL_ROLE} can be one of {@link #LOCAL_NAP_ROLE} or
- * {@link #LOCAL_PANU_ROLE}
- */
- @SuppressLint("ActionValue")
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.pan.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * Extra for {@link #ACTION_CONNECTION_STATE_CHANGED} intent
- * The local role of the PAN profile that the remote device is bound to.
- * It can be one of {@link #LOCAL_NAP_ROLE} or {@link #LOCAL_PANU_ROLE}.
- */
- @SuppressLint("ActionValue")
- public static final String EXTRA_LOCAL_ROLE = "android.bluetooth.pan.extra.LOCAL_ROLE";
-
- /**
- * Intent used to broadcast the change in tethering state of the Pan
- * Profile
- *
- * <p>This intent will have 1 extra:
- * <ul>
- * <li> {@link #EXTRA_TETHERING_STATE} - The current state of Bluetooth
- * tethering. </li>
- * </ul>
- *
- * <p> {@link #EXTRA_TETHERING_STATE} can be any of {@link #TETHERING_STATE_OFF} or
- * {@link #TETHERING_STATE_ON}
- */
- @RequiresLegacyBluetoothPermission
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_TETHERING_STATE_CHANGED =
- "android.bluetooth.action.TETHERING_STATE_CHANGED";
-
- /**
- * Extra for {@link #ACTION_TETHERING_STATE_CHANGED} intent
- * The tethering state of the PAN profile.
- * It can be one of {@link #TETHERING_STATE_OFF} or {@link #TETHERING_STATE_ON}.
- */
- public static final String EXTRA_TETHERING_STATE =
- "android.bluetooth.extra.TETHERING_STATE";
-
- /** @hide */
- @IntDef({PAN_ROLE_NONE, LOCAL_NAP_ROLE, LOCAL_PANU_ROLE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface LocalPanRole {}
-
- public static final int PAN_ROLE_NONE = 0;
- /**
- * The local device is acting as a Network Access Point.
- */
- public static final int LOCAL_NAP_ROLE = 1;
-
- /**
- * The local device is acting as a PAN User.
- */
- public static final int LOCAL_PANU_ROLE = 2;
-
- /** @hide */
- @IntDef({PAN_ROLE_NONE, REMOTE_NAP_ROLE, REMOTE_PANU_ROLE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface RemotePanRole {}
-
- public static final int REMOTE_NAP_ROLE = 1;
-
- public static final int REMOTE_PANU_ROLE = 2;
-
- /** @hide **/
- @IntDef({TETHERING_STATE_OFF, TETHERING_STATE_ON})
- @Retention(RetentionPolicy.SOURCE)
- public @interface TetheringState{}
-
- public static final int TETHERING_STATE_OFF = 1;
-
- public static final int TETHERING_STATE_ON = 2;
- /**
- * Return codes for the connect and disconnect Bluez / Dbus calls.
- *
- * @hide
- */
- public static final int PAN_DISCONNECT_FAILED_NOT_CONNECTED = 1000;
-
- /**
- * @hide
- */
- public static final int PAN_CONNECT_FAILED_ALREADY_CONNECTED = 1001;
-
- /**
- * @hide
- */
- public static final int PAN_CONNECT_FAILED_ATTEMPT_FAILED = 1002;
-
- /**
- * @hide
- */
- public static final int PAN_OPERATION_GENERIC_FAILURE = 1003;
-
- /**
- * @hide
- */
- public static final int PAN_OPERATION_SUCCESS = 1004;
-
- private final Context mContext;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothPan> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.PAN,
- "BluetoothPan", IBluetoothPan.class.getName()) {
- @Override
- public IBluetoothPan getServiceInterface(IBinder service) {
- return IBluetoothPan.Stub.asInterface(service);
- }
- };
-
-
- /**
- * Create a BluetoothPan proxy object for interacting with the local
- * Bluetooth Service which handles the Pan profile
- *
- * @hide
- */
- @UnsupportedAppUsage
- /* package */ BluetoothPan(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mContext = context;
- mProfileConnector.connect(context, listener);
- }
-
- /**
- * Closes the connection to the service and unregisters callbacks
- */
- @UnsupportedAppUsage
- void close() {
- if (VDBG) log("close()");
- mProfileConnector.disconnect();
- }
-
- private IBluetoothPan getService() {
- return mProfileConnector.getService();
- }
-
- /** @hide */
- protected void finalize() {
- close();
- }
-
- /**
- * Initiate connection to a profile of the remote bluetooth device.
- *
- * <p> This API returns false in scenarios like the profile on the
- * device is already connected or Bluetooth is not turned on.
- * When this API returns true, it is guaranteed that
- * connection state intent for the profile will be broadcasted with
- * the state. Users can get the connection state of the profile
- * from this intent.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")");
- final IBluetoothPan service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnection from a profile
- *
- * <p> This API will return false in scenarios like the profile on the
- * Bluetooth device is not in connected state etc. When this API returns,
- * true, it is guaranteed that the connection state change
- * intent will be broadcasted with the state. Users can get the
- * disconnection state of the profile from this intent.
- *
- * <p> If the disconnection is initiated by a remote device, the state
- * will transition from {@link #STATE_CONNECTED} to
- * {@link #STATE_DISCONNECTED}. If the disconnect is initiated by the
- * host (local) device the state will transition from
- * {@link #STATE_CONNECTED} to state {@link #STATE_DISCONNECTING} to
- * state {@link #STATE_DISCONNECTED}. The transition to
- * {@link #STATE_DISCONNECTING} can be used to distinguish between the
- * two scenarios.
- *
- * @param device Remote Bluetooth Device
- * @return false on immediate error, true otherwise
- * @hide
- */
- @UnsupportedAppUsage
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothPan service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothPan service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- * @hide
- */
- @SystemApi
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @NonNull List<BluetoothDevice> getConnectedDevices() {
- if (VDBG) log("getConnectedDevices()");
- final IBluetoothPan service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- * @hide
- */
- @Override
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (VDBG) log("getDevicesMatchingStates()");
- final IBluetoothPan service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * {@inheritDoc}
- * @hide
- */
- @SystemApi
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public int getConnectionState(@NonNull BluetoothDevice device) {
- if (VDBG) log("getState(" + device + ")");
- final IBluetoothPan service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Turns on/off bluetooth tethering
- *
- * @param value is whether to enable or disable bluetooth tethering
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- android.Manifest.permission.TETHER_PRIVILEGED,
- })
- public void setBluetoothTethering(boolean value) {
- String pkgName = mContext.getOpPackageName();
- if (DBG) log("setBluetoothTethering(" + value + "), calling package:" + pkgName);
- final IBluetoothPan service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.setBluetoothTethering(value, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Determines whether tethering is enabled
- *
- * @return true if tethering is on, false if not or some error occurred
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isTetheringOn() {
- if (VDBG) log("isTetheringOn()");
- final IBluetoothPan service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isTetheringOn(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- @UnsupportedAppUsage
- private boolean isEnabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_ON;
- }
-
- @UnsupportedAppUsage
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- @UnsupportedAppUsage
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
deleted file mode 100644
index de2db9c..0000000
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ /dev/null
@@ -1,317 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-/**
- * Public API for controlling the Bluetooth Pbap Service. This includes
- * Bluetooth Phone book Access profile.
- * BluetoothPbap is a proxy object for controlling the Bluetooth Pbap
- * Service via IPC.
- *
- * Creating a BluetoothPbap object will create a binding with the
- * BluetoothPbap service. Users of this object should call close() when they
- * are finished with the BluetoothPbap, so that this proxy object can unbind
- * from the service.
- *
- * This BluetoothPbap object is not immediately bound to the
- * BluetoothPbap service. Use the ServiceListener interface to obtain a
- * notification when it is bound, this is especially important if you wish to
- * immediately call methods on BluetoothPbap after construction.
- *
- * To get an instance of the BluetoothPbap class, you can call
- * {@link BluetoothAdapter#getProfileProxy(Context, ServiceListener, int)} with the final param
- * being {@link BluetoothProfile#PBAP}. The ServiceListener should be able to get the instance of
- * BluetoothPbap in {@link android.bluetooth.BluetoothProfile.ServiceListener#onServiceConnected}.
- *
- * Android only supports one connected Bluetooth Pce at a time.
- *
- * @hide
- */
-@SystemApi
-public class BluetoothPbap implements BluetoothProfile {
-
- private static final String TAG = "BluetoothPbap";
- private static final boolean DBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the PBAP
- * profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link BluetoothProfile#EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link BluetoothProfile#EXTRA_PREVIOUS_STATE}- The previous state of the profile. </li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- * <p>{@link BluetoothProfile#EXTRA_STATE} or {@link BluetoothProfile#EXTRA_PREVIOUS_STATE}
- * can be any of {@link BluetoothProfile#STATE_DISCONNECTED},
- * {@link BluetoothProfile#STATE_CONNECTING}, {@link BluetoothProfile#STATE_CONNECTED},
- * {@link BluetoothProfile#STATE_DISCONNECTING}.
- *
- * @hide
- */
- @SuppressLint("ActionValue")
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.pbap.profile.action.CONNECTION_STATE_CHANGED";
-
- private final AttributionSource mAttributionSource;
-
- /** @hide */
- public static final int RESULT_FAILURE = 0;
- /** @hide */
- public static final int RESULT_SUCCESS = 1;
- /**
- * Connection canceled before completion.
- *
- * @hide
- */
- public static final int RESULT_CANCELED = 2;
-
- private BluetoothAdapter mAdapter;
- private final BluetoothProfileConnector<IBluetoothPbap> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.PBAP, "BluetoothPbap",
- IBluetoothPbap.class.getName()) {
- @Override
- public IBluetoothPbap getServiceInterface(IBinder service) {
- return IBluetoothPbap.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothPbap proxy object.
- *
- * @hide
- */
- public BluetoothPbap(Context context, ServiceListener listener, BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- /** @hide */
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
- /**
- * Close the connection to the backing service.
- * Other public functions of BluetoothPbap will return default error
- * results once close() has been called. Multiple invocations of close()
- * are ok.
- *
- * @hide
- */
- public synchronized void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothPbap getService() {
- return (IBluetoothPbap) mProfileConnector.getService();
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- log("getConnectedDevices()");
- final IBluetoothPbap service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- return new ArrayList<BluetoothDevice>();
- }
- try {
- return Attributable.setAttributionSource(
- service.getConnectedDevices(mAttributionSource), mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- return new ArrayList<BluetoothDevice>();
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @SystemApi
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @BtProfileState int getConnectionState(@NonNull BluetoothDevice device) {
- log("getConnectionState: device=" + device);
- try {
- final IBluetoothPbap service = getService();
- if (service != null && isEnabled() && isValidDevice(device)) {
- return service.getConnectionState(device, mAttributionSource);
- }
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- }
- return BluetoothProfile.STATE_DISCONNECTED;
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- return BluetoothProfile.STATE_DISCONNECTED;
- }
-
- /**
- * {@inheritDoc}
- *
- * @hide
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- log("getDevicesMatchingConnectionStates: states=" + Arrays.toString(states));
- final IBluetoothPbap service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- return new ArrayList<BluetoothDevice>();
- }
- try {
- return Attributable.setAttributionSource(
- service.getDevicesMatchingConnectionStates(states, mAttributionSource),
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- return new ArrayList<BluetoothDevice>();
- }
-
- /**
- * Set connection policy of the profile and tries to disconnect it if connectionPolicy is
- * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN}
- *
- * <p> The device should already be paired.
- * Connection policy can be one of:
- * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED},
- * {@link BluetoothProfile#CONNECTION_POLICY_FORBIDDEN},
- * {@link BluetoothProfile#CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- try {
- final IBluetoothPbap service = getService();
- if (service != null && isEnabled()
- && isValidDevice(device)) {
- if (connectionPolicy != BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- && connectionPolicy != BluetoothProfile.CONNECTION_POLICY_ALLOWED) {
- return false;
- }
- return service.setConnectionPolicy(device, connectionPolicy, mAttributionSource);
- }
- if (service == null) Log.w(TAG, "Proxy not attached to service");
- return false;
- } catch (RemoteException e) {
- Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
- }
- }
-
- /**
- * Disconnects the current Pbap client (PCE). Currently this call blocks,
- * it may soon be made asynchronous. Returns false if this proxy object is
- * not currently connected to the Pbap service.
- *
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(BluetoothDevice device) {
- log("disconnect()");
- final IBluetoothPbap service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- return false;
- }
- try {
- service.disconnect(device, mAttributionSource);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- return false;
- }
-
- private boolean isEnabled() {
- if (mAdapter.getState() == BluetoothAdapter.STATE_ON) return true;
- return false;
- }
-
- private boolean isValidDevice(BluetoothDevice device) {
- if (device == null) return false;
-
- if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
- return false;
- }
-
- private static void log(String msg) {
- if (DBG) {
- Log.d(TAG, msg);
- }
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothPbapClient.java b/core/java/android/bluetooth/BluetoothPbapClient.java
deleted file mode 100644
index e096de8..0000000
--- a/core/java/android/bluetooth/BluetoothPbapClient.java
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the APIs to control the Bluetooth PBAP Client Profile.
- *
- * @hide
- */
-public final class BluetoothPbapClient implements BluetoothProfile {
-
- private static final String TAG = "BluetoothPbapClient";
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
-
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.pbapclient.profile.action.CONNECTION_STATE_CHANGED";
-
- /** There was an error trying to obtain the state */
- public static final int STATE_ERROR = -1;
-
- public static final int RESULT_FAILURE = 0;
- public static final int RESULT_SUCCESS = 1;
- /** Connection canceled before completion. */
- public static final int RESULT_CANCELED = 2;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothPbapClient> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.PBAP_CLIENT,
- "BluetoothPbapClient", IBluetoothPbapClient.class.getName()) {
- @Override
- public IBluetoothPbapClient getServiceInterface(IBinder service) {
- return IBluetoothPbapClient.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothPbapClient proxy object.
- */
- BluetoothPbapClient(Context context, ServiceListener listener, BluetoothAdapter adapter) {
- if (DBG) {
- Log.d(TAG, "Create BluetoothPbapClient proxy object");
- }
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
- /**
- * Close the connection to the backing service.
- * Other public functions of BluetoothPbapClient will return default error
- * results once close() has been called. Multiple invocations of close()
- * are ok.
- */
- public synchronized void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothPbapClient getService() {
- return mProfileConnector.getService();
- }
-
- /**
- * Initiate connection.
- * Upon successful connection to remote PBAP server the Client will
- * attempt to automatically download the users phonebook and call log.
- *
- * @param device a remote device we want connect to
- * @return <code>true</code> if command has been issued successfully; <code>false</code>
- * otherwise;
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean connect(BluetoothDevice device) {
- if (DBG) {
- log("connect(" + device + ") for PBAP Client.");
- }
- final IBluetoothPbapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.connect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate disconnect.
- *
- * @param device Remote Bluetooth Device
- * @return false on error, true otherwise
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) {
- log("disconnect(" + device + ")" + new Exception());
- }
- final IBluetoothPbapClient service = getService();
- final boolean defaultValue = true;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- return true;
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the list of connected devices.
- * Currently at most one.
- *
- * @return list of connected devices
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- if (DBG) {
- log("getConnectedDevices()");
- }
- final IBluetoothPbapClient service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the list of devices matching specified states. Currently at most one.
- *
- * @return list of matching devices
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (DBG) {
- log("getDevicesMatchingStates()");
- }
- final IBluetoothPbapClient service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get connection state of device
- *
- * @return device connection state
- */
- @Override
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (DBG) {
- log("getConnectionState(" + device + ")");
- }
- final IBluetoothPbapClient service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-
- private boolean isEnabled() {
- return mAdapter.isEnabled();
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) log("setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) {
- log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- }
- final IBluetoothPbapClient service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) {
- log("getConnectionPolicy(" + device + ")");
- }
- final IBluetoothPbapClient service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
deleted file mode 100644
index d0f74e9..0000000
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * Copyright (C) 2010-2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.IntDef;
-import android.annotation.RequiresNoPermission;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Build;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-
-/**
- * Public APIs for the Bluetooth Profiles.
- *
- * <p> Clients should call {@link BluetoothAdapter#getProfileProxy},
- * to get the Profile Proxy. Each public profile implements this
- * interface.
- */
-public interface BluetoothProfile {
-
- /**
- * Extra for the connection state intents of the individual profiles.
- *
- * This extra represents the current connection state of the profile of the
- * Bluetooth device.
- */
- @SuppressLint("ActionValue")
- String EXTRA_STATE = "android.bluetooth.profile.extra.STATE";
-
- /**
- * Extra for the connection state intents of the individual profiles.
- *
- * This extra represents the previous connection state of the profile of the
- * Bluetooth device.
- */
- @SuppressLint("ActionValue")
- String EXTRA_PREVIOUS_STATE =
- "android.bluetooth.profile.extra.PREVIOUS_STATE";
-
- /** The profile is in disconnected state */
- int STATE_DISCONNECTED = 0;
- /** The profile is in connecting state */
- int STATE_CONNECTING = 1;
- /** The profile is in connected state */
- int STATE_CONNECTED = 2;
- /** The profile is in disconnecting state */
- int STATE_DISCONNECTING = 3;
-
- /** @hide */
- @IntDef({
- STATE_DISCONNECTED,
- STATE_CONNECTING,
- STATE_CONNECTED,
- STATE_DISCONNECTING,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface BtProfileState {}
-
- /**
- * Headset and Handsfree profile
- */
- int HEADSET = 1;
-
- /**
- * A2DP profile.
- */
- int A2DP = 2;
-
- /**
- * Health Profile
- *
- * @deprecated Health Device Profile (HDP) and MCAP protocol are no longer used. New
- * apps should use Bluetooth Low Energy based solutions such as {@link BluetoothGatt},
- * {@link BluetoothAdapter#listenUsingL2capChannel()}, or
- * {@link BluetoothDevice#createL2capChannel(int)}
- */
- @Deprecated
- int HEALTH = 3;
-
- /**
- * HID Host
- *
- * @hide
- */
- int HID_HOST = 4;
-
- /**
- * PAN Profile
- *
- * @hide
- */
- @SystemApi
- int PAN = 5;
-
- /**
- * PBAP
- *
- * @hide
- */
- int PBAP = 6;
-
- /**
- * GATT
- */
- int GATT = 7;
-
- /**
- * GATT_SERVER
- */
- int GATT_SERVER = 8;
-
- /**
- * MAP Profile
- *
- * @hide
- */
- int MAP = 9;
-
- /*
- * SAP Profile
- * @hide
- */
- int SAP = 10;
-
- /**
- * A2DP Sink Profile
- *
- * @hide
- */
- @SystemApi
- int A2DP_SINK = 11;
-
- /**
- * AVRCP Controller Profile
- *
- * @hide
- */
- @SystemApi
- int AVRCP_CONTROLLER = 12;
-
- /**
- * AVRCP Target Profile
- *
- * @hide
- */
- int AVRCP = 13;
-
- /**
- * Headset Client - HFP HF Role
- *
- * @hide
- */
- @SystemApi
- int HEADSET_CLIENT = 16;
-
- /**
- * PBAP Client
- *
- * @hide
- */
- @SystemApi
- int PBAP_CLIENT = 17;
-
- /**
- * MAP Messaging Client Equipment (MCE)
- *
- * @hide
- */
- @SystemApi
- int MAP_CLIENT = 18;
-
- /**
- * HID Device
- */
- int HID_DEVICE = 19;
-
- /**
- * Object Push Profile (OPP)
- *
- * @hide
- */
- int OPP = 20;
-
- /**
- * Hearing Aid Device
- *
- */
- int HEARING_AID = 21;
-
- /**
- * LE Audio Device
- *
- */
- int LE_AUDIO = 22;
-
- /**
- * Volume Control profile
- *
- * @hide
- */
- @SystemApi
- int VOLUME_CONTROL = 23;
-
- /**
- * @hide
- * Media Control Profile server
- *
- */
- int MCP_SERVER = 24;
-
- /**
- * Coordinated Set Identification Profile set coordinator
- *
- */
- int CSIP_SET_COORDINATOR = 25;
-
- /**
- * LE Audio Broadcast Source
- *
- * @hide
- */
- int LE_AUDIO_BROADCAST = 26;
-
- /**
- * @hide
- * Telephone Bearer Service from Call Control Profile
- *
- */
- int LE_CALL_CONTROL = 27;
-
- /**
- * Max profile ID. This value should be updated whenever a new profile is added to match
- * the largest value assigned to a profile.
- *
- * @hide
- */
- int MAX_PROFILE_ID = 27;
-
- /**
- * Default priority for devices that we try to auto-connect to and
- * and allow incoming connections for the profile
- *
- * @hide
- **/
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- int PRIORITY_AUTO_CONNECT = 1000;
-
- /**
- * Default priority for devices that allow incoming
- * and outgoing connections for the profile
- *
- * @hide
- * @deprecated Replaced with {@link #CONNECTION_POLICY_ALLOWED}
- **/
- @Deprecated
- @SystemApi
- int PRIORITY_ON = 100;
-
- /**
- * Default priority for devices that does not allow incoming
- * connections and outgoing connections for the profile.
- *
- * @hide
- * @deprecated Replaced with {@link #CONNECTION_POLICY_FORBIDDEN}
- **/
- @Deprecated
- @SystemApi
- int PRIORITY_OFF = 0;
-
- /**
- * Default priority when not set or when the device is unpaired
- *
- * @hide
- */
- @UnsupportedAppUsage
- int PRIORITY_UNDEFINED = -1;
-
- /** @hide */
- @IntDef(prefix = "CONNECTION_POLICY_", value = {CONNECTION_POLICY_ALLOWED,
- CONNECTION_POLICY_FORBIDDEN, CONNECTION_POLICY_UNKNOWN})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ConnectionPolicy{}
-
- /**
- * Default connection policy for devices that allow incoming and outgoing connections
- * for the profile
- *
- * @hide
- **/
- @SystemApi
- int CONNECTION_POLICY_ALLOWED = 100;
-
- /**
- * Default connection policy for devices that do not allow incoming or outgoing connections
- * for the profile.
- *
- * @hide
- **/
- @SystemApi
- int CONNECTION_POLICY_FORBIDDEN = 0;
-
- /**
- * Default connection policy when not set or when the device is unpaired
- *
- * @hide
- */
- @SystemApi
- int CONNECTION_POLICY_UNKNOWN = -1;
-
- /**
- * Get connected devices for this specific profile.
- *
- * <p> Return the set of devices which are in state {@link #STATE_CONNECTED}
- *
- * @return List of devices. The list will be empty on error.
- */
- public List<BluetoothDevice> getConnectedDevices();
-
- /**
- * Get a list of devices that match any of the given connection
- * states.
- *
- * <p> If none of the devices match any of the given states,
- * an empty list will be returned.
- *
- * @param states Array of states. States can be one of {@link #STATE_CONNECTED}, {@link
- * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
- * @return List of devices. The list will be empty on error.
- */
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states);
-
- /**
- * Get the current connection state of the profile
- *
- * @param device Remote bluetooth device.
- * @return State of the profile connection. One of {@link #STATE_CONNECTED}, {@link
- * #STATE_CONNECTING}, {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
- */
- @BtProfileState int getConnectionState(BluetoothDevice device);
-
- /**
- * An interface for notifying BluetoothProfile IPC clients when they have
- * been connected or disconnected to the service.
- */
- public interface ServiceListener {
- /**
- * Called to notify the client when the proxy object has been
- * connected to the service.
- *
- * @param profile - One of {@link #HEADSET} or {@link #A2DP}
- * @param proxy - One of {@link BluetoothHeadset} or {@link BluetoothA2dp}
- */
- @RequiresNoPermission
- public void onServiceConnected(int profile, BluetoothProfile proxy);
-
- /**
- * Called to notify the client that this proxy object has been
- * disconnected from the service.
- *
- * @param profile - One of {@link #HEADSET} or {@link #A2DP}
- */
- @RequiresNoPermission
- public void onServiceDisconnected(int profile);
- }
-
- /**
- * Convert an integer value of connection state into human readable string
- *
- * @param connectionState - One of {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, or {@link #STATE_DISCONNECTED}
- * @return a string representation of the connection state, STATE_UNKNOWN if the state
- * is not defined
- * @hide
- */
- static String getConnectionStateName(int connectionState) {
- switch (connectionState) {
- case STATE_DISCONNECTED:
- return "STATE_DISCONNECTED";
- case STATE_CONNECTING:
- return "STATE_CONNECTING";
- case STATE_CONNECTED:
- return "STATE_CONNECTED";
- case STATE_DISCONNECTING:
- return "STATE_DISCONNECTING";
- default:
- return "STATE_UNKNOWN";
- }
- }
-
- /**
- * Convert an integer value of profile ID into human readable string
- *
- * @param profile profile ID
- * @return profile name as String, UNKOWN_PROFILE if the profile ID is not defined.
- * @hide
- */
- static String getProfileName(int profile) {
- switch(profile) {
- case HEADSET:
- return "HEADSET";
- case A2DP:
- return "A2DP";
- case HID_HOST:
- return "HID_HOST";
- case PAN:
- return "PAN";
- case PBAP:
- return "PBAP";
- case GATT:
- return "GATT";
- case GATT_SERVER:
- return "GATT_SERVER";
- case MAP:
- return "MAP";
- case SAP:
- return "SAP";
- case A2DP_SINK:
- return "A2DP_SINK";
- case AVRCP_CONTROLLER:
- return "AVRCP_CONTROLLER";
- case AVRCP:
- return "AVRCP";
- case HEADSET_CLIENT:
- return "HEADSET_CLIENT";
- case PBAP_CLIENT:
- return "PBAP_CLIENT";
- case MAP_CLIENT:
- return "MAP_CLIENT";
- case HID_DEVICE:
- return "HID_DEVICE";
- case OPP:
- return "OPP";
- case HEARING_AID:
- return "HEARING_AID";
- case LE_AUDIO:
- return "LE_AUDIO";
- default:
- return "UNKNOWN_PROFILE";
- }
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothProfileConnector.java b/core/java/android/bluetooth/BluetoothProfileConnector.java
deleted file mode 100644
index a457679..0000000
--- a/core/java/android/bluetooth/BluetoothProfileConnector.java
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.CloseGuard;
-import android.util.Log;
-
-import java.util.List;
-/**
- * Connector for Bluetooth profile proxies to bind manager service and
- * profile services
- * @param <T> The Bluetooth profile interface for this connection.
- * @hide
- */
-@SuppressLint("AndroidFrameworkBluetoothPermission")
-public abstract class BluetoothProfileConnector<T> {
- private final CloseGuard mCloseGuard = new CloseGuard();
- private final int mProfileId;
- private BluetoothProfile.ServiceListener mServiceListener;
- private final BluetoothProfile mProfileProxy;
- private Context mContext;
- private final String mProfileName;
- private final String mServiceName;
- private volatile T mService;
-
- private final IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
- new IBluetoothStateChangeCallback.Stub() {
- public void onBluetoothStateChange(boolean up) {
- if (up) {
- doBind();
- } else {
- doUnbind();
- }
- }
- };
-
- private @Nullable ComponentName resolveSystemService(@NonNull Intent intent,
- @NonNull PackageManager pm) {
- List<ResolveInfo> results = pm.queryIntentServices(intent,
- PackageManager.ResolveInfoFlags.of(0));
- if (results == null) {
- return null;
- }
- ComponentName comp = null;
- for (int i = 0; i < results.size(); i++) {
- ResolveInfo ri = results.get(i);
- if ((ri.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- continue;
- }
- ComponentName foundComp = new ComponentName(ri.serviceInfo.applicationInfo.packageName,
- ri.serviceInfo.name);
- if (comp != null) {
- throw new IllegalStateException("Multiple system services handle " + intent
- + ": " + comp + ", " + foundComp);
- }
- comp = foundComp;
- }
- return comp;
- }
-
- private final ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- logDebug("Proxy object connected");
- mService = getServiceInterface(service);
-
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(mProfileId, mProfileProxy);
- }
- }
-
- public void onServiceDisconnected(ComponentName className) {
- logDebug("Proxy object disconnected");
- doUnbind();
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(mProfileId);
- }
- }
- };
-
- BluetoothProfileConnector(BluetoothProfile profile, int profileId, String profileName,
- String serviceName) {
- mProfileId = profileId;
- mProfileProxy = profile;
- mProfileName = profileName;
- mServiceName = serviceName;
- }
-
- /** {@hide} */
- @Override
- public void finalize() {
- mCloseGuard.warnIfOpen();
- doUnbind();
- }
-
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private boolean doBind() {
- synchronized (mConnection) {
- if (mService == null) {
- logDebug("Binding service...");
- mCloseGuard.open("doUnbind");
- try {
- Intent intent = new Intent(mServiceName);
- ComponentName comp = resolveSystemService(intent, mContext.getPackageManager());
- intent.setComponent(comp);
- if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
- UserHandle.CURRENT)) {
- logError("Could not bind to Bluetooth Service with " + intent);
- return false;
- }
- } catch (SecurityException se) {
- logError("Failed to bind service. " + se);
- return false;
- }
- }
- }
- return true;
- }
-
- private void doUnbind() {
- synchronized (mConnection) {
- if (mService != null) {
- logDebug("Unbinding service...");
- mCloseGuard.close();
- try {
- mContext.unbindService(mConnection);
- } catch (IllegalArgumentException ie) {
- logError("Unable to unbind service: " + ie);
- } finally {
- mService = null;
- }
- }
- }
- }
-
- void connect(Context context, BluetoothProfile.ServiceListener listener) {
- mContext = context;
- mServiceListener = listener;
- IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager();
-
- // Preserve legacy compatibility where apps were depending on
- // registerStateChangeCallback() performing a permissions check which
- // has been relaxed in modern platform versions
- if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.R
- && context.checkSelfPermission(android.Manifest.permission.BLUETOOTH)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Need BLUETOOTH permission");
- }
-
- if (mgr != null) {
- try {
- mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException re) {
- logError("Failed to register state change callback. " + re);
- }
- }
- doBind();
- }
-
- void disconnect() {
- mServiceListener = null;
- IBluetoothManager mgr = BluetoothAdapter.getDefaultAdapter().getBluetoothManager();
- if (mgr != null) {
- try {
- mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
- } catch (RemoteException re) {
- logError("Failed to unregister state change callback" + re);
- }
- }
- doUnbind();
- }
-
- T getService() {
- return mService;
- }
-
- /**
- * This abstract function is used to implement method to get the
- * connected Bluetooth service interface.
- * @param service the connected binder service.
- * @return T the binder interface of {@code service}.
- * @hide
- */
- public abstract T getServiceInterface(IBinder service);
-
- private void logDebug(String log) {
- Log.d(mProfileName, log);
- }
-
- private void logError(String log) {
- Log.e(mProfileName, log);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothSap.java b/core/java/android/bluetooth/BluetoothSap.java
deleted file mode 100644
index 808fa39..0000000
--- a/core/java/android/bluetooth/BluetoothSap.java
+++ /dev/null
@@ -1,491 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the APIs to control the Bluetooth SIM
- * Access Profile (SAP).
- *
- * <p>BluetoothSap is a proxy object for controlling the Bluetooth
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothSap proxy object.
- *
- * <p>Each method is protected with its appropriate permission.
- *
- * @hide
- */
-public final class BluetoothSap implements BluetoothProfile {
-
- private static final String TAG = "BluetoothSap";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Intent used to broadcast the change in connection state of the profile.
- *
- * <p>This intent will have 4 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * @hide
- */
- @RequiresLegacyBluetoothPermission
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.sap.profile.action.CONNECTION_STATE_CHANGED";
-
- /**
- * There was an error trying to obtain the state.
- *
- * @hide
- */
- public static final int STATE_ERROR = -1;
-
- /**
- * Connection state change succceeded.
- *
- * @hide
- */
- public static final int RESULT_SUCCESS = 1;
-
- /**
- * Connection canceled before completion.
- *
- * @hide
- */
- public static final int RESULT_CANCELED = 2;
-
- private final BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothSap> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.SAP,
- "BluetoothSap", IBluetoothSap.class.getName()) {
- @Override
- public IBluetoothSap getServiceInterface(IBinder service) {
- return IBluetoothSap.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothSap proxy object.
- */
- /* package */ BluetoothSap(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- if (DBG) Log.d(TAG, "Create BluetoothSap proxy object");
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- }
-
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
- /**
- * Close the connection to the backing service.
- * Other public functions of BluetoothSap will return default error
- * results once close() has been called. Multiple invocations of close()
- * are ok.
- *
- * @hide
- */
- public synchronized void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothSap getService() {
- return mProfileConnector.getService();
- }
-
- /**
- * Get the current state of the BluetoothSap service.
- *
- * @return One of the STATE_ return codes, or STATE_ERROR if this proxy object is currently not
- * connected to the Sap service.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public int getState() {
- if (VDBG) log("getState()");
- final IBluetoothSap service = getService();
- final int defaultValue = BluetoothSap.STATE_ERROR;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getState(mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the currently connected remote Bluetooth device (PCE).
- *
- * @return The remote Bluetooth device, or null if not in connected or connecting state, or if
- * this proxy object is not connected to the Sap service.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public BluetoothDevice getClient() {
- if (VDBG) log("getClient()");
- final IBluetoothSap service = getService();
- final BluetoothDevice defaultValue = null;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<BluetoothDevice> recv =
- new SynchronousResultReceiver();
- service.getClient(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Returns true if the specified Bluetooth device is connected.
- * Returns false if not connected, or if this proxy object is not
- * currently connected to the Sap service.
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean isConnected(BluetoothDevice device) {
- if (VDBG) log("isConnected(" + device + ")");
- final IBluetoothSap service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.isConnected(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Initiate connection. Initiation of outgoing connections is not
- * supported for SAP server.
- *
- * @hide
- */
- @RequiresNoPermission
- public boolean connect(BluetoothDevice device) {
- if (DBG) log("connect(" + device + ")" + "not supported for SAPS");
- return false;
- }
-
- /**
- * Initiate disconnect.
- *
- * @param device Remote Bluetooth Device
- * @return false on error, true otherwise
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public boolean disconnect(BluetoothDevice device) {
- if (DBG) log("disconnect(" + device + ")");
- final IBluetoothSap service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.disconnect(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the list of connected devices. Currently at most one.
- *
- * @return list of connected devices
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getConnectedDevices() {
- if (DBG) log("getConnectedDevices()");
- final IBluetoothSap service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the list of devices matching specified states. Currently at most one.
- *
- * @return list of matching devices
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (DBG) log("getDevicesMatchingStates()");
- final IBluetoothSap service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get connection state of device
- *
- * @return device connection state
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (DBG) log("getConnectionState(" + device + ")");
- final IBluetoothSap service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Set priority of the profile
- *
- * <p> The device should already be paired.
- * Priority can be one of {@link #PRIORITY_ON} or {@link #PRIORITY_OFF},
- *
- * @param device Paired bluetooth device
- * @param priority
- * @return true if priority is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setPriority(BluetoothDevice device, int priority) {
- if (DBG) log("setPriority(" + device + ", " + priority + ")");
- return setConnectionPolicy(device, BluetoothAdapter.priorityToConnectionPolicy(priority));
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothSap service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the priority of the profile.
- *
- * <p> The priority can be any of:
- * {@link #PRIORITY_OFF}, {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
- *
- * @param device Bluetooth device
- * @return priority of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public int getPriority(BluetoothDevice device) {
- if (VDBG) log("getPriority(" + device + ")");
- return BluetoothAdapter.connectionPolicyToPriority(getConnectionPolicy(device));
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothSap service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-
- private boolean isEnabled() {
- return mAdapter.isEnabled();
- }
-
- private static boolean isValidDevice(BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothServerSocket.java b/core/java/android/bluetooth/BluetoothServerSocket.java
deleted file mode 100644
index bb4e354..0000000
--- a/core/java/android/bluetooth/BluetoothServerSocket.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.SuppressLint;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.Handler;
-import android.os.ParcelUuid;
-import android.util.Log;
-
-import java.io.Closeable;
-import java.io.IOException;
-
-/**
- * A listening Bluetooth socket.
- *
- * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
- * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
- * side, use a {@link BluetoothServerSocket} to create a listening server
- * socket. When a connection is accepted by the {@link BluetoothServerSocket},
- * it will return a new {@link BluetoothSocket} to manage the connection.
- * On the client side, use a single {@link BluetoothSocket} to both initiate
- * an outgoing connection and to manage the connection.
- *
- * <p>For Bluetooth BR/EDR, the most common type of socket is RFCOMM, which is the type supported by
- * the Android APIs. RFCOMM is a connection-oriented, streaming transport over Bluetooth BR/EDR. It
- * is also known as the Serial Port Profile (SPP). To create a listening
- * {@link BluetoothServerSocket} that's ready for incoming Bluetooth BR/EDR connections, use {@link
- * BluetoothAdapter#listenUsingRfcommWithServiceRecord
- * BluetoothAdapter.listenUsingRfcommWithServiceRecord()}.
- *
- * <p>For Bluetooth LE, the socket uses LE Connection-oriented Channel (CoC). LE CoC is a
- * connection-oriented, streaming transport over Bluetooth LE and has a credit-based flow control.
- * Correspondingly, use {@link BluetoothAdapter#listenUsingL2capChannel
- * BluetoothAdapter.listenUsingL2capChannel()} to create a listening {@link BluetoothServerSocket}
- * that's ready for incoming Bluetooth LE CoC connections. For LE CoC, you can use {@link #getPsm()}
- * to get the protocol/service multiplexer (PSM) value that the peer needs to use to connect to your
- * socket.
- *
- * <p> After the listening {@link BluetoothServerSocket} is created, call {@link #accept()} to
- * listen for incoming connection requests. This call will block until a connection is established,
- * at which point, it will return a {@link BluetoothSocket} to manage the connection. Once the
- * {@link BluetoothSocket} is acquired, it's a good idea to call {@link #close()} on the {@link
- * BluetoothServerSocket} when it's no longer needed for accepting
- * connections. Closing the {@link BluetoothServerSocket} will <em>not</em> close the returned
- * {@link BluetoothSocket}.
- *
- * <p>{@link BluetoothServerSocket} is thread
- * safe. In particular, {@link #close} will always immediately abort ongoing
- * operations and close the server socket.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about using Bluetooth, read the
- * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
- * </div>
- *
- * {@see BluetoothSocket}
- */
-@SuppressLint("AndroidFrameworkBluetoothPermission")
-public final class BluetoothServerSocket implements Closeable {
-
- private static final String TAG = "BluetoothServerSocket";
- private static final boolean DBG = false;
- @UnsupportedAppUsage(publicAlternatives = "Use public {@link BluetoothServerSocket} API "
- + "instead.")
- /*package*/ final BluetoothSocket mSocket;
- private Handler mHandler;
- private int mMessage;
- private int mChannel;
-
- /**
- * Construct a socket for incoming connections.
- *
- * @param type type of socket
- * @param auth require the remote device to be authenticated
- * @param encrypt require the connection to be encrypted
- * @param port remote port
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * privileges
- */
- /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port)
- throws IOException {
- mChannel = port;
- mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null);
- if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- mSocket.setExcludeSdp(true);
- }
- }
-
- /**
- * Construct a socket for incoming connections.
- *
- * @param type type of socket
- * @param auth require the remote device to be authenticated
- * @param encrypt require the connection to be encrypted
- * @param port remote port
- * @param mitm enforce person-in-the-middle protection for authentication.
- * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * privileges
- */
- /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, int port,
- boolean mitm, boolean min16DigitPin)
- throws IOException {
- mChannel = port;
- mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, port, null, mitm,
- min16DigitPin);
- if (port == BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- mSocket.setExcludeSdp(true);
- }
- }
-
- /**
- * Construct a socket for incoming connections.
- *
- * @param type type of socket
- * @param auth require the remote device to be authenticated
- * @param encrypt require the connection to be encrypted
- * @param uuid uuid
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * privileges
- */
- /*package*/ BluetoothServerSocket(int type, boolean auth, boolean encrypt, ParcelUuid uuid)
- throws IOException {
- mSocket = new BluetoothSocket(type, -1, auth, encrypt, null, -1, uuid);
- // TODO: This is the same as mChannel = -1 - is this intentional?
- mChannel = mSocket.getPort();
- }
-
-
- /**
- * Block until a connection is established.
- * <p>Returns a connected {@link BluetoothSocket} on successful connection.
- * <p>Once this call returns, it can be called again to accept subsequent
- * incoming connections.
- * <p>{@link #close} can be used to abort this call from another thread.
- *
- * @return a connected {@link BluetoothSocket}
- * @throws IOException on error, for example this call was aborted, or timeout
- */
- public BluetoothSocket accept() throws IOException {
- return accept(-1);
- }
-
- /**
- * Block until a connection is established, with timeout.
- * <p>Returns a connected {@link BluetoothSocket} on successful connection.
- * <p>Once this call returns, it can be called again to accept subsequent
- * incoming connections.
- * <p>{@link #close} can be used to abort this call from another thread.
- *
- * @return a connected {@link BluetoothSocket}
- * @throws IOException on error, for example this call was aborted, or timeout
- */
- public BluetoothSocket accept(int timeout) throws IOException {
- return mSocket.accept(timeout);
- }
-
- /**
- * Immediately close this socket, and release all associated resources.
- * <p>Causes blocked calls on this socket in other threads to immediately
- * throw an IOException.
- * <p>Closing the {@link BluetoothServerSocket} will <em>not</em>
- * close any {@link BluetoothSocket} received from {@link #accept()}.
- */
- public void close() throws IOException {
- if (DBG) Log.d(TAG, "BluetoothServerSocket:close() called. mChannel=" + mChannel);
- synchronized (this) {
- if (mHandler != null) {
- mHandler.obtainMessage(mMessage).sendToTarget();
- }
- }
- mSocket.close();
- }
-
- /*package*/
- synchronized void setCloseHandler(Handler handler, int message) {
- mHandler = handler;
- mMessage = message;
- }
-
- /*package*/ void setServiceName(String serviceName) {
- mSocket.setServiceName(serviceName);
- }
-
- /**
- * Returns the channel on which this socket is bound.
- *
- * @hide
- */
- public int getChannel() {
- return mChannel;
- }
-
- /**
- * Returns the assigned dynamic protocol/service multiplexer (PSM) value for the listening L2CAP
- * Connection-oriented Channel (CoC) server socket. This server socket must be returned by the
- * {@link BluetoothAdapter#listenUsingL2capChannel()} or {@link
- * BluetoothAdapter#listenUsingInsecureL2capChannel()}. The returned value is undefined if this
- * method is called on non-L2CAP server sockets.
- *
- * @return the assigned PSM or LE_PSM value depending on transport
- */
- public int getPsm() {
- return mChannel;
- }
-
- /**
- * Sets the channel on which future sockets are bound.
- * Currently used only when a channel is auto generated.
- */
- /*package*/ void setChannel(int newChannel) {
- /* TODO: From a design/architecture perspective this is wrong.
- * The bind operation should be conducted through this class
- * and the resulting port should be kept in mChannel, and
- * not set from BluetoothAdapter. */
- if (mSocket != null) {
- if (mSocket.getPort() != newChannel) {
- Log.w(TAG, "The port set is different that the underlying port. mSocket.getPort(): "
- + mSocket.getPort() + " requested newChannel: " + newChannel);
- }
- }
- mChannel = newChannel;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("ServerSocket: Type: ");
- switch (mSocket.getConnectionType()) {
- case BluetoothSocket.TYPE_RFCOMM: {
- sb.append("TYPE_RFCOMM");
- break;
- }
- case BluetoothSocket.TYPE_L2CAP: {
- sb.append("TYPE_L2CAP");
- break;
- }
- case BluetoothSocket.TYPE_L2CAP_LE: {
- sb.append("TYPE_L2CAP_LE");
- break;
- }
- case BluetoothSocket.TYPE_SCO: {
- sb.append("TYPE_SCO");
- break;
- }
- }
- sb.append(" Channel: ").append(mChannel);
- return sb.toString();
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
deleted file mode 100644
index db5b751..0000000
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ /dev/null
@@ -1,809 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.net.LocalSocket;
-import android.os.Build;
-import android.os.ParcelFileDescriptor;
-import android.os.ParcelUuid;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.Closeable;
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.Locale;
-import java.util.UUID;
-
-/**
- * A connected or connecting Bluetooth socket.
- *
- * <p>The interface for Bluetooth Sockets is similar to that of TCP sockets:
- * {@link java.net.Socket} and {@link java.net.ServerSocket}. On the server
- * side, use a {@link BluetoothServerSocket} to create a listening server
- * socket. When a connection is accepted by the {@link BluetoothServerSocket},
- * it will return a new {@link BluetoothSocket} to manage the connection.
- * On the client side, use a single {@link BluetoothSocket} to both initiate
- * an outgoing connection and to manage the connection.
- *
- * <p>The most common type of Bluetooth socket is RFCOMM, which is the type
- * supported by the Android APIs. RFCOMM is a connection-oriented, streaming
- * transport over Bluetooth. It is also known as the Serial Port Profile (SPP).
- *
- * <p>To create a {@link BluetoothSocket} for connecting to a known device, use
- * {@link BluetoothDevice#createRfcommSocketToServiceRecord
- * BluetoothDevice.createRfcommSocketToServiceRecord()}.
- * Then call {@link #connect()} to attempt a connection to the remote device.
- * This call will block until a connection is established or the connection
- * fails.
- *
- * <p>To create a {@link BluetoothSocket} as a server (or "host"), see the
- * {@link BluetoothServerSocket} documentation.
- *
- * <p>Once the socket is connected, whether initiated as a client or accepted
- * as a server, open the IO streams by calling {@link #getInputStream} and
- * {@link #getOutputStream} in order to retrieve {@link java.io.InputStream}
- * and {@link java.io.OutputStream} objects, respectively, which are
- * automatically connected to the socket.
- *
- * <p>{@link BluetoothSocket} is thread
- * safe. In particular, {@link #close} will always immediately abort ongoing
- * operations and close the socket.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about using Bluetooth, read the
- * <a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> developer guide.</p>
- * </div>
- *
- * {@see BluetoothServerSocket}
- * {@see java.io.InputStream}
- * {@see java.io.OutputStream}
- */
-public final class BluetoothSocket implements Closeable {
- private static final String TAG = "BluetoothSocket";
- private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
- private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
-
- /** @hide */
- public static final int MAX_RFCOMM_CHANNEL = 30;
- /*package*/ static final int MAX_L2CAP_PACKAGE_SIZE = 0xFFFF;
-
- /** RFCOMM socket */
- public static final int TYPE_RFCOMM = 1;
-
- /** SCO socket */
- public static final int TYPE_SCO = 2;
-
- /** L2CAP socket */
- public static final int TYPE_L2CAP = 3;
-
- /** L2CAP socket on BR/EDR transport
- * @hide
- */
- public static final int TYPE_L2CAP_BREDR = TYPE_L2CAP;
-
- /** L2CAP socket on LE transport
- * @hide
- */
- public static final int TYPE_L2CAP_LE = 4;
-
- /*package*/ static final int EBADFD = 77;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- /*package*/ static final int EADDRINUSE = 98;
-
- /*package*/ static final int SEC_FLAG_ENCRYPT = 1;
- /*package*/ static final int SEC_FLAG_AUTH = 1 << 1;
- /*package*/ static final int BTSOCK_FLAG_NO_SDP = 1 << 2;
- /*package*/ static final int SEC_FLAG_AUTH_MITM = 1 << 3;
- /*package*/ static final int SEC_FLAG_AUTH_16_DIGIT = 1 << 4;
-
- private final int mType; /* one of TYPE_RFCOMM etc */
- private BluetoothDevice mDevice; /* remote device */
- private String mAddress; /* remote address */
- private final boolean mAuth;
- private final boolean mEncrypt;
- private final BluetoothInputStream mInputStream;
- private final BluetoothOutputStream mOutputStream;
- private final ParcelUuid mUuid;
- /** when true no SPP SDP record will be created */
- private boolean mExcludeSdp = false;
- /** when true Person-in-the-middle protection will be enabled */
- private boolean mAuthMitm = false;
- /** Minimum 16 digit pin for sec mode 2 connections */
- private boolean mMin16DigitPin = false;
- @UnsupportedAppUsage(publicAlternatives = "Use {@link BluetoothSocket} public API instead.")
- private ParcelFileDescriptor mPfd;
- @UnsupportedAppUsage
- private LocalSocket mSocket;
- private InputStream mSocketIS;
- private OutputStream mSocketOS;
- @UnsupportedAppUsage
- private int mPort; /* RFCOMM channel or L2CAP psm */
- private int mFd;
- private String mServiceName;
- private static final int PROXY_CONNECTION_TIMEOUT = 5000;
-
- private static final int SOCK_SIGNAL_SIZE = 20;
-
- private ByteBuffer mL2capBuffer = null;
- private int mMaxTxPacketSize = 0; // The l2cap maximum packet size supported by the peer.
- private int mMaxRxPacketSize = 0; // The l2cap maximum packet size that can be received.
-
- private enum SocketState {
- INIT,
- CONNECTED,
- LISTENING,
- CLOSED,
- }
-
- /** prevents all native calls after destroyNative() */
- private volatile SocketState mSocketState;
-
- /** protects mSocketState */
- //private final ReentrantReadWriteLock mLock;
-
- /**
- * Construct a BluetoothSocket.
- *
- * @param type type of socket
- * @param fd fd to use for connected socket, or -1 for a new socket
- * @param auth require the remote device to be authenticated
- * @param encrypt require the connection to be encrypted
- * @param device remote device that this socket can connect to
- * @param port remote port
- * @param uuid SDP uuid
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * privileges
- */
- /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
- BluetoothDevice device, int port, ParcelUuid uuid) throws IOException {
- this(type, fd, auth, encrypt, device, port, uuid, false, false);
- }
-
- /**
- * Construct a BluetoothSocket.
- *
- * @param type type of socket
- * @param fd fd to use for connected socket, or -1 for a new socket
- * @param auth require the remote device to be authenticated
- * @param encrypt require the connection to be encrypted
- * @param device remote device that this socket can connect to
- * @param port remote port
- * @param uuid SDP uuid
- * @param mitm enforce person-in-the-middle protection.
- * @param min16DigitPin enforce a minimum length of 16 digits for a sec mode 2 connection
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * privileges
- */
- /*package*/ BluetoothSocket(int type, int fd, boolean auth, boolean encrypt,
- BluetoothDevice device, int port, ParcelUuid uuid, boolean mitm, boolean min16DigitPin)
- throws IOException {
- if (VDBG) Log.d(TAG, "Creating new BluetoothSocket of type: " + type);
- if (type == BluetoothSocket.TYPE_RFCOMM && uuid == null && fd == -1
- && port != BluetoothAdapter.SOCKET_CHANNEL_AUTO_STATIC_NO_SDP) {
- if (port < 1 || port > MAX_RFCOMM_CHANNEL) {
- throw new IOException("Invalid RFCOMM channel: " + port);
- }
- }
- if (uuid != null) {
- mUuid = uuid;
- } else {
- mUuid = new ParcelUuid(new UUID(0, 0));
- }
- mType = type;
- mAuth = auth;
- mAuthMitm = mitm;
- mMin16DigitPin = min16DigitPin;
- mEncrypt = encrypt;
- mDevice = device;
- mPort = port;
- mFd = fd;
-
- mSocketState = SocketState.INIT;
-
- if (device == null) {
- // Server socket
- mAddress = BluetoothAdapter.getDefaultAdapter().getAddress();
- } else {
- // Remote socket
- mAddress = device.getAddress();
- }
- mInputStream = new BluetoothInputStream(this);
- mOutputStream = new BluetoothOutputStream(this);
- }
-
- private BluetoothSocket(BluetoothSocket s) {
- if (VDBG) Log.d(TAG, "Creating new Private BluetoothSocket of type: " + s.mType);
- mUuid = s.mUuid;
- mType = s.mType;
- mAuth = s.mAuth;
- mEncrypt = s.mEncrypt;
- mPort = s.mPort;
- mInputStream = new BluetoothInputStream(this);
- mOutputStream = new BluetoothOutputStream(this);
- mMaxRxPacketSize = s.mMaxRxPacketSize;
- mMaxTxPacketSize = s.mMaxTxPacketSize;
-
- mServiceName = s.mServiceName;
- mExcludeSdp = s.mExcludeSdp;
- mAuthMitm = s.mAuthMitm;
- mMin16DigitPin = s.mMin16DigitPin;
- }
-
- private BluetoothSocket acceptSocket(String remoteAddr) throws IOException {
- BluetoothSocket as = new BluetoothSocket(this);
- as.mSocketState = SocketState.CONNECTED;
- FileDescriptor[] fds = mSocket.getAncillaryFileDescriptors();
- if (DBG) Log.d(TAG, "socket fd passed by stack fds: " + Arrays.toString(fds));
- if (fds == null || fds.length != 1) {
- Log.e(TAG, "socket fd passed from stack failed, fds: " + Arrays.toString(fds));
- as.close();
- throw new IOException("bt socket acept failed");
- }
-
- as.mPfd = ParcelFileDescriptor.dup(fds[0]);
- as.mSocket = LocalSocket.createConnectedLocalSocket(fds[0]);
- as.mSocketIS = as.mSocket.getInputStream();
- as.mSocketOS = as.mSocket.getOutputStream();
- as.mAddress = remoteAddr;
- as.mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr);
- return as;
- }
-
- /**
- * Construct a BluetoothSocket from address. Used by native code.
- *
- * @param type type of socket
- * @param fd fd to use for connected socket, or -1 for a new socket
- * @param auth require the remote device to be authenticated
- * @param encrypt require the connection to be encrypted
- * @param address remote device that this socket can connect to
- * @param port remote port
- * @throws IOException On error, for example Bluetooth not available, or insufficient
- * privileges
- */
- private BluetoothSocket(int type, int fd, boolean auth, boolean encrypt, String address,
- int port) throws IOException {
- this(type, fd, auth, encrypt, new BluetoothDevice(address), port, null, false, false);
- }
-
- /** @hide */
- @Override
- protected void finalize() throws Throwable {
- try {
- close();
- } finally {
- super.finalize();
- }
- }
-
- private int getSecurityFlags() {
- int flags = 0;
- if (mAuth) {
- flags |= SEC_FLAG_AUTH;
- }
- if (mEncrypt) {
- flags |= SEC_FLAG_ENCRYPT;
- }
- if (mExcludeSdp) {
- flags |= BTSOCK_FLAG_NO_SDP;
- }
- if (mAuthMitm) {
- flags |= SEC_FLAG_AUTH_MITM;
- }
- if (mMin16DigitPin) {
- flags |= SEC_FLAG_AUTH_16_DIGIT;
- }
- return flags;
- }
-
- /**
- * Get the remote device this socket is connecting, or connected, to.
- *
- * @return remote device
- */
- @RequiresNoPermission
- public BluetoothDevice getRemoteDevice() {
- return mDevice;
- }
-
- /**
- * Get the input stream associated with this socket.
- * <p>The input stream will be returned even if the socket is not yet
- * connected, but operations on that stream will throw IOException until
- * the associated socket is connected.
- *
- * @return InputStream
- */
- @RequiresNoPermission
- public InputStream getInputStream() throws IOException {
- return mInputStream;
- }
-
- /**
- * Get the output stream associated with this socket.
- * <p>The output stream will be returned even if the socket is not yet
- * connected, but operations on that stream will throw IOException until
- * the associated socket is connected.
- *
- * @return OutputStream
- */
- @RequiresNoPermission
- public OutputStream getOutputStream() throws IOException {
- return mOutputStream;
- }
-
- /**
- * Get the connection status of this socket, ie, whether there is an active connection with
- * remote device.
- *
- * @return true if connected false if not connected
- */
- @RequiresNoPermission
- public boolean isConnected() {
- return mSocketState == SocketState.CONNECTED;
- }
-
- /*package*/ void setServiceName(String name) {
- mServiceName = name;
- }
-
- /**
- * Attempt to connect to a remote device.
- * <p>This method will block until a connection is made or the connection
- * fails. If this method returns without an exception then this socket
- * is now connected.
- * <p>Creating new connections to
- * remote Bluetooth devices should not be attempted while device discovery
- * is in progress. Device discovery is a heavyweight procedure on the
- * Bluetooth adapter and will significantly slow a device connection.
- * Use {@link BluetoothAdapter#cancelDiscovery()} to cancel an ongoing
- * discovery. Discovery is not managed by the Activity,
- * but is run as a system service, so an application should always call
- * {@link BluetoothAdapter#cancelDiscovery()} even if it
- * did not directly request a discovery, just to be sure.
- * <p>{@link #close} can be used to abort this call from another thread.
- *
- * @throws IOException on error, for example connection failure
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void connect() throws IOException {
- if (mDevice == null) throw new IOException("Connect is called on null device");
-
- try {
- if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
- IBluetooth bluetoothProxy =
- BluetoothAdapter.getDefaultAdapter().getBluetoothService();
- if (bluetoothProxy == null) throw new IOException("Bluetooth is off");
- mPfd = bluetoothProxy.getSocketManager().connectSocket(mDevice, mType,
- mUuid, mPort, getSecurityFlags());
- synchronized (this) {
- if (DBG) Log.d(TAG, "connect(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
- if (mSocketState == SocketState.CLOSED) throw new IOException("socket closed");
- if (mPfd == null) throw new IOException("bt socket connect failed");
- FileDescriptor fd = mPfd.getFileDescriptor();
- mSocket = LocalSocket.createConnectedLocalSocket(fd);
- mSocketIS = mSocket.getInputStream();
- mSocketOS = mSocket.getOutputStream();
- }
- int channel = readInt(mSocketIS);
- if (channel <= 0) {
- throw new IOException("bt socket connect failed");
- }
- mPort = channel;
- waitSocketSignal(mSocketIS);
- synchronized (this) {
- if (mSocketState == SocketState.CLOSED) {
- throw new IOException("bt socket closed");
- }
- mSocketState = SocketState.CONNECTED;
- }
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- throw new IOException("unable to send RPC: " + e.getMessage());
- }
- }
-
- /**
- * Currently returns unix errno instead of throwing IOException,
- * so that BluetoothAdapter can check the error code for EADDRINUSE
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- /*package*/ int bindListen() {
- int ret;
- if (mSocketState == SocketState.CLOSED) return EBADFD;
- IBluetooth bluetoothProxy = BluetoothAdapter.getDefaultAdapter().getBluetoothService();
- if (bluetoothProxy == null) {
- Log.e(TAG, "bindListen fail, reason: bluetooth is off");
- return -1;
- }
- try {
- if (DBG) Log.d(TAG, "bindListen(): mPort=" + mPort + ", mType=" + mType);
- mPfd = bluetoothProxy.getSocketManager().createSocketChannel(mType, mServiceName,
- mUuid, mPort, getSecurityFlags());
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- return -1;
- }
-
- // read out port number
- try {
- synchronized (this) {
- if (DBG) {
- Log.d(TAG, "bindListen(), SocketState: " + mSocketState + ", mPfd: " + mPfd);
- }
- if (mSocketState != SocketState.INIT) return EBADFD;
- if (mPfd == null) return -1;
- FileDescriptor fd = mPfd.getFileDescriptor();
- if (fd == null) {
- Log.e(TAG, "bindListen(), null file descriptor");
- return -1;
- }
-
- if (DBG) Log.d(TAG, "bindListen(), Create LocalSocket");
- mSocket = LocalSocket.createConnectedLocalSocket(fd);
- if (DBG) Log.d(TAG, "bindListen(), new LocalSocket.getInputStream()");
- mSocketIS = mSocket.getInputStream();
- mSocketOS = mSocket.getOutputStream();
- }
- if (DBG) Log.d(TAG, "bindListen(), readInt mSocketIS: " + mSocketIS);
- int channel = readInt(mSocketIS);
- synchronized (this) {
- if (mSocketState == SocketState.INIT) {
- mSocketState = SocketState.LISTENING;
- }
- }
- if (DBG) Log.d(TAG, "bindListen(): channel=" + channel + ", mPort=" + mPort);
- if (mPort <= -1) {
- mPort = channel;
- } // else ASSERT(mPort == channel)
- ret = 0;
- } catch (IOException e) {
- if (mPfd != null) {
- try {
- mPfd.close();
- } catch (IOException e1) {
- Log.e(TAG, "bindListen, close mPfd: " + e1);
- }
- mPfd = null;
- }
- Log.e(TAG, "bindListen, fail to get port number, exception: " + e);
- return -1;
- }
- return ret;
- }
-
- /*package*/ BluetoothSocket accept(int timeout) throws IOException {
- BluetoothSocket acceptedSocket;
- if (mSocketState != SocketState.LISTENING) {
- throw new IOException("bt socket is not in listen state");
- }
- if (timeout > 0) {
- Log.d(TAG, "accept() set timeout (ms):" + timeout);
- mSocket.setSoTimeout(timeout);
- }
- String RemoteAddr = waitSocketSignal(mSocketIS);
- if (timeout > 0) {
- mSocket.setSoTimeout(0);
- }
- synchronized (this) {
- if (mSocketState != SocketState.LISTENING) {
- throw new IOException("bt socket is not in listen state");
- }
- acceptedSocket = acceptSocket(RemoteAddr);
- //quick drop the reference of the file handle
- }
- return acceptedSocket;
- }
-
- /*package*/ int available() throws IOException {
- if (VDBG) Log.d(TAG, "available: " + mSocketIS);
- return mSocketIS.available();
- }
-
- /*package*/ int read(byte[] b, int offset, int length) throws IOException {
- int ret = 0;
- if (VDBG) Log.d(TAG, "read in: " + mSocketIS + " len: " + length);
- if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
- int bytesToRead = length;
- if (VDBG) {
- Log.v(TAG, "l2cap: read(): offset: " + offset + " length:" + length
- + "mL2capBuffer= " + mL2capBuffer);
- }
- if (mL2capBuffer == null) {
- createL2capRxBuffer();
- }
- if (mL2capBuffer.remaining() == 0) {
- if (VDBG) Log.v(TAG, "l2cap buffer empty, refilling...");
- if (fillL2capRxBuffer() == -1) {
- return -1;
- }
- }
- if (bytesToRead > mL2capBuffer.remaining()) {
- bytesToRead = mL2capBuffer.remaining();
- }
- if (VDBG) {
- Log.v(TAG, "get(): offset: " + offset
- + " bytesToRead: " + bytesToRead);
- }
- mL2capBuffer.get(b, offset, bytesToRead);
- ret = bytesToRead;
- } else {
- if (VDBG) Log.v(TAG, "default: read(): offset: " + offset + " length:" + length);
- ret = mSocketIS.read(b, offset, length);
- }
- if (ret < 0) {
- throw new IOException("bt socket closed, read return: " + ret);
- }
- if (VDBG) Log.d(TAG, "read out: " + mSocketIS + " ret: " + ret);
- return ret;
- }
-
- /*package*/ int write(byte[] b, int offset, int length) throws IOException {
-
- //TODO: Since bindings can exist between the SDU size and the
- // protocol, we might need to throw an exception instead of just
- // splitting the write into multiple smaller writes.
- // Rfcomm uses dynamic allocation, and should not have any bindings
- // to the actual message length.
- if (VDBG) Log.d(TAG, "write: " + mSocketOS + " length: " + length);
- if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
- if (length <= mMaxTxPacketSize) {
- mSocketOS.write(b, offset, length);
- } else {
- if (DBG) {
- Log.w(TAG, "WARNING: Write buffer larger than L2CAP packet size!\n"
- + "Packet will be divided into SDU packets of size "
- + mMaxTxPacketSize);
- }
- int tmpOffset = offset;
- int bytesToWrite = length;
- while (bytesToWrite > 0) {
- int tmpLength = (bytesToWrite > mMaxTxPacketSize)
- ? mMaxTxPacketSize
- : bytesToWrite;
- mSocketOS.write(b, tmpOffset, tmpLength);
- tmpOffset += tmpLength;
- bytesToWrite -= tmpLength;
- }
- }
- } else {
- mSocketOS.write(b, offset, length);
- }
- // There is no good way to confirm since the entire process is asynchronous anyway
- if (VDBG) Log.d(TAG, "write out: " + mSocketOS + " length: " + length);
- return length;
- }
-
- @Override
- public void close() throws IOException {
- Log.d(TAG, "close() this: " + this + ", channel: " + mPort + ", mSocketIS: " + mSocketIS
- + ", mSocketOS: " + mSocketOS + "mSocket: " + mSocket + ", mSocketState: "
- + mSocketState);
- if (mSocketState == SocketState.CLOSED) {
- return;
- } else {
- synchronized (this) {
- if (mSocketState == SocketState.CLOSED) {
- return;
- }
- mSocketState = SocketState.CLOSED;
- if (mSocket != null) {
- if (DBG) Log.d(TAG, "Closing mSocket: " + mSocket);
- mSocket.shutdownInput();
- mSocket.shutdownOutput();
- mSocket.close();
- mSocket = null;
- }
- if (mPfd != null) {
- mPfd.close();
- mPfd = null;
- }
- }
- }
- }
-
- /*package */ void removeChannel() {
- }
-
- /*package */ int getPort() {
- return mPort;
- }
-
- /**
- * Get the maximum supported Transmit packet size for the underlying transport.
- * Use this to optimize the writes done to the output socket, to avoid sending
- * half full packets.
- *
- * @return the maximum supported Transmit packet size for the underlying transport.
- */
- @RequiresNoPermission
- public int getMaxTransmitPacketSize() {
- return mMaxTxPacketSize;
- }
-
- /**
- * Get the maximum supported Receive packet size for the underlying transport.
- * Use this to optimize the reads done on the input stream, as any call to read
- * will return a maximum of this amount of bytes - or for some transports a
- * multiple of this value.
- *
- * @return the maximum supported Receive packet size for the underlying transport.
- */
- @RequiresNoPermission
- public int getMaxReceivePacketSize() {
- return mMaxRxPacketSize;
- }
-
- /**
- * Get the type of the underlying connection.
- *
- * @return one of {@link #TYPE_RFCOMM}, {@link #TYPE_SCO} or {@link #TYPE_L2CAP}
- */
- @RequiresNoPermission
- public int getConnectionType() {
- if (mType == TYPE_L2CAP_LE) {
- // Treat the LE CoC to be the same type as L2CAP.
- return TYPE_L2CAP;
- }
- return mType;
- }
-
- /**
- * Change if a SDP entry should be automatically created.
- * Must be called before calling .bind, for the call to have any effect.
- *
- * @param excludeSdp <li>TRUE - do not auto generate SDP record. <li>FALSE - default - auto
- * generate SPP SDP record.
- * @hide
- */
- @RequiresNoPermission
- public void setExcludeSdp(boolean excludeSdp) {
- mExcludeSdp = excludeSdp;
- }
-
- /**
- * Set the LE Transmit Data Length to be the maximum that the BT Controller is capable of. This
- * parameter is used by the BT Controller to set the maximum transmission packet size on this
- * connection. This function is currently used for testing only.
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public void requestMaximumTxDataLength() throws IOException {
- if (mDevice == null) {
- throw new IOException("requestMaximumTxDataLength is called on null device");
- }
-
- try {
- if (mSocketState == SocketState.CLOSED) {
- throw new IOException("socket closed");
- }
- IBluetooth bluetoothProxy =
- BluetoothAdapter.getDefaultAdapter().getBluetoothService();
- if (bluetoothProxy == null) {
- throw new IOException("Bluetooth is off");
- }
-
- if (DBG) Log.d(TAG, "requestMaximumTxDataLength");
- bluetoothProxy.getSocketManager().requestMaximumTxDataLength(mDevice);
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- throw new IOException("unable to send RPC: " + e.getMessage());
- }
- }
-
- private String convertAddr(final byte[] addr) {
- return String.format(Locale.US, "%02X:%02X:%02X:%02X:%02X:%02X",
- addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
- }
-
- private String waitSocketSignal(InputStream is) throws IOException {
- byte[] sig = new byte[SOCK_SIGNAL_SIZE];
- int ret = readAll(is, sig);
- if (VDBG) {
- Log.d(TAG, "waitSocketSignal read " + SOCK_SIGNAL_SIZE + " bytes signal ret: " + ret);
- }
- ByteBuffer bb = ByteBuffer.wrap(sig);
- /* the struct in native is decorated with __attribute__((packed)), hence this is possible */
- bb.order(ByteOrder.nativeOrder());
- int size = bb.getShort();
- if (size != SOCK_SIGNAL_SIZE) {
- throw new IOException("Connection failure, wrong signal size: " + size);
- }
- byte[] addr = new byte[6];
- bb.get(addr);
- int channel = bb.getInt();
- int status = bb.getInt();
- mMaxTxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
- mMaxRxPacketSize = (bb.getShort() & 0xffff); // Convert to unsigned value
- String RemoteAddr = convertAddr(addr);
- if (VDBG) {
- Log.d(TAG, "waitSocketSignal: sig size: " + size + ", remote addr: "
- + RemoteAddr + ", channel: " + channel + ", status: " + status
- + " MaxRxPktSize: " + mMaxRxPacketSize + " MaxTxPktSize: " + mMaxTxPacketSize);
- }
- if (status != 0) {
- throw new IOException("Connection failure, status: " + status);
- }
- return RemoteAddr;
- }
-
- private void createL2capRxBuffer() {
- if ((mType == TYPE_L2CAP) || (mType == TYPE_L2CAP_LE)) {
- // Allocate the buffer to use for reads.
- if (VDBG) Log.v(TAG, " Creating mL2capBuffer: mMaxPacketSize: " + mMaxRxPacketSize);
- mL2capBuffer = ByteBuffer.wrap(new byte[mMaxRxPacketSize]);
- if (VDBG) Log.v(TAG, "mL2capBuffer.remaining()" + mL2capBuffer.remaining());
- mL2capBuffer.limit(0); // Ensure we do a real read at the first read-request
- if (VDBG) {
- Log.v(TAG, "mL2capBuffer.remaining() after limit(0):" + mL2capBuffer.remaining());
- }
- }
- }
-
- private int readAll(InputStream is, byte[] b) throws IOException {
- int left = b.length;
- while (left > 0) {
- int ret = is.read(b, b.length - left, left);
- if (ret <= 0) {
- throw new IOException("read failed, socket might closed or timeout, read ret: "
- + ret);
- }
- left -= ret;
- if (left != 0) {
- Log.w(TAG, "readAll() looping, read partial size: " + (b.length - left)
- + ", expect size: " + b.length);
- }
- }
- return b.length;
- }
-
- private int readInt(InputStream is) throws IOException {
- byte[] ibytes = new byte[4];
- int ret = readAll(is, ibytes);
- if (VDBG) Log.d(TAG, "inputStream.read ret: " + ret);
- ByteBuffer bb = ByteBuffer.wrap(ibytes);
- bb.order(ByteOrder.nativeOrder());
- return bb.getInt();
- }
-
- private int fillL2capRxBuffer() throws IOException {
- mL2capBuffer.rewind();
- int ret = mSocketIS.read(mL2capBuffer.array());
- if (ret == -1) {
- // reached end of stream - return -1
- mL2capBuffer.limit(0);
- return -1;
- }
- mL2capBuffer.limit(ret);
- return ret;
- }
-
-
-}
diff --git a/core/java/android/bluetooth/BluetoothStatusCodes.java b/core/java/android/bluetooth/BluetoothStatusCodes.java
deleted file mode 100644
index a8ce4b4..0000000
--- a/core/java/android/bluetooth/BluetoothStatusCodes.java
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.SystemApi;
-
-/**
- * A class with constants representing possible return values for Bluetooth APIs. General return
- * values occupy the range 0 to 199. Profile-specific return values occupy the range 200-999.
- * API-specific return values start at 1000. The exception to this is the "UNKNOWN" error code which
- * occupies the max integer value.
- */
-public final class BluetoothStatusCodes {
-
- private BluetoothStatusCodes() {}
-
- /**
- * Indicates that the API call was successful.
- */
- public static final int SUCCESS = 0;
-
- /**
- * Error code indicating that Bluetooth is not enabled.
- */
- public static final int ERROR_BLUETOOTH_NOT_ENABLED = 1;
-
- /**
- * Error code indicating that the API call was initiated by neither the system nor the active
- * user.
- */
- public static final int ERROR_BLUETOOTH_NOT_ALLOWED = 2;
-
- /**
- * Error code indicating that the Bluetooth Device specified is not bonded.
- */
- public static final int ERROR_DEVICE_NOT_BONDED = 3;
-
- /**
- * Error code indicating that the Bluetooth Device specified is not connected, but is bonded.
- *
- * @hide
- */
- public static final int ERROR_DEVICE_NOT_CONNECTED = 4;
-
- /**
- * Error code indicating that the caller does not have the
- * {@link android.Manifest.permission#BLUETOOTH_ADVERTISE} permission.
- *
- * @hide
- */
- public static final int ERROR_MISSING_BLUETOOTH_ADVERTISE_PERMISSION = 5;
-
- /**
- * Error code indicating that the caller does not have the
- * {@link android.Manifest.permission#BLUETOOTH_CONNECT} permission.
- */
- public static final int ERROR_MISSING_BLUETOOTH_CONNECT_PERMISSION = 6;
-
- /**
- * Error code indicating that the caller does not have the
- * {@link android.Manifest.permission#BLUETOOTH_SCAN} permission.
- *
- * @hide
- */
- public static final int ERROR_MISSING_BLUETOOTH_SCAN_PERMISSION = 7;
-
- /**
- * Error code indicating that the caller does not have the
- * {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission.
- */
- public static final int ERROR_MISSING_BLUETOOTH_PRIVILEGED_PERMISSION = 8;
-
- /**
- * Error code indicating that the profile service is not bound. You can bind a profile service
- * by calling {@link BluetoothAdapter#getProfileProxy}.
- */
- public static final int ERROR_PROFILE_SERVICE_NOT_BOUND = 9;
-
- /**
- * Indicates that the feature is supported.
- */
- public static final int FEATURE_SUPPORTED = 10;
-
- /**
- * Indicates that the feature is not supported.
- */
- public static final int FEATURE_NOT_SUPPORTED = 11;
-
- /**
- * Error code indicating that the device is not the active device for this profile.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_NOT_ACTIVE_DEVICE = 12;
-
- /**
- * Error code indicating that there are no active devices for the profile.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_NO_ACTIVE_DEVICES = 13;
-
- /**
- * Indicates that the Bluetooth profile is not connected to this device.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_PROFILE_NOT_CONNECTED = 14;
-
- /**
- * Error code indicating that the requested operation timed out.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_TIMEOUT = 15;
-
- /**
- * A GATT writeCharacteristic request is not permitted on the remote device.
- */
- public static final int ERROR_GATT_WRITE_NOT_ALLOWED = 200;
-
- /**
- * A GATT writeCharacteristic request is issued to a busy remote device.
- */
- public static final int ERROR_GATT_WRITE_REQUEST_BUSY = 201;
-
- /**
- * If another application has already requested {@link OobData} then another fetch will be
- * disallowed until the callback is removed.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_ANOTHER_ACTIVE_OOB_REQUEST = 1000;
-
- /**
- * Indicates that the ACL disconnected due to an explicit request from the local device.
- * <p>
- * Example cause: This is a normal disconnect reason, e.g., user/app initiates
- * disconnection.
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_LOCAL_REQUEST = 1100;
-
- /**
- * Indicates that the ACL disconnected due to an explicit request from the remote device.
- * <p>
- * Example cause: This is a normal disconnect reason, e.g., user/app initiates
- * disconnection.
- * <p>
- * Example solution: The app can also prompt the user to check their remote device.
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_REMOTE_REQUEST = 1101;
-
- /**
- * Generic disconnect reason indicating the ACL disconnected due to an error on the local
- * device.
- * <p>
- * Example solution: Prompt the user to check their local device (e.g., phone, car
- * headunit).
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_LOCAL = 1102;
-
- /**
- * Generic disconnect reason indicating the ACL disconnected due to an error on the remote
- * device.
- * <p>
- * Example solution: Prompt the user to check their remote device (e.g., headset, car
- * headunit, watch).
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_REMOTE = 1103;
-
- /**
- * Indicates that the ACL disconnected due to a timeout.
- * <p>
- * Example cause: remote device might be out of range.
- * <p>
- * Example solution: Prompt user to verify their remote device is on or in
- * connection/pairing mode.
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_TIMEOUT = 1104;
-
- /**
- * Indicates that the ACL disconnected due to link key issues.
- * <p>
- * Example cause: Devices are either unpaired or remote device is refusing our pairing
- * request.
- * <p>
- * Example solution: Prompt user to unpair and pair again.
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_SECURITY = 1105;
-
- /**
- * Indicates that the ACL disconnected due to the local device's system policy.
- * <p>
- * Example cause: privacy policy, power management policy, permissions, etc.
- * <p>
- * Example solution: Prompt the user to check settings, or check with their system
- * administrator (e.g. some corp-managed devices do not allow OPP connection).
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_SYSTEM_POLICY = 1106;
-
- /**
- * Indicates that the ACL disconnected due to resource constraints, either on the local
- * device or the remote device.
- * <p>
- * Example cause: controller is busy, memory limit reached, maximum number of connections
- * reached.
- * <p>
- * Example solution: The app should wait and try again. If still failing, prompt the user
- * to disconnect some devices, or toggle Bluetooth on the local and/or the remote device.
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_RESOURCE_LIMIT_REACHED = 1107;
-
- /**
- * Indicates that the ACL disconnected because another ACL connection already exists.
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_CONNECTION_ALREADY_EXISTS = 1108;
-
- /**
- * Indicates that the ACL disconnected due to incorrect parameters passed in from the app.
- * <p>
- * Example solution: Change parameters and try again. If error persists, the app can report
- * telemetry and/or log the error in a bugreport.
- *
- * @hide
- */
- public static final int ERROR_DISCONNECT_REASON_BAD_PARAMETERS = 1109;
-
- /**
- * Indicates that setting the LE Audio Broadcast mode failed.
- * <p>
- * Example solution: Change parameters and try again. If error persists, the app can report
- * telemetry and/or log the error in a bugreport.
- *
- * @hide
- */
- public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_BROADCAST_MODE_FAILED = 1110;
-
- /**
- * Indicates that setting a new encryption key for Bluetooth LE Audio Broadcast Source failed.
- * <p>
- * Example solution: Change parameters and try again. If error persists, the app can report
- * telemetry and/or log the error in a bugreport.
- *
- * @hide
- */
- public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_SET_ENCRYPTION_KEY_FAILED = 1111;
-
- /**
- * Indicates that connecting to a remote Broadcast Audio Scan Service failed.
- * <p>
- * Example solution: Change parameters and try again. If error persists, the app can report
- * telemetry and/or log the error in a bugreport.
- *
- * @hide
- */
- public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_CONNECT_FAILED = 1112;
-
- /**
- * Indicates that disconnecting from a remote Broadcast Audio Scan Service failed.
- * <p>
- * Example solution: Change parameters and try again. If error persists, the app can report
- * telemetry and/or log the error in a bugreport.
- *
- * @hide
- */
- public static final int ERROR_LE_AUDIO_BROADCAST_AUDIO_SCAN_SERVICE_DISCONNECT_FAILED = 1113;
-
- /**
- * Indicates that enabling LE Audio Broadcast encryption failed
- * <p>
- * Example solution: Change parameters and try again. If error persists, the app can report
- * telemetry and/or log the error in a bugreport.
- *
- * @hide
- */
- public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_ENABLE_ENCRYPTION_FAILED = 1114;
-
- /**
- * Indicates that disabling LE Audio Broadcast encryption failed
- * <p>
- * Example solution: Change parameters and try again. If error persists, the app can report
- * telemetry and/or log the error in a bugreport.
- *
- * @hide
- */
- public static final int ERROR_LE_AUDIO_BROADCAST_SOURCE_DISABLE_ENCRYPTION_FAILED = 1115;
-
- /**
- * Indicates that there is already one device for which SCO audio is connected or connecting.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_AUDIO_DEVICE_ALREADY_CONNECTED = 1116;
-
- /**
- * Indicates that SCO audio was already not connected for this device.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_AUDIO_DEVICE_ALREADY_DISCONNECTED = 1117;
-
- /**
- * Indicates that there audio route is currently blocked by the system.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_AUDIO_ROUTE_BLOCKED = 1118;
-
- /**
- * Indicates that there is an active call preventing this operation from succeeding.
- *
- * @hide
- */
- @SystemApi
- public static final int ERROR_CALL_ACTIVE = 1119;
-
- /**
- * Indicates that an unknown error has occurred has occurred.
- */
- public static final int ERROR_UNKNOWN = Integer.MAX_VALUE;
-}
diff --git a/core/java/android/bluetooth/BluetoothUtils.java b/core/java/android/bluetooth/BluetoothUtils.java
deleted file mode 100644
index 8674692..0000000
--- a/core/java/android/bluetooth/BluetoothUtils.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import java.time.Duration;
-
-/**
- * {@hide}
- */
-public final class BluetoothUtils {
- /**
- * This utility class cannot be instantiated
- */
- private BluetoothUtils() {}
-
- /**
- * Timeout value for synchronous binder call
- */
- private static final Duration SYNC_CALLS_TIMEOUT = Duration.ofSeconds(5);
-
- /**
- * @return timeout value for synchronous binder call
- */
- static Duration getSyncTimeout() {
- return SYNC_CALLS_TIMEOUT;
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
deleted file mode 100644
index 2a8ff51..0000000
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ /dev/null
@@ -1,394 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.ParcelUuid;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.UUID;
-
-/**
- * Static helper methods and constants to decode the ParcelUuid of remote devices.
- *
- * @hide
- */
-@SystemApi
-@SuppressLint("AndroidFrameworkBluetoothPermission")
-public final class BluetoothUuid {
-
- /* See Bluetooth Assigned Numbers document - SDP section, to get the values of UUIDs
- * for the various services.
- *
- * The following 128 bit values are calculated as:
- * uuid * 2^96 + BASE_UUID
- */
-
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid A2DP_SINK =
- ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid A2DP_SOURCE =
- ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid ADV_AUDIO_DIST =
- ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid HSP =
- ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid HSP_AG =
- ParcelUuid.fromString("00001112-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid HFP =
- ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid HFP_AG =
- ParcelUuid.fromString("0000111F-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid AVRCP_CONTROLLER =
- ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid AVRCP_TARGET =
- ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid OBEX_OBJECT_PUSH =
- ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid HID =
- ParcelUuid.fromString("00001124-0000-1000-8000-00805f9b34fb");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid HOGP =
- ParcelUuid.fromString("00001812-0000-1000-8000-00805f9b34fb");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid PANU =
- ParcelUuid.fromString("00001115-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid NAP =
- ParcelUuid.fromString("00001116-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid BNEP =
- ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid PBAP_PCE =
- ParcelUuid.fromString("0000112e-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid PBAP_PSE =
- ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid MAP =
- ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid MNS =
- ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid MAS =
- ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid SAP =
- ParcelUuid.fromString("0000112D-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid HEARING_AID =
- ParcelUuid.fromString("0000FDF0-0000-1000-8000-00805f9b34fb");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid LE_AUDIO =
- ParcelUuid.fromString("0000184E-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid DIP =
- ParcelUuid.fromString("00001200-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid VOLUME_CONTROL =
- ParcelUuid.fromString("00001844-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid GENERIC_MEDIA_CONTROL =
- ParcelUuid.fromString("00001849-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid MEDIA_CONTROL =
- ParcelUuid.fromString("00001848-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid COORDINATED_SET =
- ParcelUuid.fromString("00001846-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid CAP =
- ParcelUuid.fromString("00001853-0000-1000-8000-00805F9B34FB");
- /** @hide */
- @NonNull
- @SystemApi
- public static final ParcelUuid BASE_UUID =
- ParcelUuid.fromString("00000000-0000-1000-8000-00805F9B34FB");
-
- /**
- * Length of bytes for 16 bit UUID
- *
- * @hide
- */
- @SystemApi
- public static final int UUID_BYTES_16_BIT = 2;
- /**
- * Length of bytes for 32 bit UUID
- *
- * @hide
- */
- @SystemApi
- public static final int UUID_BYTES_32_BIT = 4;
- /**
- * Length of bytes for 128 bit UUID
- *
- * @hide
- */
- @SystemApi
- public static final int UUID_BYTES_128_BIT = 16;
-
- /**
- * Returns true if there any common ParcelUuids in uuidA and uuidB.
- *
- * @param uuidA - List of ParcelUuids
- * @param uuidB - List of ParcelUuids
- *
- * @hide
- */
- @SystemApi
- public static boolean containsAnyUuid(@Nullable ParcelUuid[] uuidA,
- @Nullable ParcelUuid[] uuidB) {
- if (uuidA == null && uuidB == null) return true;
-
- if (uuidA == null) {
- return uuidB.length == 0;
- }
-
- if (uuidB == null) {
- return uuidA.length == 0;
- }
-
- HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid>(Arrays.asList(uuidA));
- for (ParcelUuid uuid : uuidB) {
- if (uuidSet.contains(uuid)) return true;
- }
- return false;
- }
-
- /**
- * Extract the Service Identifier or the actual uuid from the Parcel Uuid.
- * For example, if 0000110B-0000-1000-8000-00805F9B34FB is the parcel Uuid,
- * this function will return 110B
- *
- * @param parcelUuid
- * @return the service identifier.
- */
- private static int getServiceIdentifierFromParcelUuid(ParcelUuid parcelUuid) {
- UUID uuid = parcelUuid.getUuid();
- long value = (uuid.getMostSignificantBits() & 0xFFFFFFFF00000000L) >>> 32;
- return (int) value;
- }
-
- /**
- * Parse UUID from bytes. The {@code uuidBytes} can represent a 16-bit, 32-bit or 128-bit UUID,
- * but the returned UUID is always in 128-bit format.
- * Note UUID is little endian in Bluetooth.
- *
- * @param uuidBytes Byte representation of uuid.
- * @return {@link ParcelUuid} parsed from bytes.
- * @throws IllegalArgumentException If the {@code uuidBytes} cannot be parsed.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public static ParcelUuid parseUuidFrom(@Nullable byte[] uuidBytes) {
- if (uuidBytes == null) {
- throw new IllegalArgumentException("uuidBytes cannot be null");
- }
- int length = uuidBytes.length;
- if (length != UUID_BYTES_16_BIT && length != UUID_BYTES_32_BIT
- && length != UUID_BYTES_128_BIT) {
- throw new IllegalArgumentException("uuidBytes length invalid - " + length);
- }
-
- // Construct a 128 bit UUID.
- if (length == UUID_BYTES_128_BIT) {
- ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
- long msb = buf.getLong(8);
- long lsb = buf.getLong(0);
- return new ParcelUuid(new UUID(msb, lsb));
- }
-
- // For 16 bit and 32 bit UUID we need to convert them to 128 bit value.
- // 128_bit_value = uuid * 2^96 + BASE_UUID
- long shortUuid;
- if (length == UUID_BYTES_16_BIT) {
- shortUuid = uuidBytes[0] & 0xFF;
- shortUuid += (uuidBytes[1] & 0xFF) << 8;
- } else {
- shortUuid = uuidBytes[0] & 0xFF;
- shortUuid += (uuidBytes[1] & 0xFF) << 8;
- shortUuid += (uuidBytes[2] & 0xFF) << 16;
- shortUuid += (uuidBytes[3] & 0xFF) << 24;
- }
- long msb = BASE_UUID.getUuid().getMostSignificantBits() + (shortUuid << 32);
- long lsb = BASE_UUID.getUuid().getLeastSignificantBits();
- return new ParcelUuid(new UUID(msb, lsb));
- }
-
- /**
- * Parse UUID to bytes. The returned value is shortest representation, a 16-bit, 32-bit or
- * 128-bit UUID, Note returned value is little endian (Bluetooth).
- *
- * @param uuid uuid to parse.
- * @return shortest representation of {@code uuid} as bytes.
- * @throws IllegalArgumentException If the {@code uuid} is null.
- *
- * @hide
- */
- public static byte[] uuidToBytes(ParcelUuid uuid) {
- if (uuid == null) {
- throw new IllegalArgumentException("uuid cannot be null");
- }
-
- if (is16BitUuid(uuid)) {
- byte[] uuidBytes = new byte[UUID_BYTES_16_BIT];
- int uuidVal = getServiceIdentifierFromParcelUuid(uuid);
- uuidBytes[0] = (byte) (uuidVal & 0xFF);
- uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8);
- return uuidBytes;
- }
-
- if (is32BitUuid(uuid)) {
- byte[] uuidBytes = new byte[UUID_BYTES_32_BIT];
- int uuidVal = getServiceIdentifierFromParcelUuid(uuid);
- uuidBytes[0] = (byte) (uuidVal & 0xFF);
- uuidBytes[1] = (byte) ((uuidVal & 0xFF00) >> 8);
- uuidBytes[2] = (byte) ((uuidVal & 0xFF0000) >> 16);
- uuidBytes[3] = (byte) ((uuidVal & 0xFF000000) >> 24);
- return uuidBytes;
- }
-
- // Construct a 128 bit UUID.
- long msb = uuid.getUuid().getMostSignificantBits();
- long lsb = uuid.getUuid().getLeastSignificantBits();
-
- byte[] uuidBytes = new byte[UUID_BYTES_128_BIT];
- ByteBuffer buf = ByteBuffer.wrap(uuidBytes).order(ByteOrder.LITTLE_ENDIAN);
- buf.putLong(8, msb);
- buf.putLong(0, lsb);
- return uuidBytes;
- }
-
- /**
- * Check whether the given parcelUuid can be converted to 16 bit bluetooth uuid.
- *
- * @param parcelUuid
- * @return true if the parcelUuid can be converted to 16 bit uuid, false otherwise.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public static boolean is16BitUuid(ParcelUuid parcelUuid) {
- UUID uuid = parcelUuid.getUuid();
- if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
- return false;
- }
- return ((uuid.getMostSignificantBits() & 0xFFFF0000FFFFFFFFL) == 0x1000L);
- }
-
-
- /**
- * Check whether the given parcelUuid can be converted to 32 bit bluetooth uuid.
- *
- * @param parcelUuid
- * @return true if the parcelUuid can be converted to 32 bit uuid, false otherwise.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public static boolean is32BitUuid(ParcelUuid parcelUuid) {
- UUID uuid = parcelUuid.getUuid();
- if (uuid.getLeastSignificantBits() != BASE_UUID.getUuid().getLeastSignificantBits()) {
- return false;
- }
- if (is16BitUuid(parcelUuid)) {
- return false;
- }
- return ((uuid.getMostSignificantBits() & 0xFFFFFFFFL) == 0x1000L);
- }
-
- private BluetoothUuid() {}
-}
diff --git a/core/java/android/bluetooth/BluetoothVolumeControl.java b/core/java/android/bluetooth/BluetoothVolumeControl.java
deleted file mode 100644
index 27532aa..0000000
--- a/core/java/android/bluetooth/BluetoothVolumeControl.java
+++ /dev/null
@@ -1,337 +0,0 @@
-/*
- * Copyright 2021 HIMSA II K/S - www.himsa.com.
- * Represented by EHIMA - www.ehima.com
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static android.bluetooth.BluetoothUtils.getSyncTimeout;
-
-import android.Manifest;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.bluetooth.annotations.RequiresBluetoothConnectPermission;
-import android.content.AttributionSource;
-import android.content.Context;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.util.CloseGuard;
-import android.util.Log;
-
-import com.android.modules.utils.SynchronousResultReceiver;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeoutException;
-
-/**
- * This class provides the public APIs to control the Bluetooth Volume Control service.
- *
- * <p>BluetoothVolumeControl is a proxy object for controlling the Bluetooth VC
- * Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothVolumeControl proxy object.
- * @hide
- */
-@SystemApi
-public final class BluetoothVolumeControl implements BluetoothProfile, AutoCloseable {
- private static final String TAG = "BluetoothVolumeControl";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- private CloseGuard mCloseGuard;
-
- /**
- * Intent used to broadcast the change in connection state of the Volume Control
- * profile.
- *
- * <p>This intent will have 3 extras:
- * <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
- * </ul>
- *
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
- *
- * @hide
- */
- @SystemApi
- @SuppressLint("ActionValue")
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_CONNECTION_STATE_CHANGED =
- "android.bluetooth.volume-control.profile.action.CONNECTION_STATE_CHANGED";
-
- private BluetoothAdapter mAdapter;
- private final AttributionSource mAttributionSource;
- private final BluetoothProfileConnector<IBluetoothVolumeControl> mProfileConnector =
- new BluetoothProfileConnector(this, BluetoothProfile.VOLUME_CONTROL, TAG,
- IBluetoothVolumeControl.class.getName()) {
- @Override
- public IBluetoothVolumeControl getServiceInterface(IBinder service) {
- return IBluetoothVolumeControl.Stub.asInterface(service);
- }
- };
-
- /**
- * Create a BluetoothVolumeControl proxy object for interacting with the local
- * Bluetooth Volume Control service.
- */
- /*package*/ BluetoothVolumeControl(Context context, ServiceListener listener,
- BluetoothAdapter adapter) {
- mAdapter = adapter;
- mAttributionSource = adapter.getAttributionSource();
- mProfileConnector.connect(context, listener);
- mCloseGuard = new CloseGuard();
- mCloseGuard.open("close");
- }
-
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- protected void finalize() {
- if (mCloseGuard != null) {
- mCloseGuard.warnIfOpen();
- }
- close();
- }
-
- @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void close() {
- mProfileConnector.disconnect();
- }
-
- private IBluetoothVolumeControl getService() { return mProfileConnector.getService(); }
-
- /**
- * Get the list of connected devices. Currently at most one.
- *
- * @return list of connected devices
- *
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @NonNull List<BluetoothDevice> getConnectedDevices() {
- if (DBG) log("getConnectedDevices()");
- final IBluetoothVolumeControl service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getConnectedDevices(mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the list of devices matching specified states. Currently at most one.
- *
- * @return list of matching devices
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
- if (DBG) log("getDevicesMatchingStates()");
- final IBluetoothVolumeControl service = getService();
- final List<BluetoothDevice> defaultValue = new ArrayList<BluetoothDevice>();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver<List<BluetoothDevice>> recv =
- new SynchronousResultReceiver();
- service.getDevicesMatchingConnectionStates(states, mAttributionSource, recv);
- return Attributable.setAttributionSource(
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue),
- mAttributionSource);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get connection state of device
- *
- * @return device connection state
- *
- * @hide
- */
- @RequiresBluetoothConnectPermission
- @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
- public int getConnectionState(BluetoothDevice device) {
- if (DBG) log("getConnectionState(" + device + ")");
- final IBluetoothVolumeControl service = getService();
- final int defaultValue = BluetoothProfile.STATE_DISCONNECTED;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionState(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Tells remote device to set an absolute volume.
- *
- * @param volume Absolute volume to be set on remote device.
- * Minimum value is 0 and maximum value is 255
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public void setVolume(@Nullable BluetoothDevice device,
- @IntRange(from = 0, to = 255) int volume) {
- if (DBG) log("setVolume(" + volume + ")");
- final IBluetoothVolumeControl service = getService();
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled()) {
- try {
- final SynchronousResultReceiver recv = new SynchronousResultReceiver();
- service.setVolume(device, volume, mAttributionSource, recv);
- recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(null);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- }
-
- /**
- * Set connection policy of the profile
- *
- * <p> The device should already be paired.
- * Connection policy can be one of {@link #CONNECTION_POLICY_ALLOWED},
- * {@link #CONNECTION_POLICY_FORBIDDEN}, {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Paired bluetooth device
- * @param connectionPolicy is the connection policy to set to for this profile
- * @return true if connectionPolicy is set, false on error
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
- @ConnectionPolicy int connectionPolicy) {
- if (DBG) log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
- final IBluetoothVolumeControl service = getService();
- final boolean defaultValue = false;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)
- && (connectionPolicy == BluetoothProfile.CONNECTION_POLICY_FORBIDDEN
- || connectionPolicy == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) {
- try {
- final SynchronousResultReceiver<Boolean> recv = new SynchronousResultReceiver();
- service.setConnectionPolicy(device, connectionPolicy, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- /**
- * Get the connection policy of the profile.
- *
- * <p> The connection policy can be any of:
- * {@link #CONNECTION_POLICY_ALLOWED}, {@link #CONNECTION_POLICY_FORBIDDEN},
- * {@link #CONNECTION_POLICY_UNKNOWN}
- *
- * @param device Bluetooth device
- * @return connection policy of the device
- * @hide
- */
- @SystemApi
- @RequiresBluetoothConnectPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public @ConnectionPolicy int getConnectionPolicy(@NonNull BluetoothDevice device) {
- if (VDBG) log("getConnectionPolicy(" + device + ")");
- final IBluetoothVolumeControl service = getService();
- final int defaultValue = BluetoothProfile.CONNECTION_POLICY_FORBIDDEN;
- if (service == null) {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) log(Log.getStackTraceString(new Throwable()));
- } else if (isEnabled() && isValidDevice(device)) {
- try {
- final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
- service.getConnectionPolicy(device, mAttributionSource, recv);
- return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultValue);
- } catch (RemoteException | TimeoutException e) {
- Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
- }
- }
- return defaultValue;
- }
-
- private boolean isEnabled() {
- return mAdapter.getState() == BluetoothAdapter.STATE_ON;
- }
-
- private static boolean isValidDevice(@Nullable BluetoothDevice device) {
- return device != null && BluetoothAdapter.checkBluetoothAddress(device.getAddress());
- }
-
- private static void log(String msg) {
- Log.d(TAG, msg);
- }
-}
diff --git a/core/java/android/bluetooth/BufferConstraint.java b/core/java/android/bluetooth/BufferConstraint.java
deleted file mode 100644
index cbffc78..0000000
--- a/core/java/android/bluetooth/BufferConstraint.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Stores a codec's constraints on buffering length in milliseconds.
- *
- * {@hide}
- */
-@SystemApi
-public final class BufferConstraint implements Parcelable {
-
- private static final String TAG = "BufferConstraint";
- private int mDefaultMillis;
- private int mMaxMillis;
- private int mMinMillis;
-
- public BufferConstraint(int defaultMillis, int maxMillis,
- int minMillis) {
- mDefaultMillis = defaultMillis;
- mMaxMillis = maxMillis;
- mMinMillis = minMillis;
- }
-
- BufferConstraint(Parcel in) {
- mDefaultMillis = in.readInt();
- mMaxMillis = in.readInt();
- mMinMillis = in.readInt();
- }
-
- public static final @NonNull Parcelable.Creator<BufferConstraint> CREATOR =
- new Parcelable.Creator<BufferConstraint>() {
- public BufferConstraint createFromParcel(Parcel in) {
- return new BufferConstraint(in);
- }
-
- public BufferConstraint[] newArray(int size) {
- return new BufferConstraint[size];
- }
- };
-
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeInt(mDefaultMillis);
- out.writeInt(mMaxMillis);
- out.writeInt(mMinMillis);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Get the default buffer millis
- *
- * @return default buffer millis
- * @hide
- */
- @SystemApi
- public int getDefaultMillis() {
- return mDefaultMillis;
- }
-
- /**
- * Get the maximum buffer millis
- *
- * @return maximum buffer millis
- * @hide
- */
- @SystemApi
- public int getMaxMillis() {
- return mMaxMillis;
- }
-
- /**
- * Get the minimum buffer millis
- *
- * @return minimum buffer millis
- * @hide
- */
- @SystemApi
- public int getMinMillis() {
- return mMinMillis;
- }
-}
diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java
deleted file mode 100644
index 97d9723..0000000
--- a/core/java/android/bluetooth/BufferConstraints.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-
-/**
- * A parcelable collection of buffer constraints by codec type.
- *
- * {@hide}
- */
-@SystemApi
-public final class BufferConstraints implements Parcelable {
- public static final int BUFFER_CODEC_MAX_NUM = 32;
-
- private static final String TAG = "BufferConstraints";
-
- private Map<Integer, BufferConstraint> mBufferConstraints;
- private List<BufferConstraint> mBufferConstraintList;
-
- public BufferConstraints(@NonNull List<BufferConstraint>
- bufferConstraintList) {
-
- mBufferConstraintList = new ArrayList<BufferConstraint>(bufferConstraintList);
- mBufferConstraints = new HashMap<Integer, BufferConstraint>();
- for (int i = 0; i < BUFFER_CODEC_MAX_NUM; i++) {
- mBufferConstraints.put(i, bufferConstraintList.get(i));
- }
- }
-
- BufferConstraints(Parcel in) {
- mBufferConstraintList = new ArrayList<BufferConstraint>();
- mBufferConstraints = new HashMap<Integer, BufferConstraint>();
- in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader());
- for (int i = 0; i < mBufferConstraintList.size(); i++) {
- mBufferConstraints.put(i, mBufferConstraintList.get(i));
- }
- }
-
- public static final @NonNull Parcelable.Creator<BufferConstraints> CREATOR =
- new Parcelable.Creator<BufferConstraints>() {
- public BufferConstraints createFromParcel(Parcel in) {
- return new BufferConstraints(in);
- }
-
- public BufferConstraints[] newArray(int size) {
- return new BufferConstraints[size];
- }
- };
-
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- out.writeList(mBufferConstraintList);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Get the buffer constraints by codec type.
- *
- * @param codec Audio codec
- * @return buffer constraints by codec type.
- * @hide
- */
- @SystemApi
- public @Nullable BufferConstraint forCodec(@BluetoothCodecConfig.SourceCodecType int codec) {
- return mBufferConstraints.get(codec);
- }
-}
diff --git a/core/java/android/bluetooth/OWNERS b/core/java/android/bluetooth/OWNERS
deleted file mode 100644
index 8e9d7b7..0000000
--- a/core/java/android/bluetooth/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 27441
-
-sattiraju@google.com
-baligh@google.com
diff --git a/core/java/android/bluetooth/OobData.java b/core/java/android/bluetooth/OobData.java
deleted file mode 100644
index bb0b956..0000000
--- a/core/java/android/bluetooth/OobData.java
+++ /dev/null
@@ -1,958 +0,0 @@
-/**
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Out Of Band Data for Bluetooth device pairing.
- *
- * <p>This object represents optional data obtained from a remote device through
- * an out-of-band channel (eg. NFC, QR).
- *
- * <p>References:
- * NFC AD Forum SSP 1.1 (AD)
- * {@link https://members.nfc-forum.org//apps/group_public/download.php/24620/NFCForum-AD-BTSSP_1_1.pdf}
- * Core Specification Supplement (CSS) V9
- *
- * <p>There are several BR/EDR Examples
- *
- * <p>Negotiated Handover:
- * Bluetooth Carrier Configuration Record:
- * - OOB Data Length
- * - Device Address
- * - Class of Device
- * - Simple Pairing Hash C
- * - Simple Pairing Randomizer R
- * - Service Class UUID
- * - Bluetooth Local Name
- *
- * <p>Static Handover:
- * Bluetooth Carrier Configuration Record:
- * - OOB Data Length
- * - Device Address
- * - Class of Device
- * - Service Class UUID
- * - Bluetooth Local Name
- *
- * <p>Simplified Tag Format for Single BT Carrier:
- * Bluetooth OOB Data Record:
- * - OOB Data Length
- * - Device Address
- * - Class of Device
- * - Service Class UUID
- * - Bluetooth Local Name
- *
- * @hide
- */
-@SystemApi
-public final class OobData implements Parcelable {
-
- private static final String TAG = "OobData";
- /** The {@link OobData#mClassicLength} may be. (AD 3.1.1) (CSS 1.6.2) @hide */
- @SystemApi
- public static final int OOB_LENGTH_OCTETS = 2;
- /**
- * The length for the {@link OobData#mDeviceAddressWithType}(6) and Address Type(1).
- * (AD 3.1.2) (CSS 1.6.2)
- * @hide
- */
- @SystemApi
- public static final int DEVICE_ADDRESS_OCTETS = 7;
- /** The Class of Device is 3 octets. (AD 3.1.3) (CSS 1.6.2) @hide */
- @SystemApi
- public static final int CLASS_OF_DEVICE_OCTETS = 3;
- /** The Confirmation data must be 16 octets. (AD 3.2.2) (CSS 1.6.2) @hide */
- @SystemApi
- public static final int CONFIRMATION_OCTETS = 16;
- /** The Randomizer data must be 16 octets. (AD 3.2.3) (CSS 1.6.2) @hide */
- @SystemApi
- public static final int RANDOMIZER_OCTETS = 16;
- /** The LE Device Role length is 1 octet. (AD 3.3.2) (CSS 1.17) @hide */
- @SystemApi
- public static final int LE_DEVICE_ROLE_OCTETS = 1;
- /** The {@link OobData#mLeTemporaryKey} length. (3.4.1) @hide */
- @SystemApi
- public static final int LE_TK_OCTETS = 16;
- /** The {@link OobData#mLeAppearance} length. (3.4.1) @hide */
- @SystemApi
- public static final int LE_APPEARANCE_OCTETS = 2;
- /** The {@link OobData#mLeFlags} length. (3.4.1) @hide */
- @SystemApi
- public static final int LE_DEVICE_FLAG_OCTETS = 1; // 1 octet to hold the 0-4 value.
-
- // Le Roles
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = { "LE_DEVICE_ROLE_" },
- value = {
- LE_DEVICE_ROLE_PERIPHERAL_ONLY,
- LE_DEVICE_ROLE_CENTRAL_ONLY,
- LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL,
- LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL
- }
- )
- public @interface LeRole {}
-
- /** @hide */
- @SystemApi
- public static final int LE_DEVICE_ROLE_PERIPHERAL_ONLY = 0x00;
- /** @hide */
- @SystemApi
- public static final int LE_DEVICE_ROLE_CENTRAL_ONLY = 0x01;
- /** @hide */
- @SystemApi
- public static final int LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL = 0x02;
- /** @hide */
- @SystemApi
- public static final int LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL = 0x03;
-
- // Le Flags
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = { "LE_FLAG_" },
- value = {
- LE_FLAG_LIMITED_DISCOVERY_MODE,
- LE_FLAG_GENERAL_DISCOVERY_MODE,
- LE_FLAG_BREDR_NOT_SUPPORTED,
- LE_FLAG_SIMULTANEOUS_CONTROLLER,
- LE_FLAG_SIMULTANEOUS_HOST
- }
- )
- public @interface LeFlag {}
-
- /** @hide */
- @SystemApi
- public static final int LE_FLAG_LIMITED_DISCOVERY_MODE = 0x00;
- /** @hide */
- @SystemApi
- public static final int LE_FLAG_GENERAL_DISCOVERY_MODE = 0x01;
- /** @hide */
- @SystemApi
- public static final int LE_FLAG_BREDR_NOT_SUPPORTED = 0x02;
- /** @hide */
- @SystemApi
- public static final int LE_FLAG_SIMULTANEOUS_CONTROLLER = 0x03;
- /** @hide */
- @SystemApi
- public static final int LE_FLAG_SIMULTANEOUS_HOST = 0x04;
-
- /**
- * Builds an {@link OobData} object and validates that the required combination
- * of values are present to create the LE specific OobData type.
- *
- * @hide
- */
- @SystemApi
- public static final class LeBuilder {
-
- /**
- * It is recommended that this Hash C is generated anew for each
- * pairing.
- *
- * <p>It should be noted that on passive NFC this isn't possible as the data is static
- * and immutable.
- */
- private byte[] mConfirmationHash = null;
-
- /**
- * Optional, but adds more validity to the pairing.
- *
- * <p>If not present a value of 0 is assumed.
- */
- private byte[] mRandomizerHash = new byte[] {
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- };
-
- /**
- * The Bluetooth Device user-friendly name presented over Bluetooth Technology.
- *
- * <p>This is the name that may be displayed to the device user as part of the UI.
- */
- private byte[] mDeviceName = null;
-
- /**
- * Sets the Bluetooth Device name to be used for UI purposes.
- *
- * <p>Optional attribute.
- *
- * @param deviceName byte array representing the name, may be 0 in length, not null.
- *
- * @return {@link OobData#ClassicBuilder}
- *
- * @throws NullPointerException if deviceName is null.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public LeBuilder setDeviceName(@NonNull byte[] deviceName) {
- requireNonNull(deviceName);
- this.mDeviceName = deviceName;
- return this;
- }
-
- /**
- * The Bluetooth Device Address is the address to which the OOB data belongs.
- *
- * <p>The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets.
- *
- * <p> Address is encoded in Little Endian order.
- *
- * <p>e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00
- */
- private final byte[] mDeviceAddressWithType;
-
- /**
- * During an LE connection establishment, one must be in the Peripheral mode and the other
- * in the Central role.
- *
- * <p>Possible Values:
- * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
- * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported
- * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported;
- * Peripheral Preferred
- * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred
- * 0x04 - 0xFF Reserved
- */
- private final @LeRole int mLeDeviceRole;
-
- /**
- * Temporary key value from the Security Manager.
- *
- * <p> Must be {@link LE_TK_OCTETS} in size
- */
- private byte[] mLeTemporaryKey = null;
-
- /**
- * Defines the representation of the external appearance of the device.
- *
- * <p>For example, a mouse, remote control, or keyboard.
- *
- * <p>Used for visual on discovering device to represent icon/string/etc...
- */
- private byte[] mLeAppearance = null;
-
- /**
- * Contains which discoverable mode to use, BR/EDR support and capability.
- *
- * <p>Possible LE Flags:
- * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode.
- * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode.
- * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of
- * LMP Feature Mask Definitions.
- * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to
- * Same Device Capable (Controller).
- * Bit 49 of LMP Feature Mask Definitions.
- * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to
- * Same Device Capable (Host).
- * Bit 55 of LMP Feature Mask Definitions.
- * <b>0x05- 0x07 Reserved</b>
- */
- private @LeFlag int mLeFlags = LE_FLAG_GENERAL_DISCOVERY_MODE; // Invalid default
-
- /**
- * Main creation method for creating a LE version of {@link OobData}.
- *
- * <p>This object will allow the caller to call {@link LeBuilder#build()}
- * to build the data object or add any option information to the builder.
- *
- * @param deviceAddressWithType the LE device address plus the address type (7 octets);
- * not null.
- * @param leDeviceRole whether the device supports Peripheral, Central,
- * Both including preference; not null. (1 octet)
- * @param confirmationHash Array consisting of {@link OobData#CONFIRMATION_OCTETS} octets
- * of data. Data is derived from controller/host stack and is
- * required for pairing OOB.
- *
- * <p>Possible Values:
- * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
- * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported
- * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported;
- * Peripheral Preferred
- * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred
- * 0x04 - 0xFF Reserved
- *
- * @throws IllegalArgumentException if any of the values fail to be set.
- * @throws NullPointerException if any argument is null.
- *
- * @hide
- */
- @SystemApi
- public LeBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] deviceAddressWithType,
- @LeRole int leDeviceRole) {
- requireNonNull(confirmationHash);
- requireNonNull(deviceAddressWithType);
- if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) {
- throw new IllegalArgumentException("confirmationHash must be "
- + OobData.CONFIRMATION_OCTETS + " octets in length.");
- }
- this.mConfirmationHash = confirmationHash;
- if (deviceAddressWithType.length != OobData.DEVICE_ADDRESS_OCTETS) {
- throw new IllegalArgumentException("confirmationHash must be "
- + OobData.DEVICE_ADDRESS_OCTETS+ " octets in length.");
- }
- this.mDeviceAddressWithType = deviceAddressWithType;
- if (leDeviceRole < LE_DEVICE_ROLE_PERIPHERAL_ONLY
- || leDeviceRole > LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL) {
- throw new IllegalArgumentException("leDeviceRole must be a valid value.");
- }
- this.mLeDeviceRole = leDeviceRole;
- }
-
- /**
- * Sets the Temporary Key value to be used by the LE Security Manager during
- * LE pairing.
- *
- * @param leTemporaryKey byte array that shall be 16 bytes. Please see Bluetooth CSSv6,
- * Part A 1.8 for a detailed description.
- *
- * @return {@link OobData#Builder}
- *
- * @throws IllegalArgumentException if the leTemporaryKey is an invalid format.
- * @throws NullinterException if leTemporaryKey is null.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public LeBuilder setLeTemporaryKey(@NonNull byte[] leTemporaryKey) {
- requireNonNull(leTemporaryKey);
- if (leTemporaryKey.length != LE_TK_OCTETS) {
- throw new IllegalArgumentException("leTemporaryKey must be "
- + LE_TK_OCTETS + " octets in length.");
- }
- this.mLeTemporaryKey = leTemporaryKey;
- return this;
- }
-
- /**
- * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets
- * of data. Data is derived from controller/host stack and is required for pairing OOB.
- * Also, randomizerHash may be all 0s or null in which case it becomes all 0s.
- *
- * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed.
- * @throws NullPointerException if randomizerHash is null.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public LeBuilder setRandomizerHash(@NonNull byte[] randomizerHash) {
- requireNonNull(randomizerHash);
- if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) {
- throw new IllegalArgumentException("randomizerHash must be "
- + OobData.RANDOMIZER_OCTETS + " octets in length.");
- }
- this.mRandomizerHash = randomizerHash;
- return this;
- }
-
- /**
- * Sets the LE Flags necessary for the pairing scenario or discovery mode.
- *
- * @param leFlags enum value representing the 1 octet of data about discovery modes.
- *
- * <p>Possible LE Flags:
- * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode.
- * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode.
- * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of
- * LMP Feature Mask Definitions.
- * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to
- * Same Device Capable (Controller) Bit 49 of LMP Feature Mask Definitions.
- * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to
- * Same Device Capable (Host).
- * Bit 55 of LMP Feature Mask Definitions.
- * 0x05- 0x07 Reserved
- *
- * @throws IllegalArgumentException for invalid flag
- * @hide
- */
- @NonNull
- @SystemApi
- public LeBuilder setLeFlags(@LeFlag int leFlags) {
- if (leFlags < LE_FLAG_LIMITED_DISCOVERY_MODE || leFlags > LE_FLAG_SIMULTANEOUS_HOST) {
- throw new IllegalArgumentException("leFlags must be a valid value.");
- }
- this.mLeFlags = leFlags;
- return this;
- }
-
- /**
- * Validates and builds the {@link OobData} object for LE Security.
- *
- * @return {@link OobData} with given builder values
- *
- * @throws IllegalStateException if either of the 2 required fields were not set.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public OobData build() {
- final OobData oob =
- new OobData(this.mDeviceAddressWithType, this.mLeDeviceRole,
- this.mConfirmationHash);
-
- // If we have values, set them, otherwise use default
- oob.mLeTemporaryKey =
- (this.mLeTemporaryKey != null) ? this.mLeTemporaryKey : oob.mLeTemporaryKey;
- oob.mLeAppearance = (this.mLeAppearance != null)
- ? this.mLeAppearance : oob.mLeAppearance;
- oob.mLeFlags = (this.mLeFlags != 0xF) ? this.mLeFlags : oob.mLeFlags;
- oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName;
- oob.mRandomizerHash = this.mRandomizerHash;
- return oob;
- }
- }
-
- /**
- * Builds an {@link OobData} object and validates that the required combination
- * of values are present to create the Classic specific OobData type.
- *
- * @hide
- */
- @SystemApi
- public static final class ClassicBuilder {
- // Used by both Classic and LE
- /**
- * It is recommended that this Hash C is generated anew for each
- * pairing.
- *
- * <p>It should be noted that on passive NFC this isn't possible as the data is static
- * and immutable.
- *
- * @hide
- */
- private byte[] mConfirmationHash = null;
-
- /**
- * Optional, but adds more validity to the pairing.
- *
- * <p>If not present a value of 0 is assumed.
- *
- * @hide
- */
- private byte[] mRandomizerHash = new byte[] {
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- };
-
- /**
- * The Bluetooth Device user-friendly name presented over Bluetooth Technology.
- *
- * <p>This is the name that may be displayed to the device user as part of the UI.
- *
- * @hide
- */
- private byte[] mDeviceName = null;
-
- /**
- * This length value provides the absolute length of total OOB data block used for
- * Bluetooth BR/EDR
- *
- * <p>OOB communication, which includes the length field itself and the Bluetooth
- * Device Address.
- *
- * <p>The minimum length that may be represented in this field is 8.
- *
- * @hide
- */
- private final byte[] mClassicLength;
-
- /**
- * The Bluetooth Device Address is the address to which the OOB data belongs.
- *
- * <p>The length MUST be {@link OobData#DEVICE_ADDRESS_OCTETS} octets.
- *
- * <p> Address is encoded in Little Endian order.
- *
- * <p>e.g. 00:01:02:03:04:05 would be x05x04x03x02x01x00
- *
- * @hide
- */
- private final byte[] mDeviceAddressWithType;
-
- /**
- * Class of Device information is to be used to provide a graphical representation
- * to the user as part of UI involving operations.
- *
- * <p>This is not to be used to determine a particular service can be used.
- *
- * <p>The length MUST be {@link OobData#CLASS_OF_DEVICE_OCTETS} octets.
- *
- * @hide
- */
- private byte[] mClassOfDevice = null;
-
- /**
- * Main creation method for creating a Classic version of {@link OobData}.
- *
- * <p>This object will allow the caller to call {@link ClassicBuilder#build()}
- * to build the data object or add any option information to the builder.
- *
- * @param confirmationHash byte array consisting of {@link OobData#CONFIRMATION_OCTETS}
- * octets of data. Data is derived from controller/host stack and is required for pairing
- * OOB.
- * @param classicLength byte array representing the length of data from 8-65535 across 2
- * octets (0xXXXX).
- * @param deviceAddressWithType byte array representing the Bluetooth Address of the device
- * that owns the OOB data. (i.e. the originator) [6 octets]
- *
- * @throws IllegalArgumentException if any of the values fail to be set.
- * @throws NullPointerException if any argument is null.
- *
- * @hide
- */
- @SystemApi
- public ClassicBuilder(@NonNull byte[] confirmationHash, @NonNull byte[] classicLength,
- @NonNull byte[] deviceAddressWithType) {
- requireNonNull(confirmationHash);
- requireNonNull(classicLength);
- requireNonNull(deviceAddressWithType);
- if (confirmationHash.length != OobData.CONFIRMATION_OCTETS) {
- throw new IllegalArgumentException("confirmationHash must be "
- + OobData.CONFIRMATION_OCTETS + " octets in length.");
- }
- this.mConfirmationHash = confirmationHash;
- if (classicLength.length != OOB_LENGTH_OCTETS) {
- throw new IllegalArgumentException("classicLength must be "
- + OOB_LENGTH_OCTETS + " octets in length.");
- }
- this.mClassicLength = classicLength;
- if (deviceAddressWithType.length != DEVICE_ADDRESS_OCTETS) {
- throw new IllegalArgumentException("deviceAddressWithType must be "
- + DEVICE_ADDRESS_OCTETS + " octets in length.");
- }
- this.mDeviceAddressWithType = deviceAddressWithType;
- }
-
- /**
- * @param randomizerHash byte array consisting of {@link OobData#RANDOMIZER_OCTETS} octets
- * of data. Data is derived from controller/host stack and is required for pairing OOB.
- * Also, randomizerHash may be all 0s or null in which case it becomes all 0s.
- *
- * @throws IllegalArgumentException if null or incorrect length randomizerHash was passed.
- * @throws NullPointerException if randomizerHash is null.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public ClassicBuilder setRandomizerHash(@NonNull byte[] randomizerHash) {
- requireNonNull(randomizerHash);
- if (randomizerHash.length != OobData.RANDOMIZER_OCTETS) {
- throw new IllegalArgumentException("randomizerHash must be "
- + OobData.RANDOMIZER_OCTETS + " octets in length.");
- }
- this.mRandomizerHash = randomizerHash;
- return this;
- }
-
- /**
- * Sets the Bluetooth Device name to be used for UI purposes.
- *
- * <p>Optional attribute.
- *
- * @param deviceName byte array representing the name, may be 0 in length, not null.
- *
- * @return {@link OobData#ClassicBuilder}
- *
- * @throws NullPointerException if deviceName is null
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public ClassicBuilder setDeviceName(@NonNull byte[] deviceName) {
- requireNonNull(deviceName);
- this.mDeviceName = deviceName;
- return this;
- }
-
- /**
- * Sets the Bluetooth Class of Device; used for UI purposes only.
- *
- * <p>Not an indicator of available services!
- *
- * <p>Optional attribute.
- *
- * @param classOfDevice byte array of {@link OobData#CLASS_OF_DEVICE_OCTETS} octets.
- *
- * @return {@link OobData#ClassicBuilder}
- *
- * @throws IllegalArgumentException if length is not equal to
- * {@link OobData#CLASS_OF_DEVICE_OCTETS} octets.
- * @throws NullPointerException if classOfDevice is null.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public ClassicBuilder setClassOfDevice(@NonNull byte[] classOfDevice) {
- requireNonNull(classOfDevice);
- if (classOfDevice.length != OobData.CLASS_OF_DEVICE_OCTETS) {
- throw new IllegalArgumentException("classOfDevice must be "
- + OobData.CLASS_OF_DEVICE_OCTETS + " octets in length.");
- }
- this.mClassOfDevice = classOfDevice;
- return this;
- }
-
- /**
- * Validates and builds the {@link OobDat object for Classic Security.
- *
- * @return {@link OobData} with previously given builder values.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public OobData build() {
- final OobData oob =
- new OobData(this.mClassicLength, this.mDeviceAddressWithType,
- this.mConfirmationHash);
- // If we have values, set them, otherwise use default
- oob.mDeviceName = (this.mDeviceName != null) ? this.mDeviceName : oob.mDeviceName;
- oob.mClassOfDevice = (this.mClassOfDevice != null)
- ? this.mClassOfDevice : oob.mClassOfDevice;
- oob.mRandomizerHash = this.mRandomizerHash;
- return oob;
- }
- }
-
- // Members (Defaults for Optionals must be set or Parceling fails on NPE)
- // Both
- private final byte[] mDeviceAddressWithType;
- private final byte[] mConfirmationHash;
- private byte[] mRandomizerHash = new byte[] {
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
- };
- // Default the name to "Bluetooth Device"
- private byte[] mDeviceName = new byte[] {
- // Bluetooth
- 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68,
- // <space>Device
- 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65
- };
-
- // Classic
- private final byte[] mClassicLength;
- private byte[] mClassOfDevice = new byte[CLASS_OF_DEVICE_OCTETS];
-
- // LE
- private final @LeRole int mLeDeviceRole;
- private byte[] mLeTemporaryKey = new byte[LE_TK_OCTETS];
- private byte[] mLeAppearance = new byte[LE_APPEARANCE_OCTETS];
- private @LeFlag int mLeFlags = LE_FLAG_LIMITED_DISCOVERY_MODE;
-
- /**
- * @return byte array representing the MAC address of a bluetooth device.
- * The Address is 6 octets long with a 1 octet address type associated with the address.
- *
- * <p>For classic this will be 6 byte address plus the default of PUBLIC_ADDRESS Address Type.
- * For LE there are more choices for Address Type.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public byte[] getDeviceAddressWithType() {
- return mDeviceAddressWithType;
- }
-
- /**
- * @return byte array representing the confirmationHash value
- * which is used to confirm the identity to the controller.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public byte[] getConfirmationHash() {
- return mConfirmationHash;
- }
-
- /**
- * @return byte array representing the randomizerHash value
- * which is used to verify the identity of the controller.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public byte[] getRandomizerHash() {
- return mRandomizerHash;
- }
-
- /**
- * @return Device Name used for displaying name in UI.
- *
- * <p>Also, this will be populated with the LE Local Name if the data is for LE.
- *
- * @hide
- */
- @Nullable
- @SystemApi
- public byte[] getDeviceName() {
- return mDeviceName;
- }
-
- /**
- * @return byte array representing the oob data length which is the length
- * of all of the data including these octets.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public byte[] getClassicLength() {
- return mClassicLength;
- }
-
- /**
- * @return byte array representing the class of device for UI display.
- *
- * <p>Does not indicate services available; for display only.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public byte[] getClassOfDevice() {
- return mClassOfDevice;
- }
-
- /**
- * @return Temporary Key used for LE pairing.
- *
- * @hide
- */
- @Nullable
- @SystemApi
- public byte[] getLeTemporaryKey() {
- return mLeTemporaryKey;
- }
-
- /**
- * @return Appearance used for LE pairing. For use in UI situations
- * when determining what sort of icons or text to display regarding
- * the device.
- *
- * @hide
- */
- @Nullable
- @SystemApi
- public byte[] getLeAppearance() {
- return mLeAppearance;
- }
-
- /**
- * @return Flags used to determing discoverable mode to use, BR/EDR Support, and Capability.
- *
- * <p>Possible LE Flags:
- * {@link LE_FLAG_LIMITED_DISCOVERY_MODE} LE Limited Discoverable Mode.
- * {@link LE_FLAG_GENERAL_DISCOVERY_MODE} LE General Discoverable Mode.
- * {@link LE_FLAG_BREDR_NOT_SUPPORTED} BR/EDR Not Supported. Bit 37 of
- * LMP Feature Mask Definitions.
- * {@link LE_FLAG_SIMULTANEOUS_CONTROLLER} Simultaneous LE and BR/EDR to
- * Same Device Capable (Controller).
- * Bit 49 of LMP Feature Mask Definitions.
- * {@link LE_FLAG_SIMULTANEOUS_HOST} Simultaneous LE and BR/EDR to
- * Same Device Capable (Host).
- * Bit 55 of LMP Feature Mask Definitions.
- * <b>0x05- 0x07 Reserved</b>
- *
- * @hide
- */
- @NonNull
- @SystemApi
- @LeFlag
- public int getLeFlags() {
- return mLeFlags;
- }
-
- /**
- * @return the supported and preferred roles of the LE device.
- *
- * <p>Possible Values:
- * {@link LE_DEVICE_ROLE_PERIPHERAL_ONLY} Only Peripheral supported
- * {@link LE_DEVICE_ROLE_CENTRAL_ONLY} Only Central supported
- * {@link LE_DEVICE_ROLE_BOTH_PREFER_PERIPHERAL} Central & Peripheral supported;
- * Peripheral Preferred
- * {@link LE_DEVICE_ROLE_BOTH_PREFER_CENTRAL} Only peripheral supported; Central Preferred
- * 0x04 - 0xFF Reserved
- *
- * @hide
- */
- @NonNull
- @SystemApi
- @LeRole
- public int getLeDeviceRole() {
- return mLeDeviceRole;
- }
-
- /**
- * Classic Security Constructor
- */
- private OobData(@NonNull byte[] classicLength, @NonNull byte[] deviceAddressWithType,
- @NonNull byte[] confirmationHash) {
- mClassicLength = classicLength;
- mDeviceAddressWithType = deviceAddressWithType;
- mConfirmationHash = confirmationHash;
- mLeDeviceRole = -1; // Satisfy final
- }
-
- /**
- * LE Security Constructor
- */
- private OobData(@NonNull byte[] deviceAddressWithType, @LeRole int leDeviceRole,
- @NonNull byte[] confirmationHash) {
- mDeviceAddressWithType = deviceAddressWithType;
- mLeDeviceRole = leDeviceRole;
- mConfirmationHash = confirmationHash;
- mClassicLength = new byte[OOB_LENGTH_OCTETS]; // Satisfy final
- }
-
- private OobData(Parcel in) {
- // Both
- mDeviceAddressWithType = in.createByteArray();
- mConfirmationHash = in.createByteArray();
- mRandomizerHash = in.createByteArray();
- mDeviceName = in.createByteArray();
-
- // Classic
- mClassicLength = in.createByteArray();
- mClassOfDevice = in.createByteArray();
-
- // LE
- mLeDeviceRole = in.readInt();
- mLeTemporaryKey = in.createByteArray();
- mLeAppearance = in.createByteArray();
- mLeFlags = in.readInt();
- }
-
- /**
- * @hide
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * @hide
- */
- @Override
- public void writeToParcel(@NonNull Parcel out, int flags) {
- // Both
- // Required
- out.writeByteArray(mDeviceAddressWithType);
- // Required
- out.writeByteArray(mConfirmationHash);
- // Optional
- out.writeByteArray(mRandomizerHash);
- // Optional
- out.writeByteArray(mDeviceName);
-
- // Classic
- // Required
- out.writeByteArray(mClassicLength);
- // Optional
- out.writeByteArray(mClassOfDevice);
-
- // LE
- // Required
- out.writeInt(mLeDeviceRole);
- // Required
- out.writeByteArray(mLeTemporaryKey);
- // Optional
- out.writeByteArray(mLeAppearance);
- // Optional
- out.writeInt(mLeFlags);
- }
-
- // For Parcelable
- public static final @android.annotation.NonNull Parcelable.Creator<OobData> CREATOR =
- new Parcelable.Creator<OobData>() {
- public OobData createFromParcel(Parcel in) {
- return new OobData(in);
- }
-
- public OobData[] newArray(int size) {
- return new OobData[size];
- }
- };
-
- /**
- * @return a {@link String} representation of the OobData object.
- *
- * @hide
- */
- @Override
- @NonNull
- public String toString() {
- return "OobData: \n\t"
- // Both
- + "Device Address With Type: " + toHexString(mDeviceAddressWithType) + "\n\t"
- + "Confirmation: " + toHexString(mConfirmationHash) + "\n\t"
- + "Randomizer: " + toHexString(mRandomizerHash) + "\n\t"
- + "Device Name: " + toHexString(mDeviceName) + "\n\t"
- // Classic
- + "OobData Length: " + toHexString(mClassicLength) + "\n\t"
- + "Class of Device: " + toHexString(mClassOfDevice) + "\n\t"
- // LE
- + "LE Device Role: " + toHexString(mLeDeviceRole) + "\n\t"
- + "LE Temporary Key: " + toHexString(mLeTemporaryKey) + "\n\t"
- + "LE Appearance: " + toHexString(mLeAppearance) + "\n\t"
- + "LE Flags: " + toHexString(mLeFlags) + "\n\t";
- }
-
- @NonNull
- private String toHexString(int b) {
- return toHexString(new byte[] {(byte) b});
- }
-
- @NonNull
- private String toHexString(byte b) {
- return toHexString(new byte[] {b});
- }
-
- @NonNull
- private String toHexString(byte[] array) {
- if (array == null) return "null";
- StringBuilder builder = new StringBuilder(array.length * 2);
- for (byte b: array) {
- builder.append(String.format("%02x", b));
- }
- return builder.toString();
- }
-}
diff --git a/core/java/android/bluetooth/SdpDipRecord.java b/core/java/android/bluetooth/SdpDipRecord.java
deleted file mode 100644
index 84b0eef..0000000
--- a/core/java/android/bluetooth/SdpDipRecord.java
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-* Copyright (C) 2015 Samsung System LSI
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package android.bluetooth;
-
-import java.util.Arrays;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Data representation of a Object Push Profile Server side SDP record.
- */
-/** @hide */
-public class SdpDipRecord implements Parcelable {
- private final int mSpecificationId;
- private final int mVendorId;
- private final int mVendorIdSource;
- private final int mProductId;
- private final int mVersion;
- private final boolean mPrimaryRecord;
-
- public SdpDipRecord(int specificationId,
- int vendorId, int vendorIdSource,
- int productId, int version,
- boolean primaryRecord) {
- super();
- this.mSpecificationId = specificationId;
- this.mVendorId = vendorId;
- this.mVendorIdSource = vendorIdSource;
- this.mProductId = productId;
- this.mVersion = version;
- this.mPrimaryRecord = primaryRecord;
- }
-
- public SdpDipRecord(Parcel in) {
- this.mSpecificationId = in.readInt();
- this.mVendorId = in.readInt();
- this.mVendorIdSource = in.readInt();
- this.mProductId = in.readInt();
- this.mVersion = in.readInt();
- this.mPrimaryRecord = in.readBoolean();
- }
-
- public int getSpecificationId() {
- return mSpecificationId;
- }
-
- public int getVendorId() {
- return mVendorId;
- }
-
- public int getVendorIdSource() {
- return mVendorIdSource;
- }
-
- public int getProductId() {
- return mProductId;
- }
-
- public int getVersion() {
- return mVersion;
- }
-
- public boolean getPrimaryRecord() {
- return mPrimaryRecord;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mSpecificationId);
- dest.writeInt(mVendorId);
- dest.writeInt(mVendorIdSource);
- dest.writeInt(mProductId);
- dest.writeInt(mVersion);
- dest.writeBoolean(mPrimaryRecord);
- }
-
- @Override
- public int describeContents() {
- /* No special objects */
- return 0;
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- public SdpDipRecord createFromParcel(Parcel in) {
- return new SdpDipRecord(in);
- }
- public SdpDipRecord[] newArray(int size) {
- return new SdpDipRecord[size];
- }
- };
-}
diff --git a/core/java/android/bluetooth/SdpMasRecord.java b/core/java/android/bluetooth/SdpMasRecord.java
deleted file mode 100644
index 72d4938..0000000
--- a/core/java/android/bluetooth/SdpMasRecord.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
-* Copyright (C) 2015 Samsung System LSI
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public class SdpMasRecord implements Parcelable {
- private final int mMasInstanceId;
- private final int mL2capPsm;
- private final int mRfcommChannelNumber;
- private final int mProfileVersion;
- private final int mSupportedFeatures;
- private final int mSupportedMessageTypes;
- private final String mServiceName;
-
- /** Message type */
- public static final class MessageType {
- public static final int EMAIL = 0x01;
- public static final int SMS_GSM = 0x02;
- public static final int SMS_CDMA = 0x04;
- public static final int MMS = 0x08;
- }
-
- public SdpMasRecord(int masInstanceId,
- int l2capPsm,
- int rfcommChannelNumber,
- int profileVersion,
- int supportedFeatures,
- int supportedMessageTypes,
- String serviceName) {
- mMasInstanceId = masInstanceId;
- mL2capPsm = l2capPsm;
- mRfcommChannelNumber = rfcommChannelNumber;
- mProfileVersion = profileVersion;
- mSupportedFeatures = supportedFeatures;
- mSupportedMessageTypes = supportedMessageTypes;
- mServiceName = serviceName;
- }
-
- public SdpMasRecord(Parcel in) {
- mMasInstanceId = in.readInt();
- mL2capPsm = in.readInt();
- mRfcommChannelNumber = in.readInt();
- mProfileVersion = in.readInt();
- mSupportedFeatures = in.readInt();
- mSupportedMessageTypes = in.readInt();
- mServiceName = in.readString();
- }
-
- @Override
- public int describeContents() {
- // TODO Auto-generated method stub
- return 0;
- }
-
- public int getMasInstanceId() {
- return mMasInstanceId;
- }
-
- public int getL2capPsm() {
- return mL2capPsm;
- }
-
- public int getRfcommCannelNumber() {
- return mRfcommChannelNumber;
- }
-
- public int getProfileVersion() {
- return mProfileVersion;
- }
-
- public int getSupportedFeatures() {
- return mSupportedFeatures;
- }
-
- public int getSupportedMessageTypes() {
- return mSupportedMessageTypes;
- }
-
- public boolean msgSupported(int msg) {
- return (mSupportedMessageTypes & msg) != 0;
- }
-
- public String getServiceName() {
- return mServiceName;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mMasInstanceId);
- dest.writeInt(mL2capPsm);
- dest.writeInt(mRfcommChannelNumber);
- dest.writeInt(mProfileVersion);
- dest.writeInt(mSupportedFeatures);
- dest.writeInt(mSupportedMessageTypes);
- dest.writeString(mServiceName);
- }
-
- @Override
- public String toString() {
- String ret = "Bluetooth MAS SDP Record:\n";
-
- if (mMasInstanceId != -1) {
- ret += "Mas Instance Id: " + mMasInstanceId + "\n";
- }
- if (mRfcommChannelNumber != -1) {
- ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
- }
- if (mL2capPsm != -1) {
- ret += "L2CAP PSM: " + mL2capPsm + "\n";
- }
- if (mServiceName != null) {
- ret += "Service Name: " + mServiceName + "\n";
- }
- if (mProfileVersion != -1) {
- ret += "Profile version: " + mProfileVersion + "\n";
- }
- if (mSupportedMessageTypes != -1) {
- ret += "Supported msg types: " + mSupportedMessageTypes + "\n";
- }
- if (mSupportedFeatures != -1) {
- ret += "Supported features: " + mSupportedFeatures + "\n";
- }
- return ret;
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- public SdpMasRecord createFromParcel(Parcel in) {
- return new SdpMasRecord(in);
- }
-
- public SdpRecord[] newArray(int size) {
- return new SdpRecord[size];
- }
- };
-}
diff --git a/core/java/android/bluetooth/SdpMnsRecord.java b/core/java/android/bluetooth/SdpMnsRecord.java
deleted file mode 100644
index a781d5d..0000000
--- a/core/java/android/bluetooth/SdpMnsRecord.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-* Copyright (C) 2015 Samsung System LSI
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public class SdpMnsRecord implements Parcelable {
- private final int mL2capPsm;
- private final int mRfcommChannelNumber;
- private final int mSupportedFeatures;
- private final int mProfileVersion;
- private final String mServiceName;
-
- public SdpMnsRecord(int l2capPsm,
- int rfcommChannelNumber,
- int profileVersion,
- int supportedFeatures,
- String serviceName) {
- mL2capPsm = l2capPsm;
- mRfcommChannelNumber = rfcommChannelNumber;
- mSupportedFeatures = supportedFeatures;
- mServiceName = serviceName;
- mProfileVersion = profileVersion;
- }
-
- public SdpMnsRecord(Parcel in) {
- mRfcommChannelNumber = in.readInt();
- mL2capPsm = in.readInt();
- mServiceName = in.readString();
- mSupportedFeatures = in.readInt();
- mProfileVersion = in.readInt();
- }
-
- @Override
- public int describeContents() {
- // TODO Auto-generated method stub
- return 0;
- }
-
-
- public int getL2capPsm() {
- return mL2capPsm;
- }
-
- public int getRfcommChannelNumber() {
- return mRfcommChannelNumber;
- }
-
- public int getSupportedFeatures() {
- return mSupportedFeatures;
- }
-
- public String getServiceName() {
- return mServiceName;
- }
-
- public int getProfileVersion() {
- return mProfileVersion;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRfcommChannelNumber);
- dest.writeInt(mL2capPsm);
- dest.writeString(mServiceName);
- dest.writeInt(mSupportedFeatures);
- dest.writeInt(mProfileVersion);
- }
-
- public String toString() {
- String ret = "Bluetooth MNS SDP Record:\n";
-
- if (mRfcommChannelNumber != -1) {
- ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
- }
- if (mL2capPsm != -1) {
- ret += "L2CAP PSM: " + mL2capPsm + "\n";
- }
- if (mServiceName != null) {
- ret += "Service Name: " + mServiceName + "\n";
- }
- if (mSupportedFeatures != -1) {
- ret += "Supported features: " + mSupportedFeatures + "\n";
- }
- if (mProfileVersion != -1) {
- ret += "Profile_version: " + mProfileVersion + "\n";
- }
- return ret;
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- public SdpMnsRecord createFromParcel(Parcel in) {
- return new SdpMnsRecord(in);
- }
-
- public SdpMnsRecord[] newArray(int size) {
- return new SdpMnsRecord[size];
- }
- };
-}
diff --git a/core/java/android/bluetooth/SdpOppOpsRecord.java b/core/java/android/bluetooth/SdpOppOpsRecord.java
deleted file mode 100644
index e30745b8..0000000
--- a/core/java/android/bluetooth/SdpOppOpsRecord.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
-* Copyright (C) 2015 Samsung System LSI
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/**
- * Data representation of a Object Push Profile Server side SDP record.
- */
-
-/** @hide */
-public class SdpOppOpsRecord implements Parcelable {
-
- private final String mServiceName;
- private final int mRfcommChannel;
- private final int mL2capPsm;
- private final int mProfileVersion;
- private final byte[] mFormatsList;
-
- public SdpOppOpsRecord(String serviceName, int rfcommChannel,
- int l2capPsm, int version, byte[] formatsList) {
- super();
- mServiceName = serviceName;
- mRfcommChannel = rfcommChannel;
- mL2capPsm = l2capPsm;
- mProfileVersion = version;
- mFormatsList = formatsList;
- }
-
- public String getServiceName() {
- return mServiceName;
- }
-
- public int getRfcommChannel() {
- return mRfcommChannel;
- }
-
- public int getL2capPsm() {
- return mL2capPsm;
- }
-
- public int getProfileVersion() {
- return mProfileVersion;
- }
-
- public byte[] getFormatsList() {
- return mFormatsList;
- }
-
- @Override
- public int describeContents() {
- /* No special objects */
- return 0;
- }
-
- public SdpOppOpsRecord(Parcel in) {
- mRfcommChannel = in.readInt();
- mL2capPsm = in.readInt();
- mProfileVersion = in.readInt();
- mServiceName = in.readString();
- int arrayLength = in.readInt();
- if (arrayLength > 0) {
- byte[] bytes = new byte[arrayLength];
- in.readByteArray(bytes);
- mFormatsList = bytes;
- } else {
- mFormatsList = null;
- }
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRfcommChannel);
- dest.writeInt(mL2capPsm);
- dest.writeInt(mProfileVersion);
- dest.writeString(mServiceName);
- if (mFormatsList != null && mFormatsList.length > 0) {
- dest.writeInt(mFormatsList.length);
- dest.writeByteArray(mFormatsList);
- } else {
- dest.writeInt(0);
- }
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("Bluetooth OPP Server SDP Record:\n");
- sb.append(" RFCOMM Chan Number: ").append(mRfcommChannel);
- sb.append("\n L2CAP PSM: ").append(mL2capPsm);
- sb.append("\n Profile version: ").append(mProfileVersion);
- sb.append("\n Service Name: ").append(mServiceName);
- sb.append("\n Formats List: ").append(Arrays.toString(mFormatsList));
- return sb.toString();
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- public SdpOppOpsRecord createFromParcel(Parcel in) {
- return new SdpOppOpsRecord(in);
- }
-
- public SdpOppOpsRecord[] newArray(int size) {
- return new SdpOppOpsRecord[size];
- }
- };
-
-}
diff --git a/core/java/android/bluetooth/SdpPseRecord.java b/core/java/android/bluetooth/SdpPseRecord.java
deleted file mode 100644
index 72249d0..0000000
--- a/core/java/android/bluetooth/SdpPseRecord.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
-* Copyright (C) 2015 Samsung System LSI
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public class SdpPseRecord implements Parcelable {
- private final int mL2capPsm;
- private final int mRfcommChannelNumber;
- private final int mProfileVersion;
- private final int mSupportedFeatures;
- private final int mSupportedRepositories;
- private final String mServiceName;
-
- public SdpPseRecord(int l2capPsm,
- int rfcommChannelNumber,
- int profileVersion,
- int supportedFeatures,
- int supportedRepositories,
- String serviceName) {
- mL2capPsm = l2capPsm;
- mRfcommChannelNumber = rfcommChannelNumber;
- mProfileVersion = profileVersion;
- mSupportedFeatures = supportedFeatures;
- mSupportedRepositories = supportedRepositories;
- mServiceName = serviceName;
- }
-
- public SdpPseRecord(Parcel in) {
- mRfcommChannelNumber = in.readInt();
- mL2capPsm = in.readInt();
- mProfileVersion = in.readInt();
- mSupportedFeatures = in.readInt();
- mSupportedRepositories = in.readInt();
- mServiceName = in.readString();
- }
-
- @Override
- public int describeContents() {
- // TODO Auto-generated method stub
- return 0;
- }
-
- public int getL2capPsm() {
- return mL2capPsm;
- }
-
- public int getRfcommChannelNumber() {
- return mRfcommChannelNumber;
- }
-
- public int getSupportedFeatures() {
- return mSupportedFeatures;
- }
-
- public String getServiceName() {
- return mServiceName;
- }
-
- public int getProfileVersion() {
- return mProfileVersion;
- }
-
- public int getSupportedRepositories() {
- return mSupportedRepositories;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRfcommChannelNumber);
- dest.writeInt(mL2capPsm);
- dest.writeInt(mProfileVersion);
- dest.writeInt(mSupportedFeatures);
- dest.writeInt(mSupportedRepositories);
- dest.writeString(mServiceName);
-
- }
-
- @Override
- public String toString() {
- String ret = "Bluetooth MNS SDP Record:\n";
-
- if (mRfcommChannelNumber != -1) {
- ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
- }
- if (mL2capPsm != -1) {
- ret += "L2CAP PSM: " + mL2capPsm + "\n";
- }
- if (mProfileVersion != -1) {
- ret += "profile version: " + mProfileVersion + "\n";
- }
- if (mServiceName != null) {
- ret += "Service Name: " + mServiceName + "\n";
- }
- if (mSupportedFeatures != -1) {
- ret += "Supported features: " + mSupportedFeatures + "\n";
- }
- if (mSupportedRepositories != -1) {
- ret += "Supported repositories: " + mSupportedRepositories + "\n";
- }
-
- return ret;
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- public SdpPseRecord createFromParcel(Parcel in) {
- return new SdpPseRecord(in);
- }
-
- public SdpPseRecord[] newArray(int size) {
- return new SdpPseRecord[size];
- }
- };
-}
diff --git a/core/java/android/bluetooth/SdpRecord.java b/core/java/android/bluetooth/SdpRecord.java
deleted file mode 100644
index 730862e..0000000
--- a/core/java/android/bluetooth/SdpRecord.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* Copyright (C) 2015 Samsung System LSI
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
-
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-
-/** @hide */
-public class SdpRecord implements Parcelable {
-
- private final byte[] mRawData;
- private final int mRawSize;
-
- @Override
- public String toString() {
- return "BluetoothSdpRecord [rawData=" + Arrays.toString(mRawData)
- + ", rawSize=" + mRawSize + "]";
- }
-
- public SdpRecord(int sizeRecord, byte[] record) {
- mRawData = record;
- mRawSize = sizeRecord;
- }
-
- public SdpRecord(Parcel in) {
- mRawSize = in.readInt();
- mRawData = new byte[mRawSize];
- in.readByteArray(mRawData);
-
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRawSize);
- dest.writeByteArray(mRawData);
-
-
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- public SdpRecord createFromParcel(Parcel in) {
- return new SdpRecord(in);
- }
-
- public SdpRecord[] newArray(int size) {
- return new SdpRecord[size];
- }
- };
-
- public byte[] getRawData() {
- return mRawData;
- }
-
- public int getRawSize() {
- return mRawSize;
- }
-}
diff --git a/core/java/android/bluetooth/SdpSapsRecord.java b/core/java/android/bluetooth/SdpSapsRecord.java
deleted file mode 100644
index a1e2f7b..0000000
--- a/core/java/android/bluetooth/SdpSapsRecord.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public class SdpSapsRecord implements Parcelable {
- private final int mRfcommChannelNumber;
- private final int mProfileVersion;
- private final String mServiceName;
-
- public SdpSapsRecord(int rfcommChannelNumber, int profileVersion, String serviceName) {
- mRfcommChannelNumber = rfcommChannelNumber;
- mProfileVersion = profileVersion;
- mServiceName = serviceName;
- }
-
- public SdpSapsRecord(Parcel in) {
- mRfcommChannelNumber = in.readInt();
- mProfileVersion = in.readInt();
- mServiceName = in.readString();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public int getRfcommCannelNumber() {
- return mRfcommChannelNumber;
- }
-
- public int getProfileVersion() {
- return mProfileVersion;
- }
-
- public String getServiceName() {
- return mServiceName;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRfcommChannelNumber);
- dest.writeInt(mProfileVersion);
- dest.writeString(mServiceName);
-
- }
-
- @Override
- public String toString() {
- String ret = "Bluetooth MAS SDP Record:\n";
-
- if (mRfcommChannelNumber != -1) {
- ret += "RFCOMM Chan Number: " + mRfcommChannelNumber + "\n";
- }
- if (mServiceName != null) {
- ret += "Service Name: " + mServiceName + "\n";
- }
- if (mProfileVersion != -1) {
- ret += "Profile version: " + mProfileVersion + "\n";
- }
- return ret;
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- public SdpSapsRecord createFromParcel(Parcel in) {
- return new SdpSapsRecord(in);
- }
-
- public SdpRecord[] newArray(int size) {
- return new SdpRecord[size];
- }
- };
-}
diff --git a/core/java/android/bluetooth/UidTraffic.java b/core/java/android/bluetooth/UidTraffic.java
deleted file mode 100644
index 9982fa61..0000000
--- a/core/java/android/bluetooth/UidTraffic.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.bluetooth;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Record of data traffic (in bytes) by an application identified by its UID.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
-public final class UidTraffic implements Cloneable, Parcelable {
- private final int mAppUid;
- private long mRxBytes;
- private long mTxBytes;
-
- /** @hide */
- public UidTraffic(int appUid, long rx, long tx) {
- mAppUid = appUid;
- mRxBytes = rx;
- mTxBytes = tx;
- }
-
- /** @hide */
- private UidTraffic(Parcel in) {
- mAppUid = in.readInt();
- mRxBytes = in.readLong();
- mTxBytes = in.readLong();
- }
-
- /** @hide */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mAppUid);
- dest.writeLong(mRxBytes);
- dest.writeLong(mTxBytes);
- }
-
- /** @hide */
- public void setRxBytes(long bytes) {
- mRxBytes = bytes;
- }
-
- /** @hide */
- public void setTxBytes(long bytes) {
- mTxBytes = bytes;
- }
-
- /** @hide */
- public void addRxBytes(long bytes) {
- mRxBytes += bytes;
- }
-
- /** @hide */
- public void addTxBytes(long bytes) {
- mTxBytes += bytes;
- }
-
- /**
- * @return corresponding app Uid
- */
- public int getUid() {
- return mAppUid;
- }
-
- /**
- * @return rx bytes count
- */
- public long getRxBytes() {
- return mRxBytes;
- }
-
- /**
- * @return tx bytes count
- */
- public long getTxBytes() {
- return mTxBytes;
- }
-
- /** @hide */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** @hide */
- @Override
- public UidTraffic clone() {
- return new UidTraffic(mAppUid, mRxBytes, mTxBytes);
- }
-
- /** @hide */
- @Override
- public String toString() {
- return "UidTraffic{mAppUid=" + mAppUid + ", mRxBytes=" + mRxBytes + ", mTxBytes="
- + mTxBytes + '}';
- }
-
- public static final @android.annotation.NonNull Creator<UidTraffic> CREATOR = new Creator<UidTraffic>() {
- @Override
- public UidTraffic createFromParcel(Parcel source) {
- return new UidTraffic(source);
- }
-
- @Override
- public UidTraffic[] newArray(int size) {
- return new UidTraffic[size];
- }
- };
-}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java
deleted file mode 100644
index c508c2c..0000000
--- a/core/java/android/bluetooth/annotations/RequiresBluetoothAdvertisePermission.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.Manifest;
-import android.os.Build;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
- * this requires the {@link Manifest.permission#BLUETOOTH_ADVERTISE}
- * permission which can be gained with
- * {@link android.app.Activity#requestPermissions(String[], int)}.
- * @hide
- */
-@Retention(SOURCE)
-@Target({METHOD, FIELD})
-public @interface RequiresBluetoothAdvertisePermission {
-}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java
deleted file mode 100644
index e159eaa..0000000
--- a/core/java/android/bluetooth/annotations/RequiresBluetoothConnectPermission.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.Manifest;
-import android.os.Build;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
- * this requires the {@link Manifest.permission#BLUETOOTH_CONNECT}
- * permission which can be gained with
- * {@link android.app.Activity#requestPermissions(String[], int)}.
- * @hide
- */
-@Retention(SOURCE)
-@Target({METHOD, FIELD})
-public @interface RequiresBluetoothConnectPermission {
-}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java
deleted file mode 100644
index 2bb3204..0000000
--- a/core/java/android/bluetooth/annotations/RequiresBluetoothLocationPermission.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.Manifest;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * @memberDoc In addition, this requires either the
- * {@link Manifest.permission#ACCESS_FINE_LOCATION}
- * permission or a strong assertion that you will never derive the
- * physical location of the device. You can make this assertion by
- * declaring {@code usesPermissionFlags="neverForLocation"} on the
- * relevant {@code <uses-permission>} manifest tag, but it may
- * restrict the types of Bluetooth devices you can interact with.
- * @hide
- */
-@Retention(SOURCE)
-@Target({METHOD, FIELD})
-public @interface RequiresBluetoothLocationPermission {
-}
diff --git a/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java b/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java
deleted file mode 100644
index 800ff39..0000000
--- a/core/java/android/bluetooth/annotations/RequiresBluetoothScanPermission.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.Manifest;
-import android.os.Build;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * @memberDoc For apps targeting {@link Build.VERSION_CODES#S} or or higher,
- * this requires the {@link Manifest.permission#BLUETOOTH_SCAN}
- * permission which can be gained with
- * {@link android.app.Activity#requestPermissions(String[], int)}.
- * @hide
- */
-@Retention(SOURCE)
-@Target({METHOD, FIELD})
-public @interface RequiresBluetoothScanPermission {
-}
diff --git a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java
deleted file mode 100644
index 9adf695..0000000
--- a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothAdminPermission.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.Manifest;
-import android.os.Build;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this
- * requires the {@link Manifest.permission#BLUETOOTH_ADMIN}
- * permission which can be gained with a simple
- * {@code <uses-permission>} manifest tag.
- * @hide
- */
-@Retention(SOURCE)
-@Target({METHOD, FIELD})
-public @interface RequiresLegacyBluetoothAdminPermission {
-}
diff --git a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java b/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java
deleted file mode 100644
index 79621c3..0000000
--- a/core/java/android/bluetooth/annotations/RequiresLegacyBluetoothPermission.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.annotations;
-
-import static java.lang.annotation.ElementType.FIELD;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.Manifest;
-import android.os.Build;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.Target;
-
-/**
- * @memberDoc For apps targeting {@link Build.VERSION_CODES#R} or lower, this
- * requires the {@link Manifest.permission#BLUETOOTH} permission
- * which can be gained with a simple {@code <uses-permission>}
- * manifest tag.
- * @hide
- */
-@Retention(SOURCE)
-@Target({METHOD, FIELD})
-public @interface RequiresLegacyBluetoothPermission {
-}
diff --git a/core/java/android/bluetooth/le/AdvertiseCallback.java b/core/java/android/bluetooth/le/AdvertiseCallback.java
deleted file mode 100644
index 4fa8c4f..0000000
--- a/core/java/android/bluetooth/le/AdvertiseCallback.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-/**
- * Bluetooth LE advertising callbacks, used to deliver advertising operation status.
- */
-public abstract class AdvertiseCallback {
-
- /**
- * The requested operation was successful.
- *
- * @hide
- */
- public static final int ADVERTISE_SUCCESS = 0;
-
- /**
- * Failed to start advertising as the advertise data to be broadcasted is larger than 31 bytes.
- */
- public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1;
-
- /**
- * Failed to start advertising because no advertising instance is available.
- */
- public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2;
-
- /**
- * Failed to start advertising as the advertising is already started.
- */
- public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3;
-
- /**
- * Operation failed due to an internal error.
- */
- public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4;
-
- /**
- * This feature is not supported on this platform.
- */
- public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5;
-
- /**
- * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertising} indicating
- * that the advertising has been started successfully.
- *
- * @param settingsInEffect The actual settings used for advertising, which may be different from
- * what has been requested.
- */
- public void onStartSuccess(AdvertiseSettings settingsInEffect) {
- }
-
- /**
- * Callback when advertising could not be started.
- *
- * @param errorCode Error code (see ADVERTISE_FAILED_* constants) for advertising start
- * failures.
- */
- public void onStartFailure(int errorCode) {
- }
-}
diff --git a/core/java/android/bluetooth/le/AdvertiseData.java b/core/java/android/bluetooth/le/AdvertiseData.java
deleted file mode 100644
index fdf62ec..0000000
--- a/core/java/android/bluetooth/le/AdvertiseData.java
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.os.Parcelable;
-import android.util.ArrayMap;
-import android.util.SparseArray;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * Advertise data packet container for Bluetooth LE advertising. This represents the data to be
- * advertised as well as the scan response data for active scans.
- * <p>
- * Use {@link AdvertiseData.Builder} to create an instance of {@link AdvertiseData} to be
- * advertised.
- *
- * @see BluetoothLeAdvertiser
- * @see ScanRecord
- */
-public final class AdvertiseData implements Parcelable {
-
- @Nullable
- private final List<ParcelUuid> mServiceUuids;
-
- @NonNull
- private final List<ParcelUuid> mServiceSolicitationUuids;
-
- @Nullable
- private final List<TransportDiscoveryData> mTransportDiscoveryData;
-
- private final SparseArray<byte[]> mManufacturerSpecificData;
- private final Map<ParcelUuid, byte[]> mServiceData;
- private final boolean mIncludeTxPowerLevel;
- private final boolean mIncludeDeviceName;
-
- private AdvertiseData(List<ParcelUuid> serviceUuids,
- List<ParcelUuid> serviceSolicitationUuids,
- List<TransportDiscoveryData> transportDiscoveryData,
- SparseArray<byte[]> manufacturerData,
- Map<ParcelUuid, byte[]> serviceData,
- boolean includeTxPowerLevel,
- boolean includeDeviceName) {
- mServiceUuids = serviceUuids;
- mServiceSolicitationUuids = serviceSolicitationUuids;
- mTransportDiscoveryData = transportDiscoveryData;
- mManufacturerSpecificData = manufacturerData;
- mServiceData = serviceData;
- mIncludeTxPowerLevel = includeTxPowerLevel;
- mIncludeDeviceName = includeDeviceName;
- }
-
- /**
- * Returns a list of service UUIDs within the advertisement that are used to identify the
- * Bluetooth GATT services.
- */
- public List<ParcelUuid> getServiceUuids() {
- return mServiceUuids;
- }
-
- /**
- * Returns a list of service solicitation UUIDs within the advertisement that we invite to connect.
- */
- @NonNull
- public List<ParcelUuid> getServiceSolicitationUuids() {
- return mServiceSolicitationUuids;
- }
-
- /**
- * Returns a list of {@link TransportDiscoveryData} within the advertisement.
- */
- @NonNull
- public List<TransportDiscoveryData> getTransportDiscoveryData() {
- if (mTransportDiscoveryData == null) {
- return Collections.emptyList();
- }
- return mTransportDiscoveryData;
- }
-
- /**
- * Returns an array of manufacturer Id and the corresponding manufacturer specific data. The
- * manufacturer id is a non-negative number assigned by Bluetooth SIG.
- */
- public SparseArray<byte[]> getManufacturerSpecificData() {
- return mManufacturerSpecificData;
- }
-
- /**
- * Returns a map of 16-bit UUID and its corresponding service data.
- */
- public Map<ParcelUuid, byte[]> getServiceData() {
- return mServiceData;
- }
-
- /**
- * Whether the transmission power level will be included in the advertisement packet.
- */
- public boolean getIncludeTxPowerLevel() {
- return mIncludeTxPowerLevel;
- }
-
- /**
- * Whether the device name will be included in the advertisement packet.
- */
- public boolean getIncludeDeviceName() {
- return mIncludeDeviceName;
- }
-
- /**
- * @hide
- */
- @Override
- public int hashCode() {
- return Objects.hash(mServiceUuids, mServiceSolicitationUuids, mTransportDiscoveryData,
- mManufacturerSpecificData, mServiceData, mIncludeDeviceName, mIncludeTxPowerLevel);
- }
-
- /**
- * @hide
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- AdvertiseData other = (AdvertiseData) obj;
- return Objects.equals(mServiceUuids, other.mServiceUuids)
- && Objects.equals(mServiceSolicitationUuids, other.mServiceSolicitationUuids)
- && Objects.equals(mTransportDiscoveryData, other.mTransportDiscoveryData)
- && BluetoothLeUtils.equals(mManufacturerSpecificData,
- other.mManufacturerSpecificData)
- && BluetoothLeUtils.equals(mServiceData, other.mServiceData)
- && mIncludeDeviceName == other.mIncludeDeviceName
- && mIncludeTxPowerLevel == other.mIncludeTxPowerLevel;
- }
-
- @Override
- public String toString() {
- return "AdvertiseData [mServiceUuids=" + mServiceUuids + ", mServiceSolicitationUuids="
- + mServiceSolicitationUuids + ", mTransportDiscoveryData="
- + mTransportDiscoveryData + ", mManufacturerSpecificData="
- + BluetoothLeUtils.toString(mManufacturerSpecificData) + ", mServiceData="
- + BluetoothLeUtils.toString(mServiceData)
- + ", mIncludeTxPowerLevel=" + mIncludeTxPowerLevel + ", mIncludeDeviceName="
- + mIncludeDeviceName + "]";
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeTypedArray(mServiceUuids.toArray(new ParcelUuid[mServiceUuids.size()]), flags);
- dest.writeTypedArray(mServiceSolicitationUuids.toArray(
- new ParcelUuid[mServiceSolicitationUuids.size()]), flags);
-
- dest.writeTypedList(mTransportDiscoveryData);
-
- // mManufacturerSpecificData could not be null.
- dest.writeInt(mManufacturerSpecificData.size());
- for (int i = 0; i < mManufacturerSpecificData.size(); ++i) {
- dest.writeInt(mManufacturerSpecificData.keyAt(i));
- dest.writeByteArray(mManufacturerSpecificData.valueAt(i));
- }
- dest.writeInt(mServiceData.size());
- for (ParcelUuid uuid : mServiceData.keySet()) {
- dest.writeTypedObject(uuid, flags);
- dest.writeByteArray(mServiceData.get(uuid));
- }
- dest.writeByte((byte) (getIncludeTxPowerLevel() ? 1 : 0));
- dest.writeByte((byte) (getIncludeDeviceName() ? 1 : 0));
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<AdvertiseData> CREATOR =
- new Creator<AdvertiseData>() {
- @Override
- public AdvertiseData[] newArray(int size) {
- return new AdvertiseData[size];
- }
-
- @Override
- public AdvertiseData createFromParcel(Parcel in) {
- Builder builder = new Builder();
- ArrayList<ParcelUuid> uuids = in.createTypedArrayList(ParcelUuid.CREATOR);
- for (ParcelUuid uuid : uuids) {
- builder.addServiceUuid(uuid);
- }
-
- ArrayList<ParcelUuid> solicitationUuids = in.createTypedArrayList(ParcelUuid.CREATOR);
- for (ParcelUuid uuid : solicitationUuids) {
- builder.addServiceSolicitationUuid(uuid);
- }
-
- List<TransportDiscoveryData> transportDiscoveryData =
- in.createTypedArrayList(TransportDiscoveryData.CREATOR);
- for (TransportDiscoveryData tdd : transportDiscoveryData) {
- builder.addTransportDiscoveryData(tdd);
- }
-
- int manufacturerSize = in.readInt();
- for (int i = 0; i < manufacturerSize; ++i) {
- int manufacturerId = in.readInt();
- byte[] manufacturerData = in.createByteArray();
- builder.addManufacturerData(manufacturerId, manufacturerData);
- }
- int serviceDataSize = in.readInt();
- for (int i = 0; i < serviceDataSize; ++i) {
- ParcelUuid serviceDataUuid = in.readTypedObject(ParcelUuid.CREATOR);
- byte[] serviceData = in.createByteArray();
- builder.addServiceData(serviceDataUuid, serviceData);
- }
- builder.setIncludeTxPowerLevel(in.readByte() == 1);
- builder.setIncludeDeviceName(in.readByte() == 1);
- return builder.build();
- }
- };
-
- /**
- * Builder for {@link AdvertiseData}.
- */
- public static final class Builder {
- @Nullable
- private List<ParcelUuid> mServiceUuids = new ArrayList<ParcelUuid>();
- @NonNull
- private List<ParcelUuid> mServiceSolicitationUuids = new ArrayList<ParcelUuid>();
- @Nullable
- private List<TransportDiscoveryData> mTransportDiscoveryData =
- new ArrayList<TransportDiscoveryData>();
- private SparseArray<byte[]> mManufacturerSpecificData = new SparseArray<byte[]>();
- private Map<ParcelUuid, byte[]> mServiceData = new ArrayMap<ParcelUuid, byte[]>();
- private boolean mIncludeTxPowerLevel;
- private boolean mIncludeDeviceName;
-
- /**
- * Add a service UUID to advertise data.
- *
- * @param serviceUuid A service UUID to be advertised.
- * @throws IllegalArgumentException If the {@code serviceUuid} is null.
- */
- public Builder addServiceUuid(ParcelUuid serviceUuid) {
- if (serviceUuid == null) {
- throw new IllegalArgumentException("serviceUuid is null");
- }
- mServiceUuids.add(serviceUuid);
- return this;
- }
-
- /**
- * Add a service solicitation UUID to advertise data.
- *
- * @param serviceSolicitationUuid A service solicitation UUID to be advertised.
- * @throws IllegalArgumentException If the {@code serviceSolicitationUuid} is null.
- */
- @NonNull
- public Builder addServiceSolicitationUuid(@NonNull ParcelUuid serviceSolicitationUuid) {
- if (serviceSolicitationUuid == null) {
- throw new IllegalArgumentException("serviceSolicitationUuid is null");
- }
- mServiceSolicitationUuids.add(serviceSolicitationUuid);
- return this;
- }
-
- /**
- * Add service data to advertise data.
- *
- * @param serviceDataUuid 16-bit UUID of the service the data is associated with
- * @param serviceData Service data
- * @throws IllegalArgumentException If the {@code serviceDataUuid} or {@code serviceData} is
- * empty.
- */
- public Builder addServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) {
- if (serviceDataUuid == null || serviceData == null) {
- throw new IllegalArgumentException(
- "serviceDataUuid or serviceDataUuid is null");
- }
- mServiceData.put(serviceDataUuid, serviceData);
- return this;
- }
-
- /**
- * Add Transport Discovery Data to advertise data.
- *
- * @param transportDiscoveryData Transport Discovery Data, consisting of one or more
- * Transport Blocks. Transport Discovery Data AD Type Code is already included.
- * @throws IllegalArgumentException If the {@code transportDiscoveryData} is empty
- */
- @NonNull
- public Builder addTransportDiscoveryData(
- @NonNull TransportDiscoveryData transportDiscoveryData) {
- if (transportDiscoveryData == null) {
- throw new IllegalArgumentException("transportDiscoveryData is null");
- }
- mTransportDiscoveryData.add(transportDiscoveryData);
- return this;
- }
-
- /**
- * Add manufacturer specific data.
- * <p>
- * Please refer to the Bluetooth Assigned Numbers document provided by the <a
- * href="https://www.bluetooth.org">Bluetooth SIG</a> for a list of existing company
- * identifiers.
- *
- * @param manufacturerId Manufacturer ID assigned by Bluetooth SIG.
- * @param manufacturerSpecificData Manufacturer specific data
- * @throws IllegalArgumentException If the {@code manufacturerId} is negative or {@code
- * manufacturerSpecificData} is null.
- */
- public Builder addManufacturerData(int manufacturerId, byte[] manufacturerSpecificData) {
- if (manufacturerId < 0) {
- throw new IllegalArgumentException(
- "invalid manufacturerId - " + manufacturerId);
- }
- if (manufacturerSpecificData == null) {
- throw new IllegalArgumentException("manufacturerSpecificData is null");
- }
- mManufacturerSpecificData.put(manufacturerId, manufacturerSpecificData);
- return this;
- }
-
- /**
- * Whether the transmission power level should be included in the advertise packet. Tx power
- * level field takes 3 bytes in advertise packet.
- */
- public Builder setIncludeTxPowerLevel(boolean includeTxPowerLevel) {
- mIncludeTxPowerLevel = includeTxPowerLevel;
- return this;
- }
-
- /**
- * Set whether the device name should be included in advertise packet.
- */
- public Builder setIncludeDeviceName(boolean includeDeviceName) {
- mIncludeDeviceName = includeDeviceName;
- return this;
- }
-
- /**
- * Build the {@link AdvertiseData}.
- */
- public AdvertiseData build() {
- return new AdvertiseData(mServiceUuids, mServiceSolicitationUuids,
- mTransportDiscoveryData, mManufacturerSpecificData, mServiceData,
- mIncludeTxPowerLevel, mIncludeDeviceName);
- }
- }
-}
diff --git a/core/java/android/bluetooth/le/AdvertiseSettings.java b/core/java/android/bluetooth/le/AdvertiseSettings.java
deleted file mode 100644
index c52a6ee..0000000
--- a/core/java/android/bluetooth/le/AdvertiseSettings.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.bluetooth.le.AdvertisingSetParameters.AddressTypeStatus;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * The {@link AdvertiseSettings} provide a way to adjust advertising preferences for each
- * Bluetooth LE advertisement instance. Use {@link AdvertiseSettings.Builder} to create an
- * instance of this class.
- */
-public final class AdvertiseSettings implements Parcelable {
- /**
- * Perform Bluetooth LE advertising in low power mode. This is the default and preferred
- * advertising mode as it consumes the least power.
- */
- public static final int ADVERTISE_MODE_LOW_POWER = 0;
-
- /**
- * Perform Bluetooth LE advertising in balanced power mode. This is balanced between advertising
- * frequency and power consumption.
- */
- public static final int ADVERTISE_MODE_BALANCED = 1;
-
- /**
- * Perform Bluetooth LE advertising in low latency, high power mode. This has the highest power
- * consumption and should not be used for continuous background advertising.
- */
- public static final int ADVERTISE_MODE_LOW_LATENCY = 2;
-
- /**
- * Advertise using the lowest transmission (TX) power level. Low transmission power can be used
- * to restrict the visibility range of advertising packets.
- */
- public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0;
-
- /**
- * Advertise using low TX power level.
- */
- public static final int ADVERTISE_TX_POWER_LOW = 1;
-
- /**
- * Advertise using medium TX power level.
- */
- public static final int ADVERTISE_TX_POWER_MEDIUM = 2;
-
- /**
- * Advertise using high TX power level. This corresponds to largest visibility range of the
- * advertising packet.
- */
- public static final int ADVERTISE_TX_POWER_HIGH = 3;
-
- /**
- * The maximum limited advertisement duration as specified by the Bluetooth SIG
- */
- private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000;
-
-
- private final int mAdvertiseMode;
- private final int mAdvertiseTxPowerLevel;
- private final int mAdvertiseTimeoutMillis;
- private final boolean mAdvertiseConnectable;
- private final int mOwnAddressType;
-
- private AdvertiseSettings(int advertiseMode, int advertiseTxPowerLevel,
- boolean advertiseConnectable, int advertiseTimeout,
- @AddressTypeStatus int ownAddressType) {
- mAdvertiseMode = advertiseMode;
- mAdvertiseTxPowerLevel = advertiseTxPowerLevel;
- mAdvertiseConnectable = advertiseConnectable;
- mAdvertiseTimeoutMillis = advertiseTimeout;
- mOwnAddressType = ownAddressType;
- }
-
- private AdvertiseSettings(Parcel in) {
- mAdvertiseMode = in.readInt();
- mAdvertiseTxPowerLevel = in.readInt();
- mAdvertiseConnectable = in.readInt() != 0;
- mAdvertiseTimeoutMillis = in.readInt();
- mOwnAddressType = in.readInt();
- }
-
- /**
- * Returns the advertise mode.
- */
- public int getMode() {
- return mAdvertiseMode;
- }
-
- /**
- * Returns the TX power level for advertising.
- */
- public int getTxPowerLevel() {
- return mAdvertiseTxPowerLevel;
- }
-
- /**
- * Returns whether the advertisement will indicate connectable.
- */
- public boolean isConnectable() {
- return mAdvertiseConnectable;
- }
-
- /**
- * Returns the advertising time limit in milliseconds.
- */
- public int getTimeout() {
- return mAdvertiseTimeoutMillis;
- }
-
- /**
- * @return the own address type for advertising
- *
- * @hide
- */
- @SystemApi
- public @AddressTypeStatus int getOwnAddressType() {
- return mOwnAddressType;
- }
-
- @Override
- public String toString() {
- return "Settings [mAdvertiseMode=" + mAdvertiseMode
- + ", mAdvertiseTxPowerLevel=" + mAdvertiseTxPowerLevel
- + ", mAdvertiseConnectable=" + mAdvertiseConnectable
- + ", mAdvertiseTimeoutMillis=" + mAdvertiseTimeoutMillis
- + ", mOwnAddressType=" + mOwnAddressType + "]";
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mAdvertiseMode);
- dest.writeInt(mAdvertiseTxPowerLevel);
- dest.writeInt(mAdvertiseConnectable ? 1 : 0);
- dest.writeInt(mAdvertiseTimeoutMillis);
- dest.writeInt(mOwnAddressType);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<AdvertiseSettings> CREATOR =
- new Creator<AdvertiseSettings>() {
- @Override
- public AdvertiseSettings[] newArray(int size) {
- return new AdvertiseSettings[size];
- }
-
- @Override
- public AdvertiseSettings createFromParcel(Parcel in) {
- return new AdvertiseSettings(in);
- }
- };
-
- /**
- * Builder class for {@link AdvertiseSettings}.
- */
- public static final class Builder {
- private int mMode = ADVERTISE_MODE_LOW_POWER;
- private int mTxPowerLevel = ADVERTISE_TX_POWER_MEDIUM;
- private int mTimeoutMillis = 0;
- private boolean mConnectable = true;
- private int mOwnAddressType = AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT;
-
- /**
- * Set advertise mode to control the advertising power and latency.
- *
- * @param advertiseMode Bluetooth LE Advertising mode, can only be one of {@link
- * AdvertiseSettings#ADVERTISE_MODE_LOW_POWER},
- * {@link AdvertiseSettings#ADVERTISE_MODE_BALANCED},
- * or {@link AdvertiseSettings#ADVERTISE_MODE_LOW_LATENCY}.
- * @throws IllegalArgumentException If the advertiseMode is invalid.
- */
- public Builder setAdvertiseMode(int advertiseMode) {
- if (advertiseMode < ADVERTISE_MODE_LOW_POWER
- || advertiseMode > ADVERTISE_MODE_LOW_LATENCY) {
- throw new IllegalArgumentException("unknown mode " + advertiseMode);
- }
- mMode = advertiseMode;
- return this;
- }
-
- /**
- * Set advertise TX power level to control the transmission power level for the advertising.
- *
- * @param txPowerLevel Transmission power of Bluetooth LE Advertising, can only be one of
- * {@link AdvertiseSettings#ADVERTISE_TX_POWER_ULTRA_LOW}, {@link
- * AdvertiseSettings#ADVERTISE_TX_POWER_LOW},
- * {@link AdvertiseSettings#ADVERTISE_TX_POWER_MEDIUM}
- * or {@link AdvertiseSettings#ADVERTISE_TX_POWER_HIGH}.
- * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid.
- */
- public Builder setTxPowerLevel(int txPowerLevel) {
- if (txPowerLevel < ADVERTISE_TX_POWER_ULTRA_LOW
- || txPowerLevel > ADVERTISE_TX_POWER_HIGH) {
- throw new IllegalArgumentException("unknown tx power level " + txPowerLevel);
- }
- mTxPowerLevel = txPowerLevel;
- return this;
- }
-
- /**
- * Set whether the advertisement type should be connectable or non-connectable.
- *
- * @param connectable Controls whether the advertisment type will be connectable (true) or
- * non-connectable (false).
- */
- public Builder setConnectable(boolean connectable) {
- mConnectable = connectable;
- return this;
- }
-
- /**
- * Limit advertising to a given amount of time.
- *
- * @param timeoutMillis Advertising time limit. May not exceed 180000 milliseconds. A value
- * of 0 will disable the time limit.
- * @throws IllegalArgumentException If the provided timeout is over 180000 ms.
- */
- public Builder setTimeout(int timeoutMillis) {
- if (timeoutMillis < 0 || timeoutMillis > LIMITED_ADVERTISING_MAX_MILLIS) {
- throw new IllegalArgumentException("timeoutMillis invalid (must be 0-"
- + LIMITED_ADVERTISING_MAX_MILLIS + " milliseconds)");
- }
- mTimeoutMillis = timeoutMillis;
- return this;
- }
-
- /**
- * Set own address type for advertising to control public or privacy mode. If used to set
- * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT},
- * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the
- * time of starting advertising.
- *
- * @throws IllegalArgumentException If the {@code ownAddressType} is invalid
- *
- * @hide
- */
- @SystemApi
- public @NonNull Builder setOwnAddressType(@AddressTypeStatus int ownAddressType) {
- if (ownAddressType < AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT
- || ownAddressType > AdvertisingSetParameters.ADDRESS_TYPE_RANDOM) {
- throw new IllegalArgumentException("unknown address type " + ownAddressType);
- }
- mOwnAddressType = ownAddressType;
- return this;
- }
-
- /**
- * Build the {@link AdvertiseSettings} object.
- */
- public AdvertiseSettings build() {
- return new AdvertiseSettings(mMode, mTxPowerLevel, mConnectable, mTimeoutMillis,
- mOwnAddressType);
- }
- }
-}
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
deleted file mode 100644
index bbdb695..0000000
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothManager;
-import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.content.AttributionSource;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * This class provides a way to control single Bluetooth LE advertising instance.
- * <p>
- * To get an instance of {@link AdvertisingSet}, call the
- * {@link BluetoothLeAdvertiser#startAdvertisingSet} method.
- *
- * @see AdvertiseData
- */
-public final class AdvertisingSet {
- private static final String TAG = "AdvertisingSet";
-
- private final IBluetoothGatt mGatt;
- private int mAdvertiserId;
- private AttributionSource mAttributionSource;
-
- /* package */ AdvertisingSet(int advertiserId, IBluetoothManager bluetoothManager,
- AttributionSource attributionSource) {
- mAdvertiserId = advertiserId;
- mAttributionSource = attributionSource;
- try {
- mGatt = bluetoothManager.getBluetoothGatt();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
- throw new IllegalStateException("Failed to get Bluetooth");
- }
- }
-
- /* package */ void setAdvertiserId(int advertiserId) {
- mAdvertiserId = advertiserId;
- }
-
- /**
- * Enables Advertising. This method returns immediately, the operation status is
- * delivered through {@code callback.onAdvertisingEnabled()}.
- *
- * @param enable whether the advertising should be enabled (true), or disabled (false)
- * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535
- * (655,350 ms)
- * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the
- * controller shall attempt to send prior to terminating the extended advertising, even if the
- * duration has not expired. Valid range is from 1 to 255.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void enableAdvertising(boolean enable, int duration,
- int maxExtendedAdvertisingEvents) {
- try {
- mGatt.enableAdvertisingSet(mAdvertiserId, enable, duration,
- maxExtendedAdvertisingEvents, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception - ", e);
- }
- }
-
- /**
- * Set/update data being Advertised. Make sure that data doesn't exceed the size limit for
- * specified AdvertisingSetParameters. This method returns immediately, the operation status is
- * delivered through {@code callback.onAdvertisingDataSet()}.
- * <p>
- * Advertising data must be empty if non-legacy scannable advertising is used.
- *
- * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable,
- * three bytes will be added for flags. If the update takes place when the advertising set is
- * enabled, the data can be maximum 251 bytes long.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void setAdvertisingData(AdvertiseData advertiseData) {
- try {
- mGatt.setAdvertisingData(mAdvertiserId, advertiseData, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception - ", e);
- }
- }
-
- /**
- * Set/update scan response data. Make sure that data doesn't exceed the size limit for
- * specified AdvertisingSetParameters. This method returns immediately, the operation status
- * is delivered through {@code callback.onScanResponseDataSet()}.
- *
- * @param scanResponse Scan response associated with the advertisement data. Size must not
- * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place
- * when the advertising set is enabled, the data can be maximum 251 bytes long.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void setScanResponseData(AdvertiseData scanResponse) {
- try {
- mGatt.setScanResponseData(mAdvertiserId, scanResponse, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception - ", e);
- }
- }
-
- /**
- * Update advertising parameters associated with this AdvertisingSet. Must be called when
- * advertising is not active. This method returns immediately, the operation status is delivered
- * through {@code callback.onAdvertisingParametersUpdated}.
- *
- * @param parameters advertising set parameters.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void setAdvertisingParameters(AdvertisingSetParameters parameters) {
- try {
- mGatt.setAdvertisingParameters(mAdvertiserId, parameters, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception - ", e);
- }
- }
-
- /**
- * Update periodic advertising parameters associated with this set. Must be called when
- * periodic advertising is not enabled. This method returns immediately, the operation
- * status is delivered through {@code callback.onPeriodicAdvertisingParametersUpdated()}.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void setPeriodicAdvertisingParameters(PeriodicAdvertisingParameters parameters) {
- try {
- mGatt.setPeriodicAdvertisingParameters(mAdvertiserId, parameters, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception - ", e);
- }
- }
-
- /**
- * Used to set periodic advertising data, must be called after setPeriodicAdvertisingParameters,
- * or after advertising was started with periodic advertising data set. This method returns
- * immediately, the operation status is delivered through
- * {@code callback.onPeriodicAdvertisingDataSet()}.
- *
- * @param periodicData Periodic advertising data. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the update takes place when the
- * periodic advertising is enabled for this set, the data can be maximum 251 bytes long.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void setPeriodicAdvertisingData(AdvertiseData periodicData) {
- try {
- mGatt.setPeriodicAdvertisingData(mAdvertiserId, periodicData, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception - ", e);
- }
- }
-
- /**
- * Used to enable/disable periodic advertising. This method returns immediately, the operation
- * status is delivered through {@code callback.onPeriodicAdvertisingEnable()}.
- *
- * @param enable whether the periodic advertising should be enabled (true), or disabled
- * (false).
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void setPeriodicAdvertisingEnabled(boolean enable) {
- try {
- mGatt.setPeriodicAdvertisingEnable(mAdvertiserId, enable, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception - ", e);
- }
- }
-
- /**
- * Returns address associated with this advertising set.
- * This method is exposed only for Bluetooth PTS tests, no app or system service
- * should ever use it.
- *
- * @hide
- */
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_ADVERTISE,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- public void getOwnAddress() {
- try {
- mGatt.getOwnAddress(mAdvertiserId, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "remote exception - ", e);
- }
- }
-
- /**
- * Returns advertiserId associated with this advertising set.
- *
- * @hide
- */
- @RequiresNoPermission
- public int getAdvertiserId() {
- return mAdvertiserId;
- }
-}
diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
deleted file mode 100644
index 51324fd..0000000
--- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-/**
- * Bluetooth LE advertising set callbacks, used to deliver advertising operation
- * status.
- */
-public abstract class AdvertisingSetCallback {
-
- /**
- * The requested operation was successful.
- */
- public static final int ADVERTISE_SUCCESS = 0;
-
- /**
- * Failed to start advertising as the advertise data to be broadcasted is too
- * large.
- */
- public static final int ADVERTISE_FAILED_DATA_TOO_LARGE = 1;
-
- /**
- * Failed to start advertising because no advertising instance is available.
- */
- public static final int ADVERTISE_FAILED_TOO_MANY_ADVERTISERS = 2;
-
- /**
- * Failed to start advertising as the advertising is already started.
- */
- public static final int ADVERTISE_FAILED_ALREADY_STARTED = 3;
-
- /**
- * Operation failed due to an internal error.
- */
- public static final int ADVERTISE_FAILED_INTERNAL_ERROR = 4;
-
- /**
- * This feature is not supported on this platform.
- */
- public static final int ADVERTISE_FAILED_FEATURE_UNSUPPORTED = 5;
-
- /**
- * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}
- * indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertisingSet
- * contains the started set and it is advertising. If error occurred, advertisingSet is
- * null, and status will be set to proper error code.
- *
- * @param advertisingSet The advertising set that was started or null if error.
- * @param txPower tx power that will be used for this set.
- * @param status Status of the operation.
- */
- public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower, int status) {
- }
-
- /**
- * Callback triggered in response to {@link BluetoothLeAdvertiser#stopAdvertisingSet}
- * indicating advertising set is stopped.
- *
- * @param advertisingSet The advertising set.
- */
- public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
- }
-
- /**
- * Callback triggered in response to {@link BluetoothLeAdvertiser#startAdvertisingSet}
- * indicating result of the operation. If status is ADVERTISE_SUCCESS, then advertising set is
- * advertising.
- *
- * @param advertisingSet The advertising set.
- * @param status Status of the operation.
- */
- public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable, int status) {
- }
-
- /**
- * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating
- * result of the operation. If status is ADVERTISE_SUCCESS, then data was changed.
- *
- * @param advertisingSet The advertising set.
- * @param status Status of the operation.
- */
- public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
- }
-
- /**
- * Callback triggered in response to {@link AdvertisingSet#setAdvertisingData} indicating
- * result of the operation.
- *
- * @param advertisingSet The advertising set.
- * @param status Status of the operation.
- */
- public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
- }
-
- /**
- * Callback triggered in response to {@link AdvertisingSet#setAdvertisingParameters}
- * indicating result of the operation.
- *
- * @param advertisingSet The advertising set.
- * @param txPower tx power that will be used for this set.
- * @param status Status of the operation.
- */
- public void onAdvertisingParametersUpdated(AdvertisingSet advertisingSet,
- int txPower, int status) {
- }
-
- /**
- * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingParameters}
- * indicating result of the operation.
- *
- * @param advertisingSet The advertising set.
- * @param status Status of the operation.
- */
- public void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet, int status) {
- }
-
- /**
- * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingData}
- * indicating result of the operation.
- *
- * @param advertisingSet The advertising set.
- * @param status Status of the operation.
- */
- public void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet,
- int status) {
- }
-
- /**
- * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnabled}
- * indicating result of the operation.
- *
- * @param advertisingSet The advertising set.
- * @param status Status of the operation.
- */
- public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
- int status) {
- }
-
- /**
- * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()}
- * indicating result of the operation.
- *
- * @param advertisingSet The advertising set.
- * @param addressType type of address.
- * @param address advertising set bluetooth address.
- * @hide
- */
- public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) {
- }
-}
diff --git a/core/java/android/bluetooth/le/AdvertisingSetParameters.java b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
deleted file mode 100644
index 5c8fae6..0000000
--- a/core/java/android/bluetooth/le/AdvertisingSetParameters.java
+++ /dev/null
@@ -1,513 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * The {@link AdvertisingSetParameters} provide a way to adjust advertising
- * preferences for each
- * Bluetooth LE advertising set. Use {@link AdvertisingSetParameters.Builder} to
- * create an
- * instance of this class.
- */
-public final class AdvertisingSetParameters implements Parcelable {
-
- /**
- * Advertise on low frequency, around every 1000ms. This is the default and
- * preferred advertising mode as it consumes the least power.
- */
- public static final int INTERVAL_HIGH = 1600;
-
- /**
- * Advertise on medium frequency, around every 250ms. This is balanced
- * between advertising frequency and power consumption.
- */
- public static final int INTERVAL_MEDIUM = 400;
-
- /**
- * Perform high frequency, low latency advertising, around every 100ms. This
- * has the highest power consumption and should not be used for continuous
- * background advertising.
- */
- public static final int INTERVAL_LOW = 160;
-
- /**
- * Minimum value for advertising interval.
- */
- public static final int INTERVAL_MIN = 160;
-
- /**
- * Maximum value for advertising interval.
- */
- public static final int INTERVAL_MAX = 16777215;
-
- /**
- * Advertise using the lowest transmission (TX) power level. Low transmission
- * power can be used to restrict the visibility range of advertising packets.
- */
- public static final int TX_POWER_ULTRA_LOW = -21;
-
- /**
- * Advertise using low TX power level.
- */
- public static final int TX_POWER_LOW = -15;
-
- /**
- * Advertise using medium TX power level.
- */
- public static final int TX_POWER_MEDIUM = -7;
-
- /**
- * Advertise using high TX power level. This corresponds to largest visibility
- * range of the advertising packet.
- */
- public static final int TX_POWER_HIGH = 1;
-
- /**
- * Minimum value for TX power.
- */
- public static final int TX_POWER_MIN = -127;
-
- /**
- * Maximum value for TX power.
- */
- public static final int TX_POWER_MAX = 1;
-
- /**
- * The maximum limited advertisement duration as specified by the Bluetooth
- * SIG
- */
- private static final int LIMITED_ADVERTISING_MAX_MILLIS = 180 * 1000;
-
- /** @hide */
- @IntDef(prefix = "ADDRESS_TYPE_", value = {
- ADDRESS_TYPE_DEFAULT,
- ADDRESS_TYPE_PUBLIC,
- ADDRESS_TYPE_RANDOM
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AddressTypeStatus {}
-
- /**
- * Advertise own address type that corresponds privacy settings of the device.
- *
- * @hide
- */
- @SystemApi
- public static final int ADDRESS_TYPE_DEFAULT = -1;
-
- /**
- * Advertise own public address type.
- *
- * @hide
- */
- @SystemApi
- public static final int ADDRESS_TYPE_PUBLIC = 0;
-
- /**
- * Generate and adverise own resolvable private address.
- *
- * @hide
- */
- @SystemApi
- public static final int ADDRESS_TYPE_RANDOM = 1;
-
- private final boolean mIsLegacy;
- private final boolean mIsAnonymous;
- private final boolean mIncludeTxPower;
- private final int mPrimaryPhy;
- private final int mSecondaryPhy;
- private final boolean mConnectable;
- private final boolean mScannable;
- private final int mInterval;
- private final int mTxPowerLevel;
- private final int mOwnAddressType;
-
- private AdvertisingSetParameters(boolean connectable, boolean scannable, boolean isLegacy,
- boolean isAnonymous, boolean includeTxPower,
- int primaryPhy, int secondaryPhy,
- int interval, int txPowerLevel, @AddressTypeStatus int ownAddressType) {
- mConnectable = connectable;
- mScannable = scannable;
- mIsLegacy = isLegacy;
- mIsAnonymous = isAnonymous;
- mIncludeTxPower = includeTxPower;
- mPrimaryPhy = primaryPhy;
- mSecondaryPhy = secondaryPhy;
- mInterval = interval;
- mTxPowerLevel = txPowerLevel;
- mOwnAddressType = ownAddressType;
- }
-
- private AdvertisingSetParameters(Parcel in) {
- mConnectable = in.readInt() != 0;
- mScannable = in.readInt() != 0;
- mIsLegacy = in.readInt() != 0;
- mIsAnonymous = in.readInt() != 0;
- mIncludeTxPower = in.readInt() != 0;
- mPrimaryPhy = in.readInt();
- mSecondaryPhy = in.readInt();
- mInterval = in.readInt();
- mTxPowerLevel = in.readInt();
- mOwnAddressType = in.readInt();
- }
-
- /**
- * Returns whether the advertisement will be connectable.
- */
- public boolean isConnectable() {
- return mConnectable;
- }
-
- /**
- * Returns whether the advertisement will be scannable.
- */
- public boolean isScannable() {
- return mScannable;
- }
-
- /**
- * Returns whether the legacy advertisement will be used.
- */
- public boolean isLegacy() {
- return mIsLegacy;
- }
-
- /**
- * Returns whether the advertisement will be anonymous.
- */
- public boolean isAnonymous() {
- return mIsAnonymous;
- }
-
- /**
- * Returns whether the TX Power will be included.
- */
- public boolean includeTxPower() {
- return mIncludeTxPower;
- }
-
- /**
- * Returns the primary advertising phy.
- */
- public int getPrimaryPhy() {
- return mPrimaryPhy;
- }
-
- /**
- * Returns the secondary advertising phy.
- */
- public int getSecondaryPhy() {
- return mSecondaryPhy;
- }
-
- /**
- * Returns the advertising interval.
- */
- public int getInterval() {
- return mInterval;
- }
-
- /**
- * Returns the TX power level for advertising.
- */
- public int getTxPowerLevel() {
- return mTxPowerLevel;
- }
-
- /**
- * @return the own address type for advertising
- *
- * @hide
- */
- @SystemApi
- public @AddressTypeStatus int getOwnAddressType() {
- return mOwnAddressType;
- }
-
- @Override
- public String toString() {
- return "AdvertisingSetParameters [connectable=" + mConnectable
- + ", isLegacy=" + mIsLegacy
- + ", isAnonymous=" + mIsAnonymous
- + ", includeTxPower=" + mIncludeTxPower
- + ", primaryPhy=" + mPrimaryPhy
- + ", secondaryPhy=" + mSecondaryPhy
- + ", interval=" + mInterval
- + ", txPowerLevel=" + mTxPowerLevel
- + ", ownAddressType=" + mOwnAddressType + "]";
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mConnectable ? 1 : 0);
- dest.writeInt(mScannable ? 1 : 0);
- dest.writeInt(mIsLegacy ? 1 : 0);
- dest.writeInt(mIsAnonymous ? 1 : 0);
- dest.writeInt(mIncludeTxPower ? 1 : 0);
- dest.writeInt(mPrimaryPhy);
- dest.writeInt(mSecondaryPhy);
- dest.writeInt(mInterval);
- dest.writeInt(mTxPowerLevel);
- dest.writeInt(mOwnAddressType);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<AdvertisingSetParameters> CREATOR =
- new Creator<AdvertisingSetParameters>() {
- @Override
- public AdvertisingSetParameters[] newArray(int size) {
- return new AdvertisingSetParameters[size];
- }
-
- @Override
- public AdvertisingSetParameters createFromParcel(Parcel in) {
- return new AdvertisingSetParameters(in);
- }
- };
-
- /**
- * Builder class for {@link AdvertisingSetParameters}.
- */
- public static final class Builder {
- private boolean mConnectable = false;
- private boolean mScannable = false;
- private boolean mIsLegacy = false;
- private boolean mIsAnonymous = false;
- private boolean mIncludeTxPower = false;
- private int mPrimaryPhy = BluetoothDevice.PHY_LE_1M;
- private int mSecondaryPhy = BluetoothDevice.PHY_LE_1M;
- private int mInterval = INTERVAL_LOW;
- private int mTxPowerLevel = TX_POWER_MEDIUM;
- private int mOwnAddressType = ADDRESS_TYPE_DEFAULT;
-
- /**
- * Set whether the advertisement type should be connectable or
- * non-connectable.
- * Legacy advertisements can be both connectable and scannable. Non-legacy
- * advertisements can be only scannable or only connectable.
- *
- * @param connectable Controls whether the advertisement type will be connectable (true) or
- * non-connectable (false).
- */
- public Builder setConnectable(boolean connectable) {
- mConnectable = connectable;
- return this;
- }
-
- /**
- * Set whether the advertisement type should be scannable.
- * Legacy advertisements can be both connectable and scannable. Non-legacy
- * advertisements can be only scannable or only connectable.
- *
- * @param scannable Controls whether the advertisement type will be scannable (true) or
- * non-scannable (false).
- */
- public Builder setScannable(boolean scannable) {
- mScannable = scannable;
- return this;
- }
-
- /**
- * When set to true, advertising set will advertise 4.x Spec compliant
- * advertisements.
- *
- * @param isLegacy whether legacy advertising mode should be used.
- */
- public Builder setLegacyMode(boolean isLegacy) {
- mIsLegacy = isLegacy;
- return this;
- }
-
- /**
- * Set whether advertiser address should be ommited from all packets. If this
- * mode is used, periodic advertising can't be enabled for this set.
- *
- * This is used only if legacy mode is not used.
- *
- * @param isAnonymous whether anonymous advertising should be used.
- */
- public Builder setAnonymous(boolean isAnonymous) {
- mIsAnonymous = isAnonymous;
- return this;
- }
-
- /**
- * Set whether TX power should be included in the extended header.
- *
- * This is used only if legacy mode is not used.
- *
- * @param includeTxPower whether TX power should be included in extended header
- */
- public Builder setIncludeTxPower(boolean includeTxPower) {
- mIncludeTxPower = includeTxPower;
- return this;
- }
-
- /**
- * Set the primary physical channel used for this advertising set.
- *
- * This is used only if legacy mode is not used.
- *
- * Use {@link BluetoothAdapter#isLeCodedPhySupported} to determine if LE Coded PHY is
- * supported on this device.
- *
- * @param primaryPhy Primary advertising physical channel, can only be {@link
- * BluetoothDevice#PHY_LE_1M} or {@link BluetoothDevice#PHY_LE_CODED}.
- * @throws IllegalArgumentException If the primaryPhy is invalid.
- */
- public Builder setPrimaryPhy(int primaryPhy) {
- if (primaryPhy != BluetoothDevice.PHY_LE_1M
- && primaryPhy != BluetoothDevice.PHY_LE_CODED) {
- throw new IllegalArgumentException("bad primaryPhy " + primaryPhy);
- }
- mPrimaryPhy = primaryPhy;
- return this;
- }
-
- /**
- * Set the secondary physical channel used for this advertising set.
- *
- * This is used only if legacy mode is not used.
- *
- * Use {@link BluetoothAdapter#isLeCodedPhySupported} and
- * {@link BluetoothAdapter#isLe2MPhySupported} to determine if LE Coded PHY or 2M PHY is
- * supported on this device.
- *
- * @param secondaryPhy Secondary advertising physical channel, can only be one of {@link
- * BluetoothDevice#PHY_LE_1M}, {@link BluetoothDevice#PHY_LE_2M} or {@link
- * BluetoothDevice#PHY_LE_CODED}.
- * @throws IllegalArgumentException If the secondaryPhy is invalid.
- */
- public Builder setSecondaryPhy(int secondaryPhy) {
- if (secondaryPhy != BluetoothDevice.PHY_LE_1M
- && secondaryPhy != BluetoothDevice.PHY_LE_2M
- && secondaryPhy != BluetoothDevice.PHY_LE_CODED) {
- throw new IllegalArgumentException("bad secondaryPhy " + secondaryPhy);
- }
- mSecondaryPhy = secondaryPhy;
- return this;
- }
-
- /**
- * Set advertising interval.
- *
- * @param interval Bluetooth LE Advertising interval, in 0.625ms unit. Valid range is from
- * 160 (100ms) to 16777215 (10,485.759375 s). Recommended values are: {@link
- * AdvertisingSetParameters#INTERVAL_LOW}, {@link AdvertisingSetParameters#INTERVAL_MEDIUM},
- * or {@link AdvertisingSetParameters#INTERVAL_HIGH}.
- * @throws IllegalArgumentException If the interval is invalid.
- */
- public Builder setInterval(int interval) {
- if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) {
- throw new IllegalArgumentException("unknown interval " + interval);
- }
- mInterval = interval;
- return this;
- }
-
- /**
- * Set the transmission power level for the advertising.
- *
- * @param txPowerLevel Transmission power of Bluetooth LE Advertising, in dBm. The valid
- * range is [-127, 1] Recommended values are:
- * {@link AdvertisingSetParameters#TX_POWER_ULTRA_LOW},
- * {@link AdvertisingSetParameters#TX_POWER_LOW},
- * {@link AdvertisingSetParameters#TX_POWER_MEDIUM},
- * or {@link AdvertisingSetParameters#TX_POWER_HIGH}.
- * @throws IllegalArgumentException If the {@code txPowerLevel} is invalid.
- */
- public Builder setTxPowerLevel(int txPowerLevel) {
- if (txPowerLevel < TX_POWER_MIN || txPowerLevel > TX_POWER_MAX) {
- throw new IllegalArgumentException("unknown txPowerLevel " + txPowerLevel);
- }
- mTxPowerLevel = txPowerLevel;
- return this;
- }
-
- /**
- * Set own address type for advertising to control public or privacy mode. If used to set
- * address type anything other than {@link AdvertisingSetParameters#ADDRESS_TYPE_DEFAULT},
- * then it will require BLUETOOTH_PRIVILEGED permission and will be checked at the
- * time of starting advertising.
- *
- * @throws IllegalArgumentException If the {@code ownAddressType} is invalid
- *
- * @hide
- */
- @SystemApi
- public @NonNull Builder setOwnAddressType(@AddressTypeStatus int ownAddressType) {
- if (ownAddressType < AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT
- || ownAddressType > AdvertisingSetParameters.ADDRESS_TYPE_RANDOM) {
- throw new IllegalArgumentException("unknown address type " + ownAddressType);
- }
- mOwnAddressType = ownAddressType;
- return this;
- }
-
- /**
- * Build the {@link AdvertisingSetParameters} object.
- *
- * @throws IllegalStateException if invalid combination of parameters is used.
- */
- public AdvertisingSetParameters build() {
- if (mIsLegacy) {
- if (mIsAnonymous) {
- throw new IllegalArgumentException("Legacy advertising can't be anonymous");
- }
-
- if (mConnectable && !mScannable) {
- throw new IllegalStateException(
- "Legacy advertisement can't be connectable and non-scannable");
- }
-
- if (mIncludeTxPower) {
- throw new IllegalStateException(
- "Legacy advertising can't include TX power level in header");
- }
- } else {
- if (mConnectable && mScannable) {
- throw new IllegalStateException(
- "Advertising can't be both connectable and scannable");
- }
-
- if (mIsAnonymous && mConnectable) {
- throw new IllegalStateException(
- "Advertising can't be both connectable and anonymous");
- }
- }
-
- return new AdvertisingSetParameters(mConnectable, mScannable, mIsLegacy, mIsAnonymous,
- mIncludeTxPower, mPrimaryPhy, mSecondaryPhy, mInterval, mTxPowerLevel,
- mOwnAddressType);
- }
- }
-}
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
deleted file mode 100644
index 879dcee..0000000
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ /dev/null
@@ -1,756 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothUuid;
-import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothManager;
-import android.bluetooth.annotations.RequiresBluetoothAdvertisePermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.content.AttributionSource;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.ParcelUuid;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * This class provides a way to perform Bluetooth LE advertise operations, such as starting and
- * stopping advertising. An advertiser can broadcast up to 31 bytes of advertisement data
- * represented by {@link AdvertiseData}.
- * <p>
- * To get an instance of {@link BluetoothLeAdvertiser}, call the
- * {@link BluetoothAdapter#getBluetoothLeAdvertiser()} method.
- *
- * @see AdvertiseData
- */
-public final class BluetoothLeAdvertiser {
-
- private static final String TAG = "BluetoothLeAdvertiser";
-
- private static final int MAX_ADVERTISING_DATA_BYTES = 1650;
- private static final int MAX_LEGACY_ADVERTISING_DATA_BYTES = 31;
- // Each fields need one byte for field length and another byte for field type.
- private static final int OVERHEAD_BYTES_PER_FIELD = 2;
- // Flags field will be set by system.
- private static final int FLAGS_FIELD_BYTES = 3;
- private static final int MANUFACTURER_SPECIFIC_DATA_LENGTH = 2;
-
- private final BluetoothAdapter mBluetoothAdapter;
- private final IBluetoothManager mBluetoothManager;
- private final AttributionSource mAttributionSource;
-
- private final Handler mHandler;
- private final Map<AdvertiseCallback, AdvertisingSetCallback>
- mLegacyAdvertisers = new HashMap<>();
- private final Map<AdvertisingSetCallback, IAdvertisingSetCallback>
- mCallbackWrappers = Collections.synchronizedMap(new HashMap<>());
- private final Map<Integer, AdvertisingSet>
- mAdvertisingSets = Collections.synchronizedMap(new HashMap<>());
-
- /**
- * Use BluetoothAdapter.getLeAdvertiser() instead.
- *
- * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management
- * @hide
- */
- public BluetoothLeAdvertiser(BluetoothAdapter bluetoothAdapter) {
- mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter);
- mBluetoothManager = mBluetoothAdapter.getBluetoothManager();
- mAttributionSource = mBluetoothAdapter.getAttributionSource();
- mHandler = new Handler(Looper.getMainLooper());
- }
-
- /**
- * Start Bluetooth LE Advertising. On success, the {@code advertiseData} will be broadcasted.
- * Returns immediately, the operation status is delivered through {@code callback}.
- *
- * @param settings Settings for Bluetooth LE advertising.
- * @param advertiseData Advertisement data to be broadcasted.
- * @param callback Callback for advertising status.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void startAdvertising(AdvertiseSettings settings,
- AdvertiseData advertiseData, final AdvertiseCallback callback) {
- startAdvertising(settings, advertiseData, null, callback);
- }
-
- /**
- * Start Bluetooth LE Advertising. The {@code advertiseData} will be broadcasted if the
- * operation succeeds. The {@code scanResponse} is returned when a scanning device sends an
- * active scan request. This method returns immediately, the operation status is delivered
- * through {@code callback}.
- *
- * @param settings Settings for Bluetooth LE advertising.
- * @param advertiseData Advertisement data to be advertised in advertisement packet.
- * @param scanResponse Scan response associated with the advertisement data.
- * @param callback Callback for advertising status.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void startAdvertising(AdvertiseSettings settings,
- AdvertiseData advertiseData, AdvertiseData scanResponse,
- final AdvertiseCallback callback) {
- synchronized (mLegacyAdvertisers) {
- BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null");
- }
- boolean isConnectable = settings.isConnectable();
- if (totalBytes(advertiseData, isConnectable) > MAX_LEGACY_ADVERTISING_DATA_BYTES
- || totalBytes(scanResponse, false) > MAX_LEGACY_ADVERTISING_DATA_BYTES) {
- postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_DATA_TOO_LARGE);
- return;
- }
- if (mLegacyAdvertisers.containsKey(callback)) {
- postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_ALREADY_STARTED);
- return;
- }
-
- AdvertisingSetParameters.Builder parameters = new AdvertisingSetParameters.Builder();
- parameters.setLegacyMode(true);
- parameters.setConnectable(isConnectable);
- parameters.setScannable(true); // legacy advertisements we support are always scannable
- parameters.setOwnAddressType(settings.getOwnAddressType());
- if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_POWER) {
- parameters.setInterval(1600); // 1s
- } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_BALANCED) {
- parameters.setInterval(400); // 250ms
- } else if (settings.getMode() == AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) {
- parameters.setInterval(160); // 100ms
- }
-
- if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_ULTRA_LOW) {
- parameters.setTxPowerLevel(-21);
- } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_LOW) {
- parameters.setTxPowerLevel(-15);
- } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM) {
- parameters.setTxPowerLevel(-7);
- } else if (settings.getTxPowerLevel() == AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) {
- parameters.setTxPowerLevel(1);
- }
-
- int duration = 0;
- int timeoutMillis = settings.getTimeout();
- if (timeoutMillis > 0) {
- duration = (timeoutMillis < 10) ? 1 : timeoutMillis / 10;
- }
-
- AdvertisingSetCallback wrapped = wrapOldCallback(callback, settings);
- mLegacyAdvertisers.put(callback, wrapped);
- startAdvertisingSet(parameters.build(), advertiseData, scanResponse, null, null,
- duration, 0, wrapped);
- }
- }
-
- @SuppressLint({
- "AndroidFrameworkBluetoothPermission",
- "AndroidFrameworkRequiresPermission",
- })
- AdvertisingSetCallback wrapOldCallback(AdvertiseCallback callback, AdvertiseSettings settings) {
- return new AdvertisingSetCallback() {
- @Override
- public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
- int status) {
- if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
- postStartFailure(callback, status);
- return;
- }
-
- postStartSuccess(callback, settings);
- }
-
- /* Legacy advertiser is disabled on timeout */
- @Override
- public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enabled,
- int status) {
- if (enabled) {
- Log.e(TAG, "Legacy advertiser should be only disabled on timeout,"
- + " but was enabled!");
- return;
- }
-
- stopAdvertising(callback);
- }
-
- };
- }
-
- /**
- * Stop Bluetooth LE advertising. The {@code callback} must be the same one use in
- * {@link BluetoothLeAdvertiser#startAdvertising}.
- *
- * @param callback {@link AdvertiseCallback} identifies the advertising instance to stop.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void stopAdvertising(final AdvertiseCallback callback) {
- synchronized (mLegacyAdvertisers) {
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null");
- }
- AdvertisingSetCallback wrapper = mLegacyAdvertisers.get(callback);
- if (wrapper == null) return;
-
- stopAdvertisingSet(wrapper);
-
- mLegacyAdvertisers.remove(callback);
- }
- }
-
- /**
- * Creates a new advertising set. If operation succeed, device will start advertising. This
- * method returns immediately, the operation status is delivered through
- * {@code callback.onAdvertisingSetStarted()}.
- * <p>
- *
- * @param parameters advertising set parameters.
- * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable,
- * three bytes will be added for flags.
- * @param scanResponse Scan response associated with the advertisement data. Size must not
- * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}.
- * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will
- * not be started.
- * @param periodicData Periodic advertising data. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}.
- * @param callback Callback for advertising set.
- * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable
- * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
- * feature is made when it's not supported by the controller.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void startAdvertisingSet(AdvertisingSetParameters parameters,
- AdvertiseData advertiseData, AdvertiseData scanResponse,
- PeriodicAdvertisingParameters periodicParameters,
- AdvertiseData periodicData, AdvertisingSetCallback callback) {
- startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
- periodicData, 0, 0, callback, new Handler(Looper.getMainLooper()));
- }
-
- /**
- * Creates a new advertising set. If operation succeed, device will start advertising. This
- * method returns immediately, the operation status is delivered through
- * {@code callback.onAdvertisingSetStarted()}.
- * <p>
- *
- * @param parameters advertising set parameters.
- * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable,
- * three bytes will be added for flags.
- * @param scanResponse Scan response associated with the advertisement data. Size must not
- * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}.
- * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will
- * not be started.
- * @param periodicData Periodic advertising data. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}.
- * @param callback Callback for advertising set.
- * @param handler thread upon which the callbacks will be invoked.
- * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable
- * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
- * feature is made when it's not supported by the controller.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void startAdvertisingSet(AdvertisingSetParameters parameters,
- AdvertiseData advertiseData, AdvertiseData scanResponse,
- PeriodicAdvertisingParameters periodicParameters,
- AdvertiseData periodicData, AdvertisingSetCallback callback,
- Handler handler) {
- startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
- periodicData, 0, 0, callback, handler);
- }
-
- /**
- * Creates a new advertising set. If operation succeed, device will start advertising. This
- * method returns immediately, the operation status is delivered through
- * {@code callback.onAdvertisingSetStarted()}.
- * <p>
- *
- * @param parameters advertising set parameters.
- * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable,
- * three bytes will be added for flags.
- * @param scanResponse Scan response associated with the advertisement data. Size must not
- * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}.
- * @param periodicParameters periodic advertisng parameters. If null, periodic advertising will
- * not be started.
- * @param periodicData Periodic advertising data. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}.
- * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535
- * (655,350 ms). 0 means advertising should continue until stopped.
- * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the
- * controller shall attempt to send prior to terminating the extended advertising, even if the
- * duration has not expired. Valid range is from 1 to 255. 0 means no maximum.
- * @param callback Callback for advertising set.
- * @throws IllegalArgumentException when any of the data parameter exceed the maximum allowable
- * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
- * feature is made when it's not supported by the controller.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void startAdvertisingSet(AdvertisingSetParameters parameters,
- AdvertiseData advertiseData, AdvertiseData scanResponse,
- PeriodicAdvertisingParameters periodicParameters,
- AdvertiseData periodicData, int duration,
- int maxExtendedAdvertisingEvents,
- AdvertisingSetCallback callback) {
- startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
- periodicData, duration, maxExtendedAdvertisingEvents, callback,
- new Handler(Looper.getMainLooper()));
- }
-
- /**
- * Creates a new advertising set. If operation succeed, device will start advertising. This
- * method returns immediately, the operation status is delivered through
- * {@code callback.onAdvertisingSetStarted()}.
- * <p>
- *
- * @param parameters Advertising set parameters.
- * @param advertiseData Advertisement data to be broadcasted. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}. If the advertisement is connectable,
- * three bytes will be added for flags.
- * @param scanResponse Scan response associated with the advertisement data. Size must not
- * exceed {@link BluetoothAdapter#getLeMaximumAdvertisingDataLength}
- * @param periodicParameters Periodic advertisng parameters. If null, periodic advertising will
- * not be started.
- * @param periodicData Periodic advertising data. Size must not exceed {@link
- * BluetoothAdapter#getLeMaximumAdvertisingDataLength}
- * @param duration advertising duration, in 10ms unit. Valid range is from 1 (10ms) to 65535
- * (655,350 ms). 0 means advertising should continue until stopped.
- * @param maxExtendedAdvertisingEvents maximum number of extended advertising events the
- * controller shall attempt to send prior to terminating the extended advertising, even if the
- * duration has not expired. Valid range is from 1 to 255. 0 means no maximum.
- * @param callback Callback for advertising set.
- * @param handler Thread upon which the callbacks will be invoked.
- * @throws IllegalArgumentException When any of the data parameter exceed the maximum allowable
- * size, or unsupported advertising PHY is selected, or when attempt to use Periodic Advertising
- * feature is made when it's not supported by the controller, or when
- * maxExtendedAdvertisingEvents is used on a controller that doesn't support the LE Extended
- * Advertising
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void startAdvertisingSet(AdvertisingSetParameters parameters,
- AdvertiseData advertiseData, AdvertiseData scanResponse,
- PeriodicAdvertisingParameters periodicParameters,
- AdvertiseData periodicData, int duration,
- int maxExtendedAdvertisingEvents, AdvertisingSetCallback callback,
- Handler handler) {
- BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null");
- }
-
- boolean isConnectable = parameters.isConnectable();
- if (parameters.isLegacy()) {
- if (totalBytes(advertiseData, isConnectable) > MAX_LEGACY_ADVERTISING_DATA_BYTES) {
- throw new IllegalArgumentException("Legacy advertising data too big");
- }
-
- if (totalBytes(scanResponse, false) > MAX_LEGACY_ADVERTISING_DATA_BYTES) {
- throw new IllegalArgumentException("Legacy scan response data too big");
- }
- } else {
- boolean supportCodedPhy = mBluetoothAdapter.isLeCodedPhySupported();
- boolean support2MPhy = mBluetoothAdapter.isLe2MPhySupported();
- int pphy = parameters.getPrimaryPhy();
- int sphy = parameters.getSecondaryPhy();
- if (pphy == BluetoothDevice.PHY_LE_CODED && !supportCodedPhy) {
- throw new IllegalArgumentException("Unsupported primary PHY selected");
- }
-
- if ((sphy == BluetoothDevice.PHY_LE_CODED && !supportCodedPhy)
- || (sphy == BluetoothDevice.PHY_LE_2M && !support2MPhy)) {
- throw new IllegalArgumentException("Unsupported secondary PHY selected");
- }
-
- int maxData = mBluetoothAdapter.getLeMaximumAdvertisingDataLength();
- if (totalBytes(advertiseData, isConnectable) > maxData) {
- throw new IllegalArgumentException("Advertising data too big");
- }
-
- if (totalBytes(scanResponse, false) > maxData) {
- throw new IllegalArgumentException("Scan response data too big");
- }
-
- if (totalBytes(periodicData, false) > maxData) {
- throw new IllegalArgumentException("Periodic advertising data too big");
- }
-
- boolean supportPeriodic = mBluetoothAdapter.isLePeriodicAdvertisingSupported();
- if (periodicParameters != null && !supportPeriodic) {
- throw new IllegalArgumentException(
- "Controller does not support LE Periodic Advertising");
- }
- }
-
- if (maxExtendedAdvertisingEvents < 0 || maxExtendedAdvertisingEvents > 255) {
- throw new IllegalArgumentException(
- "maxExtendedAdvertisingEvents out of range: " + maxExtendedAdvertisingEvents);
- }
-
- if (maxExtendedAdvertisingEvents != 0
- && !mBluetoothAdapter.isLePeriodicAdvertisingSupported()) {
- throw new IllegalArgumentException(
- "Can't use maxExtendedAdvertisingEvents with controller that don't support "
- + "LE Extended Advertising");
- }
-
- if (duration < 0 || duration > 65535) {
- throw new IllegalArgumentException("duration out of range: " + duration);
- }
-
- IBluetoothGatt gatt;
- try {
- gatt = mBluetoothManager.getBluetoothGatt();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get Bluetooth GATT - ", e);
- postStartSetFailure(handler, callback,
- AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
- return;
- }
-
- if (gatt == null) {
- Log.e(TAG, "Bluetooth GATT is null");
- postStartSetFailure(handler, callback,
- AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
- return;
- }
-
- IAdvertisingSetCallback wrapped = wrap(callback, handler);
- if (mCallbackWrappers.putIfAbsent(callback, wrapped) != null) {
- throw new IllegalArgumentException(
- "callback instance already associated with advertising");
- }
-
- try {
- gatt.startAdvertisingSet(parameters, advertiseData, scanResponse, periodicParameters,
- periodicData, duration, maxExtendedAdvertisingEvents, wrapped,
- mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to start advertising set - ", e);
- postStartSetFailure(handler, callback,
- AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
- return;
- }
- }
-
- /**
- * Used to dispose of a {@link AdvertisingSet} object, obtained with {@link
- * BluetoothLeAdvertiser#startAdvertisingSet}.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- public void stopAdvertisingSet(AdvertisingSetCallback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null");
- }
-
- IAdvertisingSetCallback wrapped = mCallbackWrappers.remove(callback);
- if (wrapped == null) {
- return;
- }
-
- IBluetoothGatt gatt;
- try {
- gatt = mBluetoothManager.getBluetoothGatt();
- gatt.stopAdvertisingSet(wrapped, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to stop advertising - ", e);
- }
- }
-
- /**
- * Cleans up advertisers. Should be called when bluetooth is down.
- *
- * @hide
- */
- @RequiresNoPermission
- public void cleanup() {
- mLegacyAdvertisers.clear();
- mCallbackWrappers.clear();
- mAdvertisingSets.clear();
- }
-
- // Compute the size of advertisement data or scan resp
- @RequiresBluetoothAdvertisePermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADVERTISE)
- private int totalBytes(AdvertiseData data, boolean isFlagsIncluded) {
- if (data == null) return 0;
- // Flags field is omitted if the advertising is not connectable.
- int size = (isFlagsIncluded) ? FLAGS_FIELD_BYTES : 0;
- if (data.getServiceUuids() != null) {
- int num16BitUuids = 0;
- int num32BitUuids = 0;
- int num128BitUuids = 0;
- for (ParcelUuid uuid : data.getServiceUuids()) {
- if (BluetoothUuid.is16BitUuid(uuid)) {
- ++num16BitUuids;
- } else if (BluetoothUuid.is32BitUuid(uuid)) {
- ++num32BitUuids;
- } else {
- ++num128BitUuids;
- }
- }
- // 16 bit service uuids are grouped into one field when doing advertising.
- if (num16BitUuids != 0) {
- size += OVERHEAD_BYTES_PER_FIELD + num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT;
- }
- // 32 bit service uuids are grouped into one field when doing advertising.
- if (num32BitUuids != 0) {
- size += OVERHEAD_BYTES_PER_FIELD + num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT;
- }
- // 128 bit service uuids are grouped into one field when doing advertising.
- if (num128BitUuids != 0) {
- size += OVERHEAD_BYTES_PER_FIELD
- + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
- }
- }
- if (data.getServiceSolicitationUuids() != null) {
- int num16BitUuids = 0;
- int num32BitUuids = 0;
- int num128BitUuids = 0;
- for (ParcelUuid uuid : data.getServiceSolicitationUuids()) {
- if (BluetoothUuid.is16BitUuid(uuid)) {
- ++num16BitUuids;
- } else if (BluetoothUuid.is32BitUuid(uuid)) {
- ++num32BitUuids;
- } else {
- ++num128BitUuids;
- }
- }
- // 16 bit service uuids are grouped into one field when doing advertising.
- if (num16BitUuids != 0) {
- size += OVERHEAD_BYTES_PER_FIELD + num16BitUuids * BluetoothUuid.UUID_BYTES_16_BIT;
- }
- // 32 bit service uuids are grouped into one field when doing advertising.
- if (num32BitUuids != 0) {
- size += OVERHEAD_BYTES_PER_FIELD + num32BitUuids * BluetoothUuid.UUID_BYTES_32_BIT;
- }
- // 128 bit service uuids are grouped into one field when doing advertising.
- if (num128BitUuids != 0) {
- size += OVERHEAD_BYTES_PER_FIELD
- + num128BitUuids * BluetoothUuid.UUID_BYTES_128_BIT;
- }
- }
- for (TransportDiscoveryData transportDiscoveryData : data.getTransportDiscoveryData()) {
- size += OVERHEAD_BYTES_PER_FIELD + transportDiscoveryData.totalBytes();
- }
- for (ParcelUuid uuid : data.getServiceData().keySet()) {
- int uuidLen = BluetoothUuid.uuidToBytes(uuid).length;
- size += OVERHEAD_BYTES_PER_FIELD + uuidLen
- + byteLength(data.getServiceData().get(uuid));
- }
- for (int i = 0; i < data.getManufacturerSpecificData().size(); ++i) {
- size += OVERHEAD_BYTES_PER_FIELD + MANUFACTURER_SPECIFIC_DATA_LENGTH
- + byteLength(data.getManufacturerSpecificData().valueAt(i));
- }
- if (data.getIncludeTxPowerLevel()) {
- size += OVERHEAD_BYTES_PER_FIELD + 1; // tx power level value is one byte.
- }
- if (data.getIncludeDeviceName()) {
- final int length = mBluetoothAdapter.getNameLengthForAdvertise();
- if (length >= 0) {
- size += OVERHEAD_BYTES_PER_FIELD + length;
- }
- }
- return size;
- }
-
- private int byteLength(byte[] array) {
- return array == null ? 0 : array.length;
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- IAdvertisingSetCallback wrap(AdvertisingSetCallback callback, Handler handler) {
- return new IAdvertisingSetCallback.Stub() {
- @Override
- public void onAdvertisingSetStarted(int advertiserId, int txPower, int status) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- if (status != AdvertisingSetCallback.ADVERTISE_SUCCESS) {
- callback.onAdvertisingSetStarted(null, 0, status);
- mCallbackWrappers.remove(callback);
- return;
- }
-
- AdvertisingSet advertisingSet = new AdvertisingSet(
- advertiserId, mBluetoothManager, mAttributionSource);
- mAdvertisingSets.put(advertiserId, advertisingSet);
- callback.onAdvertisingSetStarted(advertisingSet, txPower, status);
- }
- });
- }
-
- @Override
- public void onOwnAddressRead(int advertiserId, int addressType, String address) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onOwnAddressRead(advertisingSet, addressType, address);
- }
- });
- }
-
- @Override
- public void onAdvertisingSetStopped(int advertiserId) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onAdvertisingSetStopped(advertisingSet);
- mAdvertisingSets.remove(advertiserId);
- mCallbackWrappers.remove(callback);
- }
- });
- }
-
- @Override
- public void onAdvertisingEnabled(int advertiserId, boolean enabled, int status) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onAdvertisingEnabled(advertisingSet, enabled, status);
- }
- });
- }
-
- @Override
- public void onAdvertisingDataSet(int advertiserId, int status) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onAdvertisingDataSet(advertisingSet, status);
- }
- });
- }
-
- @Override
- public void onScanResponseDataSet(int advertiserId, int status) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onScanResponseDataSet(advertisingSet, status);
- }
- });
- }
-
- @Override
- public void onAdvertisingParametersUpdated(int advertiserId, int txPower, int status) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onAdvertisingParametersUpdated(advertisingSet, txPower, status);
- }
- });
- }
-
- @Override
- public void onPeriodicAdvertisingParametersUpdated(int advertiserId, int status) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onPeriodicAdvertisingParametersUpdated(advertisingSet, status);
- }
- });
- }
-
- @Override
- public void onPeriodicAdvertisingDataSet(int advertiserId, int status) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onPeriodicAdvertisingDataSet(advertisingSet, status);
- }
- });
- }
-
- @Override
- public void onPeriodicAdvertisingEnabled(int advertiserId, boolean enable, int status) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
- callback.onPeriodicAdvertisingEnabled(advertisingSet, enable, status);
- }
- });
- }
- };
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private void postStartSetFailure(Handler handler, final AdvertisingSetCallback callback,
- final int error) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.onAdvertisingSetStarted(null, 0, error);
- }
- });
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private void postStartFailure(final AdvertiseCallback callback, final int error) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- callback.onStartFailure(error);
- }
- });
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private void postStartSuccess(final AdvertiseCallback callback,
- final AdvertiseSettings settings) {
- mHandler.post(new Runnable() {
-
- @Override
- public void run() {
- callback.onStartSuccess(settings);
- }
- });
- }
-}
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
deleted file mode 100644
index 540e5a7..0000000
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ /dev/null
@@ -1,658 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresNoPermission;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.app.PendingIntent;
-import android.bluetooth.Attributable;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothGatt;
-import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothManager;
-import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
-import android.bluetooth.annotations.RequiresBluetoothScanPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.content.AttributionSource;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.WorkSource;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * This class provides methods to perform scan related operations for Bluetooth LE devices. An
- * application can scan for a particular type of Bluetooth LE devices using {@link ScanFilter}. It
- * can also request different types of callbacks for delivering the result.
- * <p>
- * Use {@link BluetoothAdapter#getBluetoothLeScanner()} to get an instance of
- * {@link BluetoothLeScanner}.
- *
- * @see ScanFilter
- */
-public final class BluetoothLeScanner {
-
- private static final String TAG = "BluetoothLeScanner";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- /**
- * Extra containing a list of ScanResults. It can have one or more results if there was no
- * error. In case of error, {@link #EXTRA_ERROR_CODE} will contain the error code and this
- * extra will not be available.
- */
- public static final String EXTRA_LIST_SCAN_RESULT =
- "android.bluetooth.le.extra.LIST_SCAN_RESULT";
-
- /**
- * Optional extra indicating the error code, if any. The error code will be one of the
- * SCAN_FAILED_* codes in {@link ScanCallback}.
- */
- public static final String EXTRA_ERROR_CODE = "android.bluetooth.le.extra.ERROR_CODE";
-
- /**
- * Optional extra indicating the callback type, which will be one of
- * CALLBACK_TYPE_* constants in {@link ScanSettings}.
- *
- * @see ScanCallback#onScanResult(int, ScanResult)
- */
- public static final String EXTRA_CALLBACK_TYPE = "android.bluetooth.le.extra.CALLBACK_TYPE";
-
- private final BluetoothAdapter mBluetoothAdapter;
- private final IBluetoothManager mBluetoothManager;
- private final AttributionSource mAttributionSource;
-
- private final Handler mHandler;
- private final Map<ScanCallback, BleScanCallbackWrapper> mLeScanClients;
-
- /**
- * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead.
- *
- * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management.
- * @param opPackageName The opPackageName of the context this object was created from
- * @param featureId The featureId of the context this object was created from
- * @hide
- */
- public BluetoothLeScanner(BluetoothAdapter bluetoothAdapter) {
- mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter);
- mBluetoothManager = mBluetoothAdapter.getBluetoothManager();
- mAttributionSource = mBluetoothAdapter.getAttributionSource();
- mHandler = new Handler(Looper.getMainLooper());
- mLeScanClients = new HashMap<ScanCallback, BleScanCallbackWrapper>();
- }
-
- /**
- * Start Bluetooth LE scan with default parameters and no filters. The scan results will be
- * delivered through {@code callback}. For unfiltered scans, scanning is stopped on screen
- * off to save power. Scanning is resumed when screen is turned on again. To avoid this, use
- * {@link #startScan(List, ScanSettings, ScanCallback)} with desired {@link ScanFilter}.
- * <p>
- * An app must have
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission
- * in order to get results. An App targeting Android Q or later must have
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
- * in order to get results.
- *
- * @param callback Callback used to deliver scan results.
- * @throws IllegalArgumentException If {@code callback} is null.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void startScan(final ScanCallback callback) {
- startScan(null, new ScanSettings.Builder().build(), callback);
- }
-
- /**
- * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}.
- * For unfiltered scans, scanning is stopped on screen off to save power. Scanning is
- * resumed when screen is turned on again. To avoid this, do filetered scanning by
- * using proper {@link ScanFilter}.
- * <p>
- * An app must have
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission
- * in order to get results. An App targeting Android Q or later must have
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
- * in order to get results.
- *
- * @param filters {@link ScanFilter}s for finding exact BLE devices.
- * @param settings Settings for the scan.
- * @param callback Callback used to deliver scan results.
- * @throws IllegalArgumentException If {@code settings} or {@code callback} is null.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void startScan(List<ScanFilter> filters, ScanSettings settings,
- final ScanCallback callback) {
- startScan(filters, settings, null, callback, /*callbackIntent=*/ null);
- }
-
- /**
- * Start Bluetooth LE scan using a {@link PendingIntent}. The scan results will be delivered via
- * the PendingIntent. Use this method of scanning if your process is not always running and it
- * should be started when scan results are available.
- * <p>
- * An app must have
- * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} permission
- * in order to get results. An App targeting Android Q or later must have
- * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
- * in order to get results.
- * <p>
- * When the PendingIntent is delivered, the Intent passed to the receiver or activity
- * will contain one or more of the extras {@link #EXTRA_CALLBACK_TYPE},
- * {@link #EXTRA_ERROR_CODE} and {@link #EXTRA_LIST_SCAN_RESULT} to indicate the result of
- * the scan.
- *
- * @param filters Optional list of ScanFilters for finding exact BLE devices.
- * @param settings Optional settings for the scan.
- * @param callbackIntent The PendingIntent to deliver the result to.
- * @return Returns 0 for success or an error code from {@link ScanCallback} if the scan request
- * could not be sent.
- * @see #stopScan(PendingIntent)
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public int startScan(@Nullable List<ScanFilter> filters, @Nullable ScanSettings settings,
- @NonNull PendingIntent callbackIntent) {
- return startScan(filters,
- settings != null ? settings : new ScanSettings.Builder().build(),
- null, null, callbackIntent);
- }
-
- /**
- * Start Bluetooth LE scan. Same as {@link #startScan(ScanCallback)} but allows the caller to
- * specify on behalf of which application(s) the work is being done.
- *
- * @param workSource {@link WorkSource} identifying the application(s) for which to blame for
- * the scan.
- * @param callback Callback used to deliver scan results.
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_SCAN,
- android.Manifest.permission.UPDATE_DEVICE_STATS
- })
- public void startScanFromSource(final WorkSource workSource, final ScanCallback callback) {
- startScanFromSource(null, new ScanSettings.Builder().build(), workSource, callback);
- }
-
- /**
- * Start Bluetooth LE scan. Same as {@link #startScan(List, ScanSettings, ScanCallback)} but
- * allows the caller to specify on behalf of which application(s) the work is being done.
- *
- * @param filters {@link ScanFilter}s for finding exact BLE devices.
- * @param settings Settings for the scan.
- * @param workSource {@link WorkSource} identifying the application(s) for which to blame for
- * the scan.
- * @param callback Callback used to deliver scan results.
- * @hide
- */
- @SystemApi
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_SCAN,
- android.Manifest.permission.UPDATE_DEVICE_STATS
- })
- @SuppressLint("AndroidFrameworkRequiresPermission")
- public void startScanFromSource(List<ScanFilter> filters, ScanSettings settings,
- final WorkSource workSource, final ScanCallback callback) {
- startScan(filters, settings, workSource, callback, null);
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- private int startScan(List<ScanFilter> filters, ScanSettings settings,
- final WorkSource workSource, final ScanCallback callback,
- final PendingIntent callbackIntent) {
- BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
- if (callback == null && callbackIntent == null) {
- throw new IllegalArgumentException("callback is null");
- }
- if (settings == null) {
- throw new IllegalArgumentException("settings is null");
- }
- synchronized (mLeScanClients) {
- if (callback != null && mLeScanClients.containsKey(callback)) {
- return postCallbackErrorOrReturn(callback,
- ScanCallback.SCAN_FAILED_ALREADY_STARTED);
- }
- IBluetoothGatt gatt;
- try {
- gatt = mBluetoothManager.getBluetoothGatt();
- } catch (RemoteException e) {
- gatt = null;
- }
- if (gatt == null) {
- return postCallbackErrorOrReturn(callback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
- }
- if (!isSettingsConfigAllowedForScan(settings)) {
- return postCallbackErrorOrReturn(callback,
- ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
- }
- if (!isHardwareResourcesAvailableForScan(settings)) {
- return postCallbackErrorOrReturn(callback,
- ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES);
- }
- if (!isSettingsAndFilterComboAllowed(settings, filters)) {
- return postCallbackErrorOrReturn(callback,
- ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED);
- }
- if (callback != null) {
- BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters,
- settings, workSource, callback);
- wrapper.startRegistration();
- } else {
- try {
- gatt.startScanForIntent(callbackIntent, settings, filters,
- mAttributionSource);
- } catch (RemoteException e) {
- return ScanCallback.SCAN_FAILED_INTERNAL_ERROR;
- }
- }
- }
- return ScanCallback.NO_ERROR;
- }
-
- /**
- * Stops an ongoing Bluetooth LE scan.
- *
- * @param callback
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void stopScan(ScanCallback callback) {
- BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
- synchronized (mLeScanClients) {
- BleScanCallbackWrapper wrapper = mLeScanClients.remove(callback);
- if (wrapper == null) {
- if (DBG) Log.d(TAG, "could not find callback wrapper");
- return;
- }
- wrapper.stopLeScan();
- }
- }
-
- /**
- * Stops an ongoing Bluetooth LE scan started using a PendingIntent. When creating the
- * PendingIntent parameter, please do not use the FLAG_CANCEL_CURRENT flag. Otherwise, the stop
- * scan may have no effect.
- *
- * @param callbackIntent The PendingIntent that was used to start the scan.
- * @see #startScan(List, ScanSettings, PendingIntent)
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void stopScan(PendingIntent callbackIntent) {
- BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
- IBluetoothGatt gatt;
- try {
- gatt = mBluetoothManager.getBluetoothGatt();
- gatt.stopScanForIntent(callbackIntent, mAttributionSource);
- } catch (RemoteException e) {
- }
- }
-
- /**
- * Flush pending batch scan results stored in Bluetooth controller. This will return Bluetooth
- * LE scan results batched on bluetooth controller. Returns immediately, batch scan results data
- * will be delivered through the {@code callback}.
- *
- * @param callback Callback of the Bluetooth LE Scan, it has to be the same instance as the one
- * used to start scan.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void flushPendingScanResults(ScanCallback callback) {
- BluetoothLeUtils.checkAdapterStateOn(mBluetoothAdapter);
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null!");
- }
- synchronized (mLeScanClients) {
- BleScanCallbackWrapper wrapper = mLeScanClients.get(callback);
- if (wrapper == null) {
- return;
- }
- wrapper.flushPendingBatchResults();
- }
- }
-
- /**
- * Start truncated scan.
- *
- * @deprecated this is not used anywhere
- *
- * @hide
- */
- @Deprecated
- @SystemApi
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void startTruncatedScan(List<TruncatedFilter> truncatedFilters, ScanSettings settings,
- final ScanCallback callback) {
- int filterSize = truncatedFilters.size();
- List<ScanFilter> scanFilters = new ArrayList<ScanFilter>(filterSize);
- for (TruncatedFilter filter : truncatedFilters) {
- scanFilters.add(filter.getFilter());
- }
- startScan(scanFilters, settings, null, callback, null);
- }
-
- /**
- * Cleans up scan clients. Should be called when bluetooth is down.
- *
- * @hide
- */
- @RequiresNoPermission
- public void cleanup() {
- mLeScanClients.clear();
- }
-
- /**
- * Bluetooth GATT interface callbacks
- */
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private class BleScanCallbackWrapper extends IScannerCallback.Stub {
- private static final int REGISTRATION_CALLBACK_TIMEOUT_MILLIS = 2000;
-
- private final ScanCallback mScanCallback;
- private final List<ScanFilter> mFilters;
- private final WorkSource mWorkSource;
- private ScanSettings mSettings;
- private IBluetoothGatt mBluetoothGatt;
-
- // mLeHandle 0: not registered
- // -2: registration failed because app is scanning to frequently
- // -1: scan stopped or registration failed
- // > 0: registered and scan started
- private int mScannerId;
-
- public BleScanCallbackWrapper(IBluetoothGatt bluetoothGatt,
- List<ScanFilter> filters, ScanSettings settings,
- WorkSource workSource, ScanCallback scanCallback) {
- mBluetoothGatt = bluetoothGatt;
- mFilters = filters;
- mSettings = settings;
- mWorkSource = workSource;
- mScanCallback = scanCallback;
- mScannerId = 0;
- }
-
- public void startRegistration() {
- synchronized (this) {
- // Scan stopped.
- if (mScannerId == -1 || mScannerId == -2) return;
- try {
- mBluetoothGatt.registerScanner(this, mWorkSource, mAttributionSource);
- wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS);
- } catch (InterruptedException | RemoteException e) {
- Log.e(TAG, "application registeration exception", e);
- postCallbackError(mScanCallback, ScanCallback.SCAN_FAILED_INTERNAL_ERROR);
- }
- if (mScannerId > 0) {
- mLeScanClients.put(mScanCallback, this);
- } else {
- // Registration timed out or got exception, reset RscannerId to -1 so no
- // subsequent operations can proceed.
- if (mScannerId == 0) mScannerId = -1;
-
- // If scanning too frequently, don't report anything to the app.
- if (mScannerId == -2) return;
-
- postCallbackError(mScanCallback,
- ScanCallback.SCAN_FAILED_APPLICATION_REGISTRATION_FAILED);
- }
- }
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void stopLeScan() {
- synchronized (this) {
- if (mScannerId <= 0) {
- Log.e(TAG, "Error state, mLeHandle: " + mScannerId);
- return;
- }
- try {
- mBluetoothGatt.stopScan(mScannerId, mAttributionSource);
- mBluetoothGatt.unregisterScanner(mScannerId, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to stop scan and unregister", e);
- }
- mScannerId = -1;
- }
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- void flushPendingBatchResults() {
- synchronized (this) {
- if (mScannerId <= 0) {
- Log.e(TAG, "Error state, mLeHandle: " + mScannerId);
- return;
- }
- try {
- mBluetoothGatt.flushPendingBatchResults(mScannerId, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get pending scan results", e);
- }
- }
- }
-
- /**
- * Application interface registered - app is ready to go
- */
- @Override
- public void onScannerRegistered(int status, int scannerId) {
- Log.d(TAG, "onScannerRegistered() - status=" + status
- + " scannerId=" + scannerId + " mScannerId=" + mScannerId);
- synchronized (this) {
- if (status == BluetoothGatt.GATT_SUCCESS) {
- try {
- if (mScannerId == -1) {
- // Registration succeeds after timeout, unregister scanner.
- mBluetoothGatt.unregisterScanner(scannerId, mAttributionSource);
- } else {
- mScannerId = scannerId;
- mBluetoothGatt.startScan(mScannerId, mSettings, mFilters,
- mAttributionSource);
- }
- } catch (RemoteException e) {
- Log.e(TAG, "fail to start le scan: " + e);
- mScannerId = -1;
- }
- } else if (status == ScanCallback.SCAN_FAILED_SCANNING_TOO_FREQUENTLY) {
- // applicaiton was scanning too frequently
- mScannerId = -2;
- } else {
- // registration failed
- mScannerId = -1;
- }
- notifyAll();
- }
- }
-
- /**
- * Callback reporting an LE scan result.
- *
- * @hide
- */
- @Override
- public void onScanResult(final ScanResult scanResult) {
- Attributable.setAttributionSource(scanResult, mAttributionSource);
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "onScanResult() - mScannerId=" + mScannerId);
- }
- if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString());
-
- // Check null in case the scan has been stopped
- synchronized (this) {
- if (mScannerId <= 0) {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "Ignoring result as scan stopped.");
- }
- return;
- };
- }
- Handler handler = new Handler(Looper.getMainLooper());
- handler.post(new Runnable() {
- @Override
- public void run() {
- if (Log.isLoggable(TAG, Log.DEBUG)) {
- Log.d(TAG, "onScanResult() - handler run");
- }
- mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_ALL_MATCHES, scanResult);
- }
- });
- }
-
- @Override
- public void onBatchScanResults(final List<ScanResult> results) {
- Attributable.setAttributionSource(results, mAttributionSource);
- Handler handler = new Handler(Looper.getMainLooper());
- handler.post(new Runnable() {
- @Override
- public void run() {
- mScanCallback.onBatchScanResults(results);
- }
- });
- }
-
- @Override
- public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) {
- Attributable.setAttributionSource(scanResult, mAttributionSource);
- if (VDBG) {
- Log.d(TAG, "onFoundOrLost() - onFound = " + onFound + " " + scanResult.toString());
- }
-
- // Check null in case the scan has been stopped
- synchronized (this) {
- if (mScannerId <= 0) {
- return;
- }
- }
- Handler handler = new Handler(Looper.getMainLooper());
- handler.post(new Runnable() {
- @Override
- public void run() {
- if (onFound) {
- mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_FIRST_MATCH,
- scanResult);
- } else {
- mScanCallback.onScanResult(ScanSettings.CALLBACK_TYPE_MATCH_LOST,
- scanResult);
- }
- }
- });
- }
-
- @Override
- public void onScanManagerErrorCallback(final int errorCode) {
- if (VDBG) {
- Log.d(TAG, "onScanManagerErrorCallback() - errorCode = " + errorCode);
- }
- synchronized (this) {
- if (mScannerId <= 0) {
- return;
- }
- }
- postCallbackError(mScanCallback, errorCode);
- }
- }
-
- private int postCallbackErrorOrReturn(final ScanCallback callback, final int errorCode) {
- if (callback == null) {
- return errorCode;
- } else {
- postCallbackError(callback, errorCode);
- return ScanCallback.NO_ERROR;
- }
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private void postCallbackError(final ScanCallback callback, final int errorCode) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- callback.onScanFailed(errorCode);
- }
- });
- }
-
- private boolean isSettingsConfigAllowedForScan(ScanSettings settings) {
- if (mBluetoothAdapter.isOffloadedFilteringSupported()) {
- return true;
- }
- final int callbackType = settings.getCallbackType();
- // Only support regular scan if no offloaded filter support.
- if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES
- && settings.getReportDelayMillis() == 0) {
- return true;
- }
- return false;
- }
-
- private boolean isSettingsAndFilterComboAllowed(ScanSettings settings,
- List<ScanFilter> filterList) {
- final int callbackType = settings.getCallbackType();
- // If onlost/onfound is requested, a non-empty filter is expected
- if ((callbackType & (ScanSettings.CALLBACK_TYPE_FIRST_MATCH
- | ScanSettings.CALLBACK_TYPE_MATCH_LOST)) != 0) {
- if (filterList == null) {
- return false;
- }
- for (ScanFilter filter : filterList) {
- if (filter.isAllFieldsEmpty()) {
- return false;
- }
- }
- }
- return true;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) {
- final int callbackType = settings.getCallbackType();
- if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0
- || (callbackType & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) {
- // For onlost/onfound, we required hw support be available
- return (mBluetoothAdapter.isOffloadedFilteringSupported()
- && mBluetoothAdapter.isHardwareTrackingFiltersAvailable());
- }
- return true;
- }
-}
diff --git a/core/java/android/bluetooth/le/BluetoothLeUtils.java b/core/java/android/bluetooth/le/BluetoothLeUtils.java
deleted file mode 100644
index ed50b09..0000000
--- a/core/java/android/bluetooth/le/BluetoothLeUtils.java
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.bluetooth.BluetoothAdapter;
-import android.util.SparseArray;
-
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * Helper class for Bluetooth LE utils.
- *
- * @hide
- */
-public class BluetoothLeUtils {
-
- /**
- * Returns a string composed from a {@link SparseArray}.
- */
- static String toString(SparseArray<byte[]> array) {
- if (array == null) {
- return "null";
- }
- if (array.size() == 0) {
- return "{}";
- }
- StringBuilder buffer = new StringBuilder();
- buffer.append('{');
- for (int i = 0; i < array.size(); ++i) {
- buffer.append(array.keyAt(i)).append("=").append(Arrays.toString(array.valueAt(i)));
- }
- buffer.append('}');
- return buffer.toString();
- }
-
- /**
- * Returns a string composed from a {@link Map}.
- */
- static <T> String toString(Map<T, byte[]> map) {
- if (map == null) {
- return "null";
- }
- if (map.isEmpty()) {
- return "{}";
- }
- StringBuilder buffer = new StringBuilder();
- buffer.append('{');
- Iterator<Map.Entry<T, byte[]>> it = map.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry<T, byte[]> entry = it.next();
- Object key = entry.getKey();
- buffer.append(key).append("=").append(Arrays.toString(map.get(key)));
- if (it.hasNext()) {
- buffer.append(", ");
- }
- }
- buffer.append('}');
- return buffer.toString();
- }
-
- /**
- * Check whether two {@link SparseArray} equal.
- */
- static boolean equals(SparseArray<byte[]> array, SparseArray<byte[]> otherArray) {
- if (array == otherArray) {
- return true;
- }
- if (array == null || otherArray == null) {
- return false;
- }
- if (array.size() != otherArray.size()) {
- return false;
- }
-
- // Keys are guaranteed in ascending order when indices are in ascending order.
- for (int i = 0; i < array.size(); ++i) {
- if (array.keyAt(i) != otherArray.keyAt(i)
- || !Arrays.equals(array.valueAt(i), otherArray.valueAt(i))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Check whether two {@link Map} equal.
- */
- static <T> boolean equals(Map<T, byte[]> map, Map<T, byte[]> otherMap) {
- if (map == otherMap) {
- return true;
- }
- if (map == null || otherMap == null) {
- return false;
- }
- if (map.size() != otherMap.size()) {
- return false;
- }
- Set<T> keys = map.keySet();
- if (!keys.equals(otherMap.keySet())) {
- return false;
- }
- for (T key : keys) {
- if (!Objects.deepEquals(map.get(key), otherMap.get(key))) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Ensure Bluetooth is turned on.
- *
- * @throws IllegalStateException If {@code adapter} is null or Bluetooth state is not {@link
- * BluetoothAdapter#STATE_ON}.
- */
- static void checkAdapterStateOn(BluetoothAdapter adapter) {
- if (adapter == null || !adapter.isLeEnabled()) {
- throw new IllegalStateException("BT Adapter is not turned ON");
- }
- }
-
- /**
- * Compares two UUIDs with a UUID mask.
- *
- * @param data first {@link #UUID} to compare.
- * @param uuid second {@link #UUID} to compare.
- * @param mask mask {@link #UUID}.
- * @return true if both UUIDs are equals when masked, false otherwise.
- */
- static boolean maskedEquals(UUID data, UUID uuid, UUID mask) {
- if (mask == null) {
- return Objects.equals(data, uuid);
- }
- return (data.getLeastSignificantBits() & mask.getLeastSignificantBits())
- == (uuid.getLeastSignificantBits() & mask.getLeastSignificantBits())
- && (data.getMostSignificantBits() & mask.getMostSignificantBits())
- == (uuid.getMostSignificantBits() & mask.getMostSignificantBits());
- }
-}
diff --git a/core/java/android/bluetooth/le/OWNERS b/core/java/android/bluetooth/le/OWNERS
deleted file mode 100644
index 3523ee0..0000000
--- a/core/java/android/bluetooth/le/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# Bug component: 27441
-
-zachoverflow@google.com
-siyuanh@google.com
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java b/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java
deleted file mode 100644
index 14ac911..0000000
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingCallback.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.bluetooth.BluetoothDevice;
-
-/**
- * Bluetooth LE periodic advertising callbacks, used to deliver periodic
- * advertising operation status.
- *
- * @hide
- * @see PeriodicAdvertisingManager#createSync
- */
-public abstract class PeriodicAdvertisingCallback {
-
- /**
- * The requested operation was successful.
- *
- * @hide
- */
- public static final int SYNC_SUCCESS = 0;
-
- /**
- * Sync failed to be established because remote device did not respond.
- */
- public static final int SYNC_NO_RESPONSE = 1;
-
- /**
- * Sync failed to be established because controller can't support more syncs.
- */
- public static final int SYNC_NO_RESOURCES = 2;
-
-
- /**
- * Callback when synchronization was established.
- *
- * @param syncHandle handle used to identify this synchronization.
- * @param device remote device.
- * @param advertisingSid synchronized advertising set id.
- * @param skip The number of periodic advertising packets that can be skipped after a successful
- * receive in force. @see PeriodicAdvertisingManager#createSync
- * @param timeout Synchronization timeout for the periodic advertising in force. One unit is
- * 10ms. @see PeriodicAdvertisingManager#createSync
- * @param timeout
- * @param status operation status.
- */
- public void onSyncEstablished(int syncHandle, BluetoothDevice device,
- int advertisingSid, int skip, int timeout,
- int status) {
- }
-
- /**
- * Callback when periodic advertising report is received.
- *
- * @param report periodic advertising report.
- */
- public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) {
- }
-
- /**
- * Callback when periodic advertising synchronization was lost.
- *
- * @param syncHandle handle used to identify this synchronization.
- */
- public void onSyncLost(int syncHandle) {
- }
-}
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java b/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
deleted file mode 100644
index bbd3117..0000000
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingManager.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.bluetooth.Attributable;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothManager;
-import android.bluetooth.annotations.RequiresBluetoothLocationPermission;
-import android.bluetooth.annotations.RequiresBluetoothScanPermission;
-import android.bluetooth.annotations.RequiresLegacyBluetoothAdminPermission;
-import android.content.AttributionSource;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * This class provides methods to perform periodic advertising related
- * operations. An application can register for periodic advertisements using
- * {@link PeriodicAdvertisingManager#registerSync}.
- * <p>
- * Use {@link BluetoothAdapter#getPeriodicAdvertisingManager()} to get an
- * instance of {@link PeriodicAdvertisingManager}.
- *
- * @hide
- */
-public final class PeriodicAdvertisingManager {
-
- private static final String TAG = "PeriodicAdvertisingManager";
-
- private static final int SKIP_MIN = 0;
- private static final int SKIP_MAX = 499;
- private static final int TIMEOUT_MIN = 10;
- private static final int TIMEOUT_MAX = 16384;
-
- private static final int SYNC_STARTING = -1;
-
- private final BluetoothAdapter mBluetoothAdapter;
- private final IBluetoothManager mBluetoothManager;
- private final AttributionSource mAttributionSource;
-
- /* maps callback, to callback wrapper and sync handle */
- Map<PeriodicAdvertisingCallback,
- IPeriodicAdvertisingCallback /* callbackWrapper */> mCallbackWrappers;
-
- /**
- * Use {@link BluetoothAdapter#getBluetoothLeScanner()} instead.
- *
- * @param bluetoothManager BluetoothManager that conducts overall Bluetooth Management.
- * @hide
- */
- public PeriodicAdvertisingManager(BluetoothAdapter bluetoothAdapter) {
- mBluetoothAdapter = Objects.requireNonNull(bluetoothAdapter);
- mBluetoothManager = mBluetoothAdapter.getBluetoothManager();
- mAttributionSource = mBluetoothAdapter.getAttributionSource();
- mCallbackWrappers = new IdentityHashMap<>();
- }
-
- /**
- * Synchronize with periodic advertising pointed to by the {@code scanResult}.
- * The {@code scanResult} used must contain a valid advertisingSid. First
- * call to registerSync will use the {@code skip} and {@code timeout} provided.
- * Subsequent calls from other apps, trying to sync with same set will reuse
- * existing sync, thus {@code skip} and {@code timeout} values will not take
- * effect. The values in effect will be returned in
- * {@link PeriodicAdvertisingCallback#onSyncEstablished}.
- *
- * @param scanResult Scan result containing advertisingSid.
- * @param skip The number of periodic advertising packets that can be skipped after a successful
- * receive. Must be between 0 and 499.
- * @param timeout Synchronization timeout for the periodic advertising. One unit is 10ms. Must
- * be between 10 (100ms) and 16384 (163.84s).
- * @param callback Callback used to deliver all operations status.
- * @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or
- * {@code timeout} is invalid or {@code callback} is null.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void registerSync(ScanResult scanResult, int skip, int timeout,
- PeriodicAdvertisingCallback callback) {
- registerSync(scanResult, skip, timeout, callback, null);
- }
-
- /**
- * Synchronize with periodic advertising pointed to by the {@code scanResult}.
- * The {@code scanResult} used must contain a valid advertisingSid. First
- * call to registerSync will use the {@code skip} and {@code timeout} provided.
- * Subsequent calls from other apps, trying to sync with same set will reuse
- * existing sync, thus {@code skip} and {@code timeout} values will not take
- * effect. The values in effect will be returned in
- * {@link PeriodicAdvertisingCallback#onSyncEstablished}.
- *
- * @param scanResult Scan result containing advertisingSid.
- * @param skip The number of periodic advertising packets that can be skipped after a successful
- * receive. Must be between 0 and 499.
- * @param timeout Synchronization timeout for the periodic advertising. One unit is 10ms. Must
- * be between 10 (100ms) and 16384 (163.84s).
- * @param callback Callback used to deliver all operations status.
- * @param handler thread upon which the callbacks will be invoked.
- * @throws IllegalArgumentException if {@code scanResult} is null or {@code skip} is invalid or
- * {@code timeout} is invalid or {@code callback} is null.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresBluetoothLocationPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void registerSync(ScanResult scanResult, int skip, int timeout,
- PeriodicAdvertisingCallback callback, Handler handler) {
- if (callback == null) {
- throw new IllegalArgumentException("callback can't be null");
- }
-
- if (scanResult == null) {
- throw new IllegalArgumentException("scanResult can't be null");
- }
-
- if (scanResult.getAdvertisingSid() == ScanResult.SID_NOT_PRESENT) {
- throw new IllegalArgumentException("scanResult must contain a valid sid");
- }
-
- if (skip < SKIP_MIN || skip > SKIP_MAX) {
- throw new IllegalArgumentException(
- "timeout must be between " + TIMEOUT_MIN + " and " + TIMEOUT_MAX);
- }
-
- if (timeout < TIMEOUT_MIN || timeout > TIMEOUT_MAX) {
- throw new IllegalArgumentException(
- "timeout must be between " + TIMEOUT_MIN + " and " + TIMEOUT_MAX);
- }
-
- IBluetoothGatt gatt;
- try {
- gatt = mBluetoothManager.getBluetoothGatt();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
- callback.onSyncEstablished(0, scanResult.getDevice(), scanResult.getAdvertisingSid(),
- skip, timeout,
- PeriodicAdvertisingCallback.SYNC_NO_RESOURCES);
- return;
- }
-
- if (handler == null) {
- handler = new Handler(Looper.getMainLooper());
- }
-
- IPeriodicAdvertisingCallback wrapped = wrap(callback, handler);
- mCallbackWrappers.put(callback, wrapped);
-
- try {
- gatt.registerSync(
- scanResult, skip, timeout, wrapped, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to register sync - ", e);
- return;
- }
- }
-
- /**
- * Cancel pending attempt to create sync, or terminate existing sync.
- *
- * @param callback Callback used to deliver all operations status.
- * @throws IllegalArgumentException if {@code callback} is null, or not a properly registered
- * callback.
- */
- @RequiresLegacyBluetoothAdminPermission
- @RequiresBluetoothScanPermission
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_SCAN)
- public void unregisterSync(PeriodicAdvertisingCallback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback can't be null");
- }
-
- IBluetoothGatt gatt;
- try {
- gatt = mBluetoothManager.getBluetoothGatt();
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
- return;
- }
-
- IPeriodicAdvertisingCallback wrapper = mCallbackWrappers.remove(callback);
- if (wrapper == null) {
- throw new IllegalArgumentException("callback was not properly registered");
- }
-
- try {
- gatt.unregisterSync(wrapper, mAttributionSource);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to cancel sync creation - ", e);
- return;
- }
- }
-
- @SuppressLint("AndroidFrameworkBluetoothPermission")
- private IPeriodicAdvertisingCallback wrap(PeriodicAdvertisingCallback callback,
- Handler handler) {
- return new IPeriodicAdvertisingCallback.Stub() {
- public void onSyncEstablished(int syncHandle, BluetoothDevice device,
- int advertisingSid, int skip, int timeout, int status) {
- Attributable.setAttributionSource(device, mAttributionSource);
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.onSyncEstablished(syncHandle, device, advertisingSid, skip,
- timeout,
- status);
-
- if (status != PeriodicAdvertisingCallback.SYNC_SUCCESS) {
- // App can still unregister the sync until notified it failed. Remove
- // callback
- // after app was notifed.
- mCallbackWrappers.remove(callback);
- }
- }
- });
- }
-
- public void onPeriodicAdvertisingReport(PeriodicAdvertisingReport report) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.onPeriodicAdvertisingReport(report);
- }
- });
- }
-
- public void onSyncLost(int syncHandle) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- callback.onSyncLost(syncHandle);
- // App can still unregister the sync until notified it's lost.
- // Remove callback after app was notifed.
- mCallbackWrappers.remove(callback);
- }
- });
- }
- };
- }
-}
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java b/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
deleted file mode 100644
index 4e64dbe..0000000
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingParameters.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * The {@link PeriodicAdvertisingParameters} provide a way to adjust periodic
- * advertising preferences for each Bluetooth LE advertising set. Use {@link
- * PeriodicAdvertisingParameters.Builder} to create an instance of this class.
- */
-public final class PeriodicAdvertisingParameters implements Parcelable {
-
- private static final int INTERVAL_MIN = 80;
- private static final int INTERVAL_MAX = 65519;
-
- private final boolean mIncludeTxPower;
- private final int mInterval;
-
- private PeriodicAdvertisingParameters(boolean includeTxPower, int interval) {
- mIncludeTxPower = includeTxPower;
- mInterval = interval;
- }
-
- private PeriodicAdvertisingParameters(Parcel in) {
- mIncludeTxPower = in.readInt() != 0;
- mInterval = in.readInt();
- }
-
- /**
- * Returns whether the TX Power will be included.
- */
- public boolean getIncludeTxPower() {
- return mIncludeTxPower;
- }
-
- /**
- * Returns the periodic advertising interval, in 1.25ms unit.
- * Valid values are from 80 (100ms) to 65519 (81.89875s).
- */
- public int getInterval() {
- return mInterval;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mIncludeTxPower ? 1 : 0);
- dest.writeInt(mInterval);
- }
-
- public static final Parcelable
- .Creator<PeriodicAdvertisingParameters> CREATOR =
- new Creator<PeriodicAdvertisingParameters>() {
- @Override
- public PeriodicAdvertisingParameters[] newArray(int size) {
- return new PeriodicAdvertisingParameters[size];
- }
-
- @Override
- public PeriodicAdvertisingParameters createFromParcel(Parcel in) {
- return new PeriodicAdvertisingParameters(in);
- }
- };
-
- public static final class Builder {
- private boolean mIncludeTxPower = false;
- private int mInterval = INTERVAL_MAX;
-
- /**
- * Whether the transmission power level should be included in the periodic
- * packet.
- */
- public Builder setIncludeTxPower(boolean includeTxPower) {
- mIncludeTxPower = includeTxPower;
- return this;
- }
-
- /**
- * Set advertising interval for periodic advertising, in 1.25ms unit.
- * Valid values are from 80 (100ms) to 65519 (81.89875s).
- * Value from range [interval, interval+20ms] will be picked as the actual value.
- *
- * @throws IllegalArgumentException If the interval is invalid.
- */
- public Builder setInterval(int interval) {
- if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) {
- throw new IllegalArgumentException("Invalid interval (must be " + INTERVAL_MIN
- + "-" + INTERVAL_MAX + ")");
- }
- mInterval = interval;
- return this;
- }
-
- /**
- * Build the {@link AdvertisingSetParameters} object.
- */
- public PeriodicAdvertisingParameters build() {
- return new PeriodicAdvertisingParameters(mIncludeTxPower, mInterval);
- }
- }
-}
diff --git a/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java b/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
deleted file mode 100644
index 54b953c..0000000
--- a/core/java/android/bluetooth/le/PeriodicAdvertisingReport.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * PeriodicAdvertisingReport for Bluetooth LE synchronized advertising.
- *
- * @hide
- */
-public final class PeriodicAdvertisingReport implements Parcelable {
-
- /**
- * The data returned is complete
- */
- public static final int DATA_COMPLETE = 0;
-
- /**
- * The data returned is incomplete. The controller was unsuccessfull to
- * receive all chained packets, returning only partial data.
- */
- public static final int DATA_INCOMPLETE_TRUNCATED = 2;
-
- private int mSyncHandle;
- private int mTxPower;
- private int mRssi;
- private int mDataStatus;
-
- // periodic advertising data.
- @Nullable
- private ScanRecord mData;
-
- // Device timestamp when the result was last seen.
- private long mTimestampNanos;
-
- /**
- * Constructor of periodic advertising result.
- */
- public PeriodicAdvertisingReport(int syncHandle, int txPower, int rssi,
- int dataStatus, ScanRecord data) {
- mSyncHandle = syncHandle;
- mTxPower = txPower;
- mRssi = rssi;
- mDataStatus = dataStatus;
- mData = data;
- }
-
- private PeriodicAdvertisingReport(Parcel in) {
- readFromParcel(in);
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mSyncHandle);
- dest.writeInt(mTxPower);
- dest.writeInt(mRssi);
- dest.writeInt(mDataStatus);
- if (mData != null) {
- dest.writeInt(1);
- dest.writeByteArray(mData.getBytes());
- } else {
- dest.writeInt(0);
- }
- }
-
- private void readFromParcel(Parcel in) {
- mSyncHandle = in.readInt();
- mTxPower = in.readInt();
- mRssi = in.readInt();
- mDataStatus = in.readInt();
- if (in.readInt() == 1) {
- mData = ScanRecord.parseFromBytes(in.createByteArray());
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Returns the synchronization handle.
- */
- public int getSyncHandle() {
- return mSyncHandle;
- }
-
- /**
- * Returns the transmit power in dBm. The valid range is [-127, 126]. Value
- * of 127 means information was not available.
- */
- public int getTxPower() {
- return mTxPower;
- }
-
- /**
- * Returns the received signal strength in dBm. The valid range is [-127, 20].
- */
- public int getRssi() {
- return mRssi;
- }
-
- /**
- * Returns the data status. Can be one of {@link PeriodicAdvertisingReport#DATA_COMPLETE}
- * or {@link PeriodicAdvertisingReport#DATA_INCOMPLETE_TRUNCATED}.
- */
- public int getDataStatus() {
- return mDataStatus;
- }
-
- /**
- * Returns the data contained in this periodic advertising report.
- */
- @Nullable
- public ScanRecord getData() {
- return mData;
- }
-
- /**
- * Returns timestamp since boot when the scan record was observed.
- */
- public long getTimestampNanos() {
- return mTimestampNanos;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mSyncHandle, mTxPower, mRssi, mDataStatus, mData, mTimestampNanos);
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- PeriodicAdvertisingReport other = (PeriodicAdvertisingReport) obj;
- return (mSyncHandle == other.mSyncHandle)
- && (mTxPower == other.mTxPower)
- && (mRssi == other.mRssi)
- && (mDataStatus == other.mDataStatus)
- && Objects.equals(mData, other.mData)
- && (mTimestampNanos == other.mTimestampNanos);
- }
-
- @Override
- public String toString() {
- return "PeriodicAdvertisingReport{syncHandle=" + mSyncHandle
- + ", txPower=" + mTxPower + ", rssi=" + mRssi + ", dataStatus=" + mDataStatus
- + ", data=" + Objects.toString(mData) + ", timestampNanos=" + mTimestampNanos + '}';
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<PeriodicAdvertisingReport> CREATOR =
- new Creator<PeriodicAdvertisingReport>() {
- @Override
- public PeriodicAdvertisingReport createFromParcel(Parcel source) {
- return new PeriodicAdvertisingReport(source);
- }
-
- @Override
- public PeriodicAdvertisingReport[] newArray(int size) {
- return new PeriodicAdvertisingReport[size];
- }
- };
-}
diff --git a/core/java/android/bluetooth/le/ResultStorageDescriptor.java b/core/java/android/bluetooth/le/ResultStorageDescriptor.java
deleted file mode 100644
index f650489..0000000
--- a/core/java/android/bluetooth/le/ResultStorageDescriptor.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Describes the way to store scan result.
- *
- * @deprecated this is not used anywhere
- *
- * @hide
- */
-@Deprecated
-@SystemApi
-public final class ResultStorageDescriptor implements Parcelable {
- private int mType;
- private int mOffset;
- private int mLength;
-
- public int getType() {
- return mType;
- }
-
- public int getOffset() {
- return mOffset;
- }
-
- public int getLength() {
- return mLength;
- }
-
- /**
- * Constructor of {@link ResultStorageDescriptor}
- *
- * @param type Type of the data.
- * @param offset Offset from start of the advertise packet payload.
- * @param length Byte length of the data
- */
- public ResultStorageDescriptor(int type, int offset, int length) {
- mType = type;
- mOffset = offset;
- mLength = length;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mType);
- dest.writeInt(mOffset);
- dest.writeInt(mLength);
- }
-
- private ResultStorageDescriptor(Parcel in) {
- ReadFromParcel(in);
- }
-
- private void ReadFromParcel(Parcel in) {
- mType = in.readInt();
- mOffset = in.readInt();
- mLength = in.readInt();
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<ResultStorageDescriptor> CREATOR =
- new Creator<ResultStorageDescriptor>() {
- @Override
- public ResultStorageDescriptor createFromParcel(Parcel source) {
- return new ResultStorageDescriptor(source);
- }
-
- @Override
- public ResultStorageDescriptor[] newArray(int size) {
- return new ResultStorageDescriptor[size];
- }
- };
-}
diff --git a/core/java/android/bluetooth/le/ScanCallback.java b/core/java/android/bluetooth/le/ScanCallback.java
deleted file mode 100644
index 53d9310..0000000
--- a/core/java/android/bluetooth/le/ScanCallback.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import java.util.List;
-
-/**
- * Bluetooth LE scan callbacks. Scan results are reported using these callbacks.
- *
- * @see BluetoothLeScanner#startScan
- */
-public abstract class ScanCallback {
- /**
- * Fails to start scan as BLE scan with the same settings is already started by the app.
- */
- public static final int SCAN_FAILED_ALREADY_STARTED = 1;
-
- /**
- * Fails to start scan as app cannot be registered.
- */
- public static final int SCAN_FAILED_APPLICATION_REGISTRATION_FAILED = 2;
-
- /**
- * Fails to start scan due an internal error
- */
- public static final int SCAN_FAILED_INTERNAL_ERROR = 3;
-
- /**
- * Fails to start power optimized scan as this feature is not supported.
- */
- public static final int SCAN_FAILED_FEATURE_UNSUPPORTED = 4;
-
- /**
- * Fails to start scan as it is out of hardware resources.
- *
- * @hide
- */
- public static final int SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5;
-
- /**
- * Fails to start scan as application tries to scan too frequently.
- * @hide
- */
- public static final int SCAN_FAILED_SCANNING_TOO_FREQUENTLY = 6;
-
- static final int NO_ERROR = 0;
-
- /**
- * Callback when a BLE advertisement has been found.
- *
- * @param callbackType Determines how this callback was triggered. Could be one of {@link
- * ScanSettings#CALLBACK_TYPE_ALL_MATCHES}, {@link ScanSettings#CALLBACK_TYPE_FIRST_MATCH} or
- * {@link ScanSettings#CALLBACK_TYPE_MATCH_LOST}
- * @param result A Bluetooth LE scan result.
- */
- public void onScanResult(int callbackType, ScanResult result) {
- }
-
- /**
- * Callback when batch results are delivered.
- *
- * @param results List of scan results that are previously scanned.
- */
- public void onBatchScanResults(List<ScanResult> results) {
- }
-
- /**
- * Callback when scan could not be started.
- *
- * @param errorCode Error code (one of SCAN_FAILED_*) for scan failure.
- */
- public void onScanFailed(int errorCode) {
- }
-}
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
deleted file mode 100644
index b059193..0000000
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ /dev/null
@@ -1,910 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import static java.util.Objects.requireNonNull;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothDevice.AddressType;
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
-
-/**
- * Criteria for filtering result from Bluetooth LE scans. A {@link ScanFilter} allows clients to
- * restrict scan results to only those that are of interest to them.
- * <p>
- * Current filtering on the following fields are supported:
- * <li>Service UUIDs which identify the bluetooth gatt services running on the device.
- * <li>Name of remote Bluetooth LE device.
- * <li>Mac address of the remote device.
- * <li>Service data which is the data associated with a service.
- * <li>Manufacturer specific data which is the data associated with a particular manufacturer.
- *
- * @see ScanResult
- * @see BluetoothLeScanner
- */
-public final class ScanFilter implements Parcelable {
-
- @Nullable
- private final String mDeviceName;
-
- @Nullable
- private final String mDeviceAddress;
-
- private final @AddressType int mAddressType;
-
- @Nullable
- private final byte[] mIrk;
-
- @Nullable
- private final ParcelUuid mServiceUuid;
- @Nullable
- private final ParcelUuid mServiceUuidMask;
-
- @Nullable
- private final ParcelUuid mServiceSolicitationUuid;
- @Nullable
- private final ParcelUuid mServiceSolicitationUuidMask;
-
- @Nullable
- private final ParcelUuid mServiceDataUuid;
- @Nullable
- private final byte[] mServiceData;
- @Nullable
- private final byte[] mServiceDataMask;
-
- private final int mManufacturerId;
- @Nullable
- private final byte[] mManufacturerData;
- @Nullable
- private final byte[] mManufacturerDataMask;
-
- /** @hide */
- public static final ScanFilter EMPTY = new ScanFilter.Builder().build();
-
- private ScanFilter(String name, String deviceAddress, ParcelUuid uuid,
- ParcelUuid uuidMask, ParcelUuid solicitationUuid,
- ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid,
- byte[] serviceData, byte[] serviceDataMask,
- int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask,
- @AddressType int addressType, @Nullable byte[] irk) {
- mDeviceName = name;
- mServiceUuid = uuid;
- mServiceUuidMask = uuidMask;
- mServiceSolicitationUuid = solicitationUuid;
- mServiceSolicitationUuidMask = solicitationUuidMask;
- mDeviceAddress = deviceAddress;
- mServiceDataUuid = serviceDataUuid;
- mServiceData = serviceData;
- mServiceDataMask = serviceDataMask;
- mManufacturerId = manufacturerId;
- mManufacturerData = manufacturerData;
- mManufacturerDataMask = manufacturerDataMask;
- mAddressType = addressType;
- mIrk = irk;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mDeviceName == null ? 0 : 1);
- if (mDeviceName != null) {
- dest.writeString(mDeviceName);
- }
- dest.writeInt(mDeviceAddress == null ? 0 : 1);
- if (mDeviceAddress != null) {
- dest.writeString(mDeviceAddress);
- }
- dest.writeInt(mServiceUuid == null ? 0 : 1);
- if (mServiceUuid != null) {
- dest.writeParcelable(mServiceUuid, flags);
- dest.writeInt(mServiceUuidMask == null ? 0 : 1);
- if (mServiceUuidMask != null) {
- dest.writeParcelable(mServiceUuidMask, flags);
- }
- }
- dest.writeInt(mServiceSolicitationUuid == null ? 0 : 1);
- if (mServiceSolicitationUuid != null) {
- dest.writeParcelable(mServiceSolicitationUuid, flags);
- dest.writeInt(mServiceSolicitationUuidMask == null ? 0 : 1);
- if (mServiceSolicitationUuidMask != null) {
- dest.writeParcelable(mServiceSolicitationUuidMask, flags);
- }
- }
- dest.writeInt(mServiceDataUuid == null ? 0 : 1);
- if (mServiceDataUuid != null) {
- dest.writeParcelable(mServiceDataUuid, flags);
- dest.writeInt(mServiceData == null ? 0 : 1);
- if (mServiceData != null) {
- dest.writeInt(mServiceData.length);
- dest.writeByteArray(mServiceData);
-
- dest.writeInt(mServiceDataMask == null ? 0 : 1);
- if (mServiceDataMask != null) {
- dest.writeInt(mServiceDataMask.length);
- dest.writeByteArray(mServiceDataMask);
- }
- }
- }
- dest.writeInt(mManufacturerId);
- dest.writeInt(mManufacturerData == null ? 0 : 1);
- if (mManufacturerData != null) {
- dest.writeInt(mManufacturerData.length);
- dest.writeByteArray(mManufacturerData);
-
- dest.writeInt(mManufacturerDataMask == null ? 0 : 1);
- if (mManufacturerDataMask != null) {
- dest.writeInt(mManufacturerDataMask.length);
- dest.writeByteArray(mManufacturerDataMask);
- }
- }
-
- // IRK
- if (mDeviceAddress != null) {
- dest.writeInt(mAddressType);
- dest.writeInt(mIrk == null ? 0 : 1);
- if (mIrk != null) {
- dest.writeByteArray(mIrk);
- }
- }
- }
-
- /**
- * A {@link android.os.Parcelable.Creator} to create {@link ScanFilter} from parcel.
- */
- public static final @android.annotation.NonNull Creator<ScanFilter> CREATOR =
- new Creator<ScanFilter>() {
-
- @Override
- public ScanFilter[] newArray(int size) {
- return new ScanFilter[size];
- }
-
- @Override
- public ScanFilter createFromParcel(Parcel in) {
- Builder builder = new Builder();
- if (in.readInt() == 1) {
- builder.setDeviceName(in.readString());
- }
- String address = null;
- // If we have a non-null address
- if (in.readInt() == 1) {
- address = in.readString();
- }
- if (in.readInt() == 1) {
- ParcelUuid uuid = in.readParcelable(ParcelUuid.class.getClassLoader());
- builder.setServiceUuid(uuid);
- if (in.readInt() == 1) {
- ParcelUuid uuidMask = in.readParcelable(
- ParcelUuid.class.getClassLoader());
- builder.setServiceUuid(uuid, uuidMask);
- }
- }
- if (in.readInt() == 1) {
- ParcelUuid solicitationUuid = in.readParcelable(
- ParcelUuid.class.getClassLoader());
- builder.setServiceSolicitationUuid(solicitationUuid);
- if (in.readInt() == 1) {
- ParcelUuid solicitationUuidMask = in.readParcelable(
- ParcelUuid.class.getClassLoader());
- builder.setServiceSolicitationUuid(solicitationUuid,
- solicitationUuidMask);
- }
- }
- if (in.readInt() == 1) {
- ParcelUuid servcieDataUuid =
- in.readParcelable(ParcelUuid.class.getClassLoader());
- if (in.readInt() == 1) {
- int serviceDataLength = in.readInt();
- byte[] serviceData = new byte[serviceDataLength];
- in.readByteArray(serviceData);
- if (in.readInt() == 0) {
- builder.setServiceData(servcieDataUuid, serviceData);
- } else {
- int serviceDataMaskLength = in.readInt();
- byte[] serviceDataMask = new byte[serviceDataMaskLength];
- in.readByteArray(serviceDataMask);
- builder.setServiceData(
- servcieDataUuid, serviceData, serviceDataMask);
- }
- }
- }
-
- int manufacturerId = in.readInt();
- if (in.readInt() == 1) {
- int manufacturerDataLength = in.readInt();
- byte[] manufacturerData = new byte[manufacturerDataLength];
- in.readByteArray(manufacturerData);
- if (in.readInt() == 0) {
- builder.setManufacturerData(manufacturerId, manufacturerData);
- } else {
- int manufacturerDataMaskLength = in.readInt();
- byte[] manufacturerDataMask = new byte[manufacturerDataMaskLength];
- in.readByteArray(manufacturerDataMask);
- builder.setManufacturerData(manufacturerId, manufacturerData,
- manufacturerDataMask);
- }
- }
-
- // IRK
- if (address != null) {
- final int addressType = in.readInt();
- if (in.readInt() == 1) {
- final byte[] irk = new byte[16];
- in.readByteArray(irk);
- builder.setDeviceAddress(address, addressType, irk);
- } else {
- builder.setDeviceAddress(address, addressType);
- }
- }
- return builder.build();
- }
- };
-
- /**
- * Returns the filter set the device name field of Bluetooth advertisement data.
- */
- @Nullable
- public String getDeviceName() {
- return mDeviceName;
- }
-
- /**
- * Returns the filter set on the service uuid.
- */
- @Nullable
- public ParcelUuid getServiceUuid() {
- return mServiceUuid;
- }
-
- @Nullable
- public ParcelUuid getServiceUuidMask() {
- return mServiceUuidMask;
- }
-
- /**
- * Returns the filter set on the service Solicitation uuid.
- */
- @Nullable
- public ParcelUuid getServiceSolicitationUuid() {
- return mServiceSolicitationUuid;
- }
-
- /**
- * Returns the filter set on the service Solicitation uuid mask.
- */
- @Nullable
- public ParcelUuid getServiceSolicitationUuidMask() {
- return mServiceSolicitationUuidMask;
- }
-
- @Nullable
- public String getDeviceAddress() {
- return mDeviceAddress;
- }
-
- /**
- * @hide
- */
- @SystemApi
- public @AddressType int getAddressType() {
- return mAddressType;
- }
-
- /**
- * @hide
- */
- @SystemApi
- @Nullable
- public byte[] getIrk() {
- return mIrk;
- }
-
- @Nullable
- public byte[] getServiceData() {
- return mServiceData;
- }
-
- @Nullable
- public byte[] getServiceDataMask() {
- return mServiceDataMask;
- }
-
- @Nullable
- public ParcelUuid getServiceDataUuid() {
- return mServiceDataUuid;
- }
-
- /**
- * Returns the manufacturer id. -1 if the manufacturer filter is not set.
- */
- public int getManufacturerId() {
- return mManufacturerId;
- }
-
- @Nullable
- public byte[] getManufacturerData() {
- return mManufacturerData;
- }
-
- @Nullable
- public byte[] getManufacturerDataMask() {
- return mManufacturerDataMask;
- }
-
- /**
- * Check if the scan filter matches a {@code scanResult}. A scan result is considered as a match
- * if it matches all the field filters.
- */
- public boolean matches(ScanResult scanResult) {
- if (scanResult == null) {
- return false;
- }
- BluetoothDevice device = scanResult.getDevice();
- // Device match.
- if (mDeviceAddress != null
- && (device == null || !mDeviceAddress.equals(device.getAddress()))) {
- return false;
- }
-
- ScanRecord scanRecord = scanResult.getScanRecord();
-
- // Scan record is null but there exist filters on it.
- if (scanRecord == null
- && (mDeviceName != null || mServiceUuid != null || mManufacturerData != null
- || mServiceData != null || mServiceSolicitationUuid != null)) {
- return false;
- }
-
- // Local name match.
- if (mDeviceName != null && !mDeviceName.equals(scanRecord.getDeviceName())) {
- return false;
- }
-
- // UUID match.
- if (mServiceUuid != null && !matchesServiceUuids(mServiceUuid, mServiceUuidMask,
- scanRecord.getServiceUuids())) {
- return false;
- }
-
- // solicitation UUID match.
- if (mServiceSolicitationUuid != null && !matchesServiceSolicitationUuids(
- mServiceSolicitationUuid, mServiceSolicitationUuidMask,
- scanRecord.getServiceSolicitationUuids())) {
- return false;
- }
-
- // Service data match
- if (mServiceDataUuid != null) {
- if (!matchesPartialData(mServiceData, mServiceDataMask,
- scanRecord.getServiceData(mServiceDataUuid))) {
- return false;
- }
- }
-
- // Manufacturer data match.
- if (mManufacturerId >= 0) {
- if (!matchesPartialData(mManufacturerData, mManufacturerDataMask,
- scanRecord.getManufacturerSpecificData(mManufacturerId))) {
- return false;
- }
- }
- // All filters match.
- return true;
- }
-
- /**
- * Check if the uuid pattern is contained in a list of parcel uuids.
- *
- * @hide
- */
- public static boolean matchesServiceUuids(ParcelUuid uuid, ParcelUuid parcelUuidMask,
- List<ParcelUuid> uuids) {
- if (uuid == null) {
- return true;
- }
- if (uuids == null) {
- return false;
- }
-
- for (ParcelUuid parcelUuid : uuids) {
- UUID uuidMask = parcelUuidMask == null ? null : parcelUuidMask.getUuid();
- if (matchesServiceUuid(uuid.getUuid(), uuidMask, parcelUuid.getUuid())) {
- return true;
- }
- }
- return false;
- }
-
- // Check if the uuid pattern matches the particular service uuid.
- private static boolean matchesServiceUuid(UUID uuid, UUID mask, UUID data) {
- return BluetoothLeUtils.maskedEquals(data, uuid, mask);
- }
-
- /**
- * Check if the solicitation uuid pattern is contained in a list of parcel uuids.
- *
- */
- private static boolean matchesServiceSolicitationUuids(ParcelUuid solicitationUuid,
- ParcelUuid parcelSolicitationUuidMask, List<ParcelUuid> solicitationUuids) {
- if (solicitationUuid == null) {
- return true;
- }
- if (solicitationUuids == null) {
- return false;
- }
-
- for (ParcelUuid parcelSolicitationUuid : solicitationUuids) {
- UUID solicitationUuidMask = parcelSolicitationUuidMask == null
- ? null : parcelSolicitationUuidMask.getUuid();
- if (matchesServiceUuid(solicitationUuid.getUuid(), solicitationUuidMask,
- parcelSolicitationUuid.getUuid())) {
- return true;
- }
- }
- return false;
- }
-
- // Check if the solicitation uuid pattern matches the particular service solicitation uuid.
- private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid,
- UUID solicitationUuidMask, UUID data) {
- return BluetoothLeUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask);
- }
-
- // Check whether the data pattern matches the parsed data.
- private boolean matchesPartialData(byte[] data, byte[] dataMask, byte[] parsedData) {
- if (parsedData == null || parsedData.length < data.length) {
- return false;
- }
- if (dataMask == null) {
- for (int i = 0; i < data.length; ++i) {
- if (parsedData[i] != data[i]) {
- return false;
- }
- }
- return true;
- }
- for (int i = 0; i < data.length; ++i) {
- if ((dataMask[i] & parsedData[i]) != (dataMask[i] & data[i])) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public String toString() {
- return "BluetoothLeScanFilter [mDeviceName=" + mDeviceName + ", mDeviceAddress="
- + mDeviceAddress
- + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask
- + ", mServiceSolicitationUuid=" + mServiceSolicitationUuid
- + ", mServiceSolicitationUuidMask=" + mServiceSolicitationUuidMask
- + ", mServiceDataUuid=" + Objects.toString(mServiceDataUuid) + ", mServiceData="
- + Arrays.toString(mServiceData) + ", mServiceDataMask="
- + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId
- + ", mManufacturerData=" + Arrays.toString(mManufacturerData)
- + ", mManufacturerDataMask=" + Arrays.toString(mManufacturerDataMask) + "]";
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mDeviceName, mDeviceAddress, mManufacturerId,
- Arrays.hashCode(mManufacturerData),
- Arrays.hashCode(mManufacturerDataMask),
- mServiceDataUuid,
- Arrays.hashCode(mServiceData),
- Arrays.hashCode(mServiceDataMask),
- mServiceUuid, mServiceUuidMask,
- mServiceSolicitationUuid, mServiceSolicitationUuidMask);
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- ScanFilter other = (ScanFilter) obj;
- return Objects.equals(mDeviceName, other.mDeviceName)
- && Objects.equals(mDeviceAddress, other.mDeviceAddress)
- && mManufacturerId == other.mManufacturerId
- && Objects.deepEquals(mManufacturerData, other.mManufacturerData)
- && Objects.deepEquals(mManufacturerDataMask, other.mManufacturerDataMask)
- && Objects.equals(mServiceDataUuid, other.mServiceDataUuid)
- && Objects.deepEquals(mServiceData, other.mServiceData)
- && Objects.deepEquals(mServiceDataMask, other.mServiceDataMask)
- && Objects.equals(mServiceUuid, other.mServiceUuid)
- && Objects.equals(mServiceUuidMask, other.mServiceUuidMask)
- && Objects.equals(mServiceSolicitationUuid, other.mServiceSolicitationUuid)
- && Objects.equals(mServiceSolicitationUuidMask,
- other.mServiceSolicitationUuidMask);
- }
-
- /**
- * Checks if the scanfilter is empty
- *
- * @hide
- */
- public boolean isAllFieldsEmpty() {
- return EMPTY.equals(this);
- }
-
- /**
- * Builder class for {@link ScanFilter}.
- */
- public static final class Builder {
-
- /**
- * @hide
- */
- @SystemApi
- public static final int LEN_IRK_OCTETS = 16;
-
- private String mDeviceName;
- private String mDeviceAddress;
- private @AddressType int mAddressType = BluetoothDevice.ADDRESS_TYPE_PUBLIC;
- private byte[] mIrk;
-
- private ParcelUuid mServiceUuid;
- private ParcelUuid mUuidMask;
-
- private ParcelUuid mServiceSolicitationUuid;
- private ParcelUuid mServiceSolicitationUuidMask;
-
- private ParcelUuid mServiceDataUuid;
- private byte[] mServiceData;
- private byte[] mServiceDataMask;
-
- private int mManufacturerId = -1;
- private byte[] mManufacturerData;
- private byte[] mManufacturerDataMask;
-
- /**
- * Set filter on device name.
- */
- public Builder setDeviceName(String deviceName) {
- mDeviceName = deviceName;
- return this;
- }
-
- /**
- * Set filter on device address.
- *
- * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
- * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
- * BluetoothAdapter#checkBluetoothAddress}. The @AddressType is defaulted to {@link
- * BluetoothDevice#ADDRESS_TYPE_PUBLIC}
- * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
- */
- public Builder setDeviceAddress(String deviceAddress) {
- if (deviceAddress == null) {
- mDeviceAddress = deviceAddress;
- return this;
- }
- return setDeviceAddress(deviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
- }
-
- /**
- * Set filter on Address with AddressType
- *
- * <p>This key is used to resolve a private address from a public address.
- *
- * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
- * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
- * BluetoothAdapter#checkBluetoothAddress}. May be any type of address.
- * @param addressType indication of the type of address
- * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
- * or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM}
- *
- * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
- * @throws IllegalArgumentException If the {@code addressType} is invalid length
- * @throws NullPointerException if {@code deviceAddress} is null.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public Builder setDeviceAddress(@NonNull String deviceAddress,
- @AddressType int addressType) {
- return setDeviceAddressInternal(deviceAddress, addressType, null);
- }
-
- /**
- * Set filter on Address with AddressType and the Identity Resolving Key (IRK).
- *
- * <p>The IRK is used to resolve a {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC} from
- * a PRIVATE_ADDRESS type.
- *
- * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
- * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
- * BluetoothAdapter#checkBluetoothAddress}. This Address type must only be PUBLIC OR RANDOM
- * STATIC.
- * @param addressType indication of the type of address
- * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
- * or {@link BluetoothDevice#ADDRESS_TYPE_RANDOM}
- * @param irk non-null byte array representing the Identity Resolving Key
- *
- * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
- * @throws IllegalArgumentException if the {@code irk} is invalid length.
- * @throws IllegalArgumentException If the {@code addressType} is invalid length or is not
- * PUBLIC or RANDOM STATIC when an IRK is present.
- * @throws NullPointerException if {@code deviceAddress} or {@code irk} is null.
- *
- * @hide
- */
- @NonNull
- @SystemApi
- public Builder setDeviceAddress(@NonNull String deviceAddress,
- @AddressType int addressType,
- @NonNull byte[] irk) {
- requireNonNull(irk);
- if (irk.length != LEN_IRK_OCTETS) {
- throw new IllegalArgumentException("'irk' is invalid length!");
- }
- return setDeviceAddressInternal(deviceAddress, addressType, irk);
- }
-
- /**
- * Set filter on Address with AddressType and the Identity Resolving Key (IRK).
- *
- * <p>Internal setter for the device address
- *
- * @param deviceAddress The device Bluetooth address for the filter. It needs to be in the
- * format of "01:02:03:AB:CD:EF". The device address can be validated using {@link
- * BluetoothAdapter#checkBluetoothAddress}.
- * @param addressType indication of the type of address
- * e.g. {@link BluetoothDevice#ADDRESS_TYPE_PUBLIC}
- * @param irk non-null byte array representing the Identity Resolving Address; nullable
- * internally.
- *
- * @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
- * @throws IllegalArgumentException If the {@code addressType} is invalid length.
- * @throws NullPointerException if {@code deviceAddress} is null.
- *
- * @hide
- */
- @NonNull
- private Builder setDeviceAddressInternal(@NonNull String deviceAddress,
- @AddressType int addressType,
- @Nullable byte[] irk) {
-
- // Make sure our deviceAddress is valid!
- requireNonNull(deviceAddress);
- if (!BluetoothAdapter.checkBluetoothAddress(deviceAddress)) {
- throw new IllegalArgumentException("invalid device address " + deviceAddress);
- }
-
- // Verify type range
- if (addressType < BluetoothDevice.ADDRESS_TYPE_PUBLIC
- || addressType > BluetoothDevice.ADDRESS_TYPE_RANDOM) {
- throw new IllegalArgumentException("'addressType' is invalid!");
- }
-
- // IRK can only be used for a PUBLIC or RANDOM (STATIC) Address.
- if (addressType == BluetoothDevice.ADDRESS_TYPE_RANDOM) {
- // Don't want a bad combination of address and irk!
- if (irk != null) {
- // Since there are 3 possible RANDOM subtypes we must check to make sure
- // the correct type of address is used.
- if (!BluetoothAdapter.isAddressRandomStatic(deviceAddress)) {
- throw new IllegalArgumentException(
- "Invalid combination: IRK requires either a PUBLIC or "
- + "RANDOM (STATIC) Address");
- }
- }
- }
-
- // PUBLIC doesn't require extra work
- // Without an IRK any address may be accepted
-
- mDeviceAddress = deviceAddress;
- mAddressType = addressType;
- mIrk = irk;
- return this;
- }
-
- /**
- * Set filter on service uuid.
- */
- public Builder setServiceUuid(ParcelUuid serviceUuid) {
- mServiceUuid = serviceUuid;
- mUuidMask = null; // clear uuid mask
- return this;
- }
-
- /**
- * Set filter on partial service uuid. The {@code uuidMask} is the bit mask for the
- * {@code serviceUuid}. Set any bit in the mask to 1 to indicate a match is needed for the
- * bit in {@code serviceUuid}, and 0 to ignore that bit.
- *
- * @throws IllegalArgumentException If {@code serviceUuid} is {@code null} but {@code
- * uuidMask} is not {@code null}.
- */
- public Builder setServiceUuid(ParcelUuid serviceUuid, ParcelUuid uuidMask) {
- if (mUuidMask != null && mServiceUuid == null) {
- throw new IllegalArgumentException("uuid is null while uuidMask is not null!");
- }
- mServiceUuid = serviceUuid;
- mUuidMask = uuidMask;
- return this;
- }
-
-
- /**
- * Set filter on service solicitation uuid.
- */
- public @NonNull Builder setServiceSolicitationUuid(
- @Nullable ParcelUuid serviceSolicitationUuid) {
- mServiceSolicitationUuid = serviceSolicitationUuid;
- if (serviceSolicitationUuid == null) {
- mServiceSolicitationUuidMask = null;
- }
- return this;
- }
-
-
- /**
- * Set filter on partial service Solicitation uuid. The {@code SolicitationUuidMask} is the
- * bit mask for the {@code serviceSolicitationUuid}. Set any bit in the mask to 1 to
- * indicate a match is needed for the bit in {@code serviceSolicitationUuid}, and 0 to
- * ignore that bit.
- *
- * @param serviceSolicitationUuid can only be null if solicitationUuidMask is null.
- * @param solicitationUuidMask can be null or a mask with no restriction.
- *
- * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but
- * {@code serviceSolicitationUuidMask} is not {@code null}.
- */
- public @NonNull Builder setServiceSolicitationUuid(
- @Nullable ParcelUuid serviceSolicitationUuid,
- @Nullable ParcelUuid solicitationUuidMask) {
- if (solicitationUuidMask != null && serviceSolicitationUuid == null) {
- throw new IllegalArgumentException(
- "SolicitationUuid is null while SolicitationUuidMask is not null!");
- }
- mServiceSolicitationUuid = serviceSolicitationUuid;
- mServiceSolicitationUuidMask = solicitationUuidMask;
- return this;
- }
-
- /**
- * Set filtering on service data.
- *
- * @throws IllegalArgumentException If {@code serviceDataUuid} is null.
- */
- public Builder setServiceData(ParcelUuid serviceDataUuid, byte[] serviceData) {
- if (serviceDataUuid == null) {
- throw new IllegalArgumentException("serviceDataUuid is null");
- }
- mServiceDataUuid = serviceDataUuid;
- mServiceData = serviceData;
- mServiceDataMask = null; // clear service data mask
- return this;
- }
-
- /**
- * Set partial filter on service data. For any bit in the mask, set it to 1 if it needs to
- * match the one in service data, otherwise set it to 0 to ignore that bit.
- * <p>
- * The {@code serviceDataMask} must have the same length of the {@code serviceData}.
- *
- * @throws IllegalArgumentException If {@code serviceDataUuid} is null or {@code
- * serviceDataMask} is {@code null} while {@code serviceData} is not or {@code
- * serviceDataMask} and {@code serviceData} has different length.
- */
- public Builder setServiceData(ParcelUuid serviceDataUuid,
- byte[] serviceData, byte[] serviceDataMask) {
- if (serviceDataUuid == null) {
- throw new IllegalArgumentException("serviceDataUuid is null");
- }
- if (mServiceDataMask != null) {
- if (mServiceData == null) {
- throw new IllegalArgumentException(
- "serviceData is null while serviceDataMask is not null");
- }
- // Since the mServiceDataMask is a bit mask for mServiceData, the lengths of the two
- // byte array need to be the same.
- if (mServiceData.length != mServiceDataMask.length) {
- throw new IllegalArgumentException(
- "size mismatch for service data and service data mask");
- }
- }
- mServiceDataUuid = serviceDataUuid;
- mServiceData = serviceData;
- mServiceDataMask = serviceDataMask;
- return this;
- }
-
- /**
- * Set filter on on manufacturerData. A negative manufacturerId is considered as invalid id.
- *
- * @throws IllegalArgumentException If the {@code manufacturerId} is invalid.
- */
- public Builder setManufacturerData(int manufacturerId, byte[] manufacturerData) {
- if (manufacturerData != null && manufacturerId < 0) {
- throw new IllegalArgumentException("invalid manufacture id");
- }
- mManufacturerId = manufacturerId;
- mManufacturerData = manufacturerData;
- mManufacturerDataMask = null; // clear manufacturer data mask
- return this;
- }
-
- /**
- * Set filter on partial manufacture data. For any bit in the mask, set it the 1 if it needs
- * to match the one in manufacturer data, otherwise set it to 0.
- * <p>
- * The {@code manufacturerDataMask} must have the same length of {@code manufacturerData}.
- *
- * @throws IllegalArgumentException If the {@code manufacturerId} is invalid, or {@code
- * manufacturerData} is null while {@code manufacturerDataMask} is not, or {@code
- * manufacturerData} and {@code manufacturerDataMask} have different length.
- */
- public Builder setManufacturerData(int manufacturerId, byte[] manufacturerData,
- byte[] manufacturerDataMask) {
- if (manufacturerData != null && manufacturerId < 0) {
- throw new IllegalArgumentException("invalid manufacture id");
- }
- if (mManufacturerDataMask != null) {
- if (mManufacturerData == null) {
- throw new IllegalArgumentException(
- "manufacturerData is null while manufacturerDataMask is not null");
- }
- // Since the mManufacturerDataMask is a bit mask for mManufacturerData, the lengths
- // of the two byte array need to be the same.
- if (mManufacturerData.length != mManufacturerDataMask.length) {
- throw new IllegalArgumentException(
- "size mismatch for manufacturerData and manufacturerDataMask");
- }
- }
- mManufacturerId = manufacturerId;
- mManufacturerData = manufacturerData;
- mManufacturerDataMask = manufacturerDataMask;
- return this;
- }
-
- /**
- * Build {@link ScanFilter}.
- *
- * @throws IllegalArgumentException If the filter cannot be built.
- */
- public ScanFilter build() {
- return new ScanFilter(mDeviceName, mDeviceAddress,
- mServiceUuid, mUuidMask, mServiceSolicitationUuid,
- mServiceSolicitationUuidMask,
- mServiceDataUuid, mServiceData, mServiceDataMask,
- mManufacturerId, mManufacturerData, mManufacturerDataMask,
- mAddressType, mIrk);
- }
- }
-}
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
deleted file mode 100644
index 9b8c2ea..0000000
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SuppressLint;
-import android.bluetooth.BluetoothUuid;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.os.ParcelUuid;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Predicate;
-
-/**
- * Represents a scan record from Bluetooth LE scan.
- */
-@SuppressLint("AndroidFrameworkBluetoothPermission")
-public final class ScanRecord {
-
- private static final String TAG = "ScanRecord";
-
- // The following data type values are assigned by Bluetooth SIG.
- // For more details refer to Bluetooth 4.1 specification, Volume 3, Part C, Section 18.
- private static final int DATA_TYPE_FLAGS = 0x01;
- private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL = 0x02;
- private static final int DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE = 0x03;
- private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL = 0x04;
- private static final int DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE = 0x05;
- private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL = 0x06;
- private static final int DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE = 0x07;
- private static final int DATA_TYPE_LOCAL_NAME_SHORT = 0x08;
- private static final int DATA_TYPE_LOCAL_NAME_COMPLETE = 0x09;
- private static final int DATA_TYPE_TX_POWER_LEVEL = 0x0A;
- private static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16;
- private static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20;
- private static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21;
- private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT = 0x14;
- private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT = 0x1F;
- private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15;
- private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF;
-
- // Flags of the advertising data.
- private final int mAdvertiseFlags;
-
- @Nullable
- private final List<ParcelUuid> mServiceUuids;
- @Nullable
- private final List<ParcelUuid> mServiceSolicitationUuids;
-
- private final SparseArray<byte[]> mManufacturerSpecificData;
-
- private final Map<ParcelUuid, byte[]> mServiceData;
-
- // Transmission power level(in dB).
- private final int mTxPowerLevel;
-
- // Local name of the Bluetooth LE device.
- private final String mDeviceName;
-
- // Raw bytes of scan record.
- private final byte[] mBytes;
-
- /**
- * Returns the advertising flags indicating the discoverable mode and capability of the device.
- * Returns -1 if the flag field is not set.
- */
- public int getAdvertiseFlags() {
- return mAdvertiseFlags;
- }
-
- /**
- * Returns a list of service UUIDs within the advertisement that are used to identify the
- * bluetooth GATT services.
- */
- public List<ParcelUuid> getServiceUuids() {
- return mServiceUuids;
- }
-
- /**
- * Returns a list of service solicitation UUIDs within the advertisement that are used to
- * identify the Bluetooth GATT services.
- */
- @NonNull
- public List<ParcelUuid> getServiceSolicitationUuids() {
- return mServiceSolicitationUuids;
- }
-
- /**
- * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific
- * data.
- */
- public SparseArray<byte[]> getManufacturerSpecificData() {
- return mManufacturerSpecificData;
- }
-
- /**
- * Returns the manufacturer specific data associated with the manufacturer id. Returns
- * {@code null} if the {@code manufacturerId} is not found.
- */
- @Nullable
- public byte[] getManufacturerSpecificData(int manufacturerId) {
- if (mManufacturerSpecificData == null) {
- return null;
- }
- return mManufacturerSpecificData.get(manufacturerId);
- }
-
- /**
- * Returns a map of service UUID and its corresponding service data.
- */
- public Map<ParcelUuid, byte[]> getServiceData() {
- return mServiceData;
- }
-
- /**
- * Returns the service data byte array associated with the {@code serviceUuid}. Returns
- * {@code null} if the {@code serviceDataUuid} is not found.
- */
- @Nullable
- public byte[] getServiceData(ParcelUuid serviceDataUuid) {
- if (serviceDataUuid == null || mServiceData == null) {
- return null;
- }
- return mServiceData.get(serviceDataUuid);
- }
-
- /**
- * Returns the transmission power level of the packet in dBm. Returns {@link Integer#MIN_VALUE}
- * if the field is not set. This value can be used to calculate the path loss of a received
- * packet using the following equation:
- * <p>
- * <code>pathloss = txPowerLevel - rssi</code>
- */
- public int getTxPowerLevel() {
- return mTxPowerLevel;
- }
-
- /**
- * Returns the local name of the BLE device. This is a UTF-8 encoded string.
- */
- @Nullable
- public String getDeviceName() {
- return mDeviceName;
- }
-
- /**
- * Returns raw bytes of scan record.
- */
- public byte[] getBytes() {
- return mBytes;
- }
-
- /**
- * Test if any fields contained inside this scan record are matched by the
- * given matcher.
- *
- * @hide
- */
- public boolean matchesAnyField(@NonNull Predicate<byte[]> matcher) {
- int pos = 0;
- while (pos < mBytes.length) {
- final int length = mBytes[pos] & 0xFF;
- if (length == 0) {
- break;
- }
- if (matcher.test(Arrays.copyOfRange(mBytes, pos, pos + length + 1))) {
- return true;
- }
- pos += length + 1;
- }
- return false;
- }
-
- private ScanRecord(List<ParcelUuid> serviceUuids,
- List<ParcelUuid> serviceSolicitationUuids,
- SparseArray<byte[]> manufacturerData,
- Map<ParcelUuid, byte[]> serviceData,
- int advertiseFlags, int txPowerLevel,
- String localName, byte[] bytes) {
- mServiceSolicitationUuids = serviceSolicitationUuids;
- mServiceUuids = serviceUuids;
- mManufacturerSpecificData = manufacturerData;
- mServiceData = serviceData;
- mDeviceName = localName;
- mAdvertiseFlags = advertiseFlags;
- mTxPowerLevel = txPowerLevel;
- mBytes = bytes;
- }
-
- /**
- * Parse scan record bytes to {@link ScanRecord}.
- * <p>
- * The format is defined in Bluetooth 4.1 specification, Volume 3, Part C, Section 11 and 18.
- * <p>
- * All numerical multi-byte entities and values shall use little-endian <strong>byte</strong>
- * order.
- *
- * @param scanRecord The scan record of Bluetooth LE advertisement and/or scan response.
- * @hide
- */
- @UnsupportedAppUsage
- public static ScanRecord parseFromBytes(byte[] scanRecord) {
- if (scanRecord == null) {
- return null;
- }
-
- int currentPos = 0;
- int advertiseFlag = -1;
- List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>();
- List<ParcelUuid> serviceSolicitationUuids = new ArrayList<ParcelUuid>();
- String localName = null;
- int txPowerLevel = Integer.MIN_VALUE;
-
- SparseArray<byte[]> manufacturerData = new SparseArray<byte[]>();
- Map<ParcelUuid, byte[]> serviceData = new ArrayMap<ParcelUuid, byte[]>();
-
- try {
- while (currentPos < scanRecord.length) {
- // length is unsigned int.
- int length = scanRecord[currentPos++] & 0xFF;
- if (length == 0) {
- break;
- }
- // Note the length includes the length of the field type itself.
- int dataLength = length - 1;
- // fieldType is unsigned int.
- int fieldType = scanRecord[currentPos++] & 0xFF;
- switch (fieldType) {
- case DATA_TYPE_FLAGS:
- advertiseFlag = scanRecord[currentPos] & 0xFF;
- break;
- case DATA_TYPE_SERVICE_UUIDS_16_BIT_PARTIAL:
- case DATA_TYPE_SERVICE_UUIDS_16_BIT_COMPLETE:
- parseServiceUuid(scanRecord, currentPos,
- dataLength, BluetoothUuid.UUID_BYTES_16_BIT, serviceUuids);
- break;
- case DATA_TYPE_SERVICE_UUIDS_32_BIT_PARTIAL:
- case DATA_TYPE_SERVICE_UUIDS_32_BIT_COMPLETE:
- parseServiceUuid(scanRecord, currentPos, dataLength,
- BluetoothUuid.UUID_BYTES_32_BIT, serviceUuids);
- break;
- case DATA_TYPE_SERVICE_UUIDS_128_BIT_PARTIAL:
- case DATA_TYPE_SERVICE_UUIDS_128_BIT_COMPLETE:
- parseServiceUuid(scanRecord, currentPos, dataLength,
- BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids);
- break;
- case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT:
- parseServiceSolicitationUuid(scanRecord, currentPos, dataLength,
- BluetoothUuid.UUID_BYTES_16_BIT, serviceSolicitationUuids);
- break;
- case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT:
- parseServiceSolicitationUuid(scanRecord, currentPos, dataLength,
- BluetoothUuid.UUID_BYTES_32_BIT, serviceSolicitationUuids);
- break;
- case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT:
- parseServiceSolicitationUuid(scanRecord, currentPos, dataLength,
- BluetoothUuid.UUID_BYTES_128_BIT, serviceSolicitationUuids);
- break;
- case DATA_TYPE_LOCAL_NAME_SHORT:
- case DATA_TYPE_LOCAL_NAME_COMPLETE:
- localName = new String(
- extractBytes(scanRecord, currentPos, dataLength));
- break;
- case DATA_TYPE_TX_POWER_LEVEL:
- txPowerLevel = scanRecord[currentPos];
- break;
- case DATA_TYPE_SERVICE_DATA_16_BIT:
- case DATA_TYPE_SERVICE_DATA_32_BIT:
- case DATA_TYPE_SERVICE_DATA_128_BIT:
- int serviceUuidLength = BluetoothUuid.UUID_BYTES_16_BIT;
- if (fieldType == DATA_TYPE_SERVICE_DATA_32_BIT) {
- serviceUuidLength = BluetoothUuid.UUID_BYTES_32_BIT;
- } else if (fieldType == DATA_TYPE_SERVICE_DATA_128_BIT) {
- serviceUuidLength = BluetoothUuid.UUID_BYTES_128_BIT;
- }
-
- byte[] serviceDataUuidBytes = extractBytes(scanRecord, currentPos,
- serviceUuidLength);
- ParcelUuid serviceDataUuid = BluetoothUuid.parseUuidFrom(
- serviceDataUuidBytes);
- byte[] serviceDataArray = extractBytes(scanRecord,
- currentPos + serviceUuidLength, dataLength - serviceUuidLength);
- serviceData.put(serviceDataUuid, serviceDataArray);
- break;
- case DATA_TYPE_MANUFACTURER_SPECIFIC_DATA:
- // The first two bytes of the manufacturer specific data are
- // manufacturer ids in little endian.
- int manufacturerId = ((scanRecord[currentPos + 1] & 0xFF) << 8)
- + (scanRecord[currentPos] & 0xFF);
- byte[] manufacturerDataBytes = extractBytes(scanRecord, currentPos + 2,
- dataLength - 2);
- manufacturerData.put(manufacturerId, manufacturerDataBytes);
- break;
- default:
- // Just ignore, we don't handle such data type.
- break;
- }
- currentPos += dataLength;
- }
-
- if (serviceUuids.isEmpty()) {
- serviceUuids = null;
- }
- return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData,
- serviceData, advertiseFlag, txPowerLevel, localName, scanRecord);
- } catch (Exception e) {
- Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord));
- // As the record is invalid, ignore all the parsed results for this packet
- // and return an empty record with raw scanRecord bytes in results
- return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, scanRecord);
- }
- }
-
- @Override
- public String toString() {
- return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids
- + ", mServiceSolicitationUuids=" + mServiceSolicitationUuids
- + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString(
- mManufacturerSpecificData)
- + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData)
- + ", mTxPowerLevel=" + mTxPowerLevel + ", mDeviceName=" + mDeviceName + "]";
- }
-
- // Parse service UUIDs.
- private static int parseServiceUuid(byte[] scanRecord, int currentPos, int dataLength,
- int uuidLength, List<ParcelUuid> serviceUuids) {
- while (dataLength > 0) {
- byte[] uuidBytes = extractBytes(scanRecord, currentPos,
- uuidLength);
- serviceUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
- dataLength -= uuidLength;
- currentPos += uuidLength;
- }
- return currentPos;
- }
-
- /**
- * Parse service Solicitation UUIDs.
- */
- private static int parseServiceSolicitationUuid(byte[] scanRecord, int currentPos,
- int dataLength, int uuidLength, List<ParcelUuid> serviceSolicitationUuids) {
- while (dataLength > 0) {
- byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength);
- serviceSolicitationUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes));
- dataLength -= uuidLength;
- currentPos += uuidLength;
- }
- return currentPos;
- }
-
- // Helper method to extract bytes from byte array.
- private static byte[] extractBytes(byte[] scanRecord, int start, int length) {
- byte[] bytes = new byte[length];
- System.arraycopy(scanRecord, start, bytes, 0, length);
- return bytes;
- }
-}
diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java
deleted file mode 100644
index f437d86..0000000
--- a/core/java/android/bluetooth/le/ScanResult.java
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.bluetooth.Attributable;
-import android.bluetooth.BluetoothDevice;
-import android.content.AttributionSource;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * ScanResult for Bluetooth LE scan.
- */
-public final class ScanResult implements Parcelable, Attributable {
-
- /**
- * For chained advertisements, inidcates tha the data contained in this
- * scan result is complete.
- */
- public static final int DATA_COMPLETE = 0x00;
-
- /**
- * For chained advertisements, indicates that the controller was
- * unable to receive all chained packets and the scan result contains
- * incomplete truncated data.
- */
- public static final int DATA_TRUNCATED = 0x02;
-
- /**
- * Indicates that the secondary physical layer was not used.
- */
- public static final int PHY_UNUSED = 0x00;
-
- /**
- * Advertising Set ID is not present in the packet.
- */
- public static final int SID_NOT_PRESENT = 0xFF;
-
- /**
- * TX power is not present in the packet.
- */
- public static final int TX_POWER_NOT_PRESENT = 0x7F;
-
- /**
- * Periodic advertising interval is not present in the packet.
- */
- public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0x00;
-
- /**
- * Mask for checking whether event type represents legacy advertisement.
- */
- private static final int ET_LEGACY_MASK = 0x10;
-
- /**
- * Mask for checking whether event type represents connectable advertisement.
- */
- private static final int ET_CONNECTABLE_MASK = 0x01;
-
- // Remote Bluetooth device.
- private BluetoothDevice mDevice;
-
- // Scan record, including advertising data and scan response data.
- @Nullable
- private ScanRecord mScanRecord;
-
- // Received signal strength.
- private int mRssi;
-
- // Device timestamp when the result was last seen.
- private long mTimestampNanos;
-
- private int mEventType;
- private int mPrimaryPhy;
- private int mSecondaryPhy;
- private int mAdvertisingSid;
- private int mTxPower;
- private int mPeriodicAdvertisingInterval;
-
- /**
- * Constructs a new ScanResult.
- *
- * @param device Remote Bluetooth device found.
- * @param scanRecord Scan record including both advertising data and scan response data.
- * @param rssi Received signal strength.
- * @param timestampNanos Timestamp at which the scan result was observed.
- * @deprecated use {@link #ScanResult(BluetoothDevice, int, int, int, int, int, int, int,
- * ScanRecord, long)}
- */
- @Deprecated
- public ScanResult(BluetoothDevice device, ScanRecord scanRecord, int rssi,
- long timestampNanos) {
- mDevice = device;
- mScanRecord = scanRecord;
- mRssi = rssi;
- mTimestampNanos = timestampNanos;
- mEventType = (DATA_COMPLETE << 5) | ET_LEGACY_MASK | ET_CONNECTABLE_MASK;
- mPrimaryPhy = BluetoothDevice.PHY_LE_1M;
- mSecondaryPhy = PHY_UNUSED;
- mAdvertisingSid = SID_NOT_PRESENT;
- mTxPower = 127;
- mPeriodicAdvertisingInterval = 0;
- }
-
- /**
- * Constructs a new ScanResult.
- *
- * @param device Remote Bluetooth device found.
- * @param eventType Event type.
- * @param primaryPhy Primary advertising phy.
- * @param secondaryPhy Secondary advertising phy.
- * @param advertisingSid Advertising set ID.
- * @param txPower Transmit power.
- * @param rssi Received signal strength.
- * @param periodicAdvertisingInterval Periodic advertising interval.
- * @param scanRecord Scan record including both advertising data and scan response data.
- * @param timestampNanos Timestamp at which the scan result was observed.
- */
- public ScanResult(BluetoothDevice device, int eventType, int primaryPhy, int secondaryPhy,
- int advertisingSid, int txPower, int rssi, int periodicAdvertisingInterval,
- ScanRecord scanRecord, long timestampNanos) {
- mDevice = device;
- mEventType = eventType;
- mPrimaryPhy = primaryPhy;
- mSecondaryPhy = secondaryPhy;
- mAdvertisingSid = advertisingSid;
- mTxPower = txPower;
- mRssi = rssi;
- mPeriodicAdvertisingInterval = periodicAdvertisingInterval;
- mScanRecord = scanRecord;
- mTimestampNanos = timestampNanos;
- }
-
- private ScanResult(Parcel in) {
- readFromParcel(in);
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- if (mDevice != null) {
- dest.writeInt(1);
- mDevice.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
- if (mScanRecord != null) {
- dest.writeInt(1);
- dest.writeByteArray(mScanRecord.getBytes());
- } else {
- dest.writeInt(0);
- }
- dest.writeInt(mRssi);
- dest.writeLong(mTimestampNanos);
- dest.writeInt(mEventType);
- dest.writeInt(mPrimaryPhy);
- dest.writeInt(mSecondaryPhy);
- dest.writeInt(mAdvertisingSid);
- dest.writeInt(mTxPower);
- dest.writeInt(mPeriodicAdvertisingInterval);
- }
-
- private void readFromParcel(Parcel in) {
- if (in.readInt() == 1) {
- mDevice = BluetoothDevice.CREATOR.createFromParcel(in);
- }
- if (in.readInt() == 1) {
- mScanRecord = ScanRecord.parseFromBytes(in.createByteArray());
- }
- mRssi = in.readInt();
- mTimestampNanos = in.readLong();
- mEventType = in.readInt();
- mPrimaryPhy = in.readInt();
- mSecondaryPhy = in.readInt();
- mAdvertisingSid = in.readInt();
- mTxPower = in.readInt();
- mPeriodicAdvertisingInterval = in.readInt();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** {@hide} */
- public void setAttributionSource(@NonNull AttributionSource attributionSource) {
- Attributable.setAttributionSource(mDevice, attributionSource);
- }
-
- /**
- * Returns the remote Bluetooth device identified by the Bluetooth device address.
- */
- public BluetoothDevice getDevice() {
- return mDevice;
- }
-
- /**
- * Returns the scan record, which is a combination of advertisement and scan response.
- */
- @Nullable
- public ScanRecord getScanRecord() {
- return mScanRecord;
- }
-
- /**
- * Returns the received signal strength in dBm. The valid range is [-127, 126].
- */
- public int getRssi() {
- return mRssi;
- }
-
- /**
- * Returns timestamp since boot when the scan record was observed.
- */
- public long getTimestampNanos() {
- return mTimestampNanos;
- }
-
- /**
- * Returns true if this object represents legacy scan result.
- * Legacy scan results do not contain advanced advertising information
- * as specified in the Bluetooth Core Specification v5.
- */
- public boolean isLegacy() {
- return (mEventType & ET_LEGACY_MASK) != 0;
- }
-
- /**
- * Returns true if this object represents connectable scan result.
- */
- public boolean isConnectable() {
- return (mEventType & ET_CONNECTABLE_MASK) != 0;
- }
-
- /**
- * Returns the data status.
- * Can be one of {@link ScanResult#DATA_COMPLETE} or
- * {@link ScanResult#DATA_TRUNCATED}.
- */
- public int getDataStatus() {
- // return bit 5 and 6
- return (mEventType >> 5) & 0x03;
- }
-
- /**
- * Returns the primary Physical Layer
- * on which this advertisment was received.
- * Can be one of {@link BluetoothDevice#PHY_LE_1M} or
- * {@link BluetoothDevice#PHY_LE_CODED}.
- */
- public int getPrimaryPhy() {
- return mPrimaryPhy;
- }
-
- /**
- * Returns the secondary Physical Layer
- * on which this advertisment was received.
- * Can be one of {@link BluetoothDevice#PHY_LE_1M},
- * {@link BluetoothDevice#PHY_LE_2M}, {@link BluetoothDevice#PHY_LE_CODED}
- * or {@link ScanResult#PHY_UNUSED} - if the advertisement
- * was not received on a secondary physical channel.
- */
- public int getSecondaryPhy() {
- return mSecondaryPhy;
- }
-
- /**
- * Returns the advertising set id.
- * May return {@link ScanResult#SID_NOT_PRESENT} if
- * no set id was is present.
- */
- public int getAdvertisingSid() {
- return mAdvertisingSid;
- }
-
- /**
- * Returns the transmit power in dBm.
- * Valid range is [-127, 126]. A value of {@link ScanResult#TX_POWER_NOT_PRESENT}
- * indicates that the TX power is not present.
- */
- public int getTxPower() {
- return mTxPower;
- }
-
- /**
- * Returns the periodic advertising interval in units of 1.25ms.
- * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of
- * {@link ScanResult#PERIODIC_INTERVAL_NOT_PRESENT} means periodic
- * advertising interval is not present.
- */
- public int getPeriodicAdvertisingInterval() {
- return mPeriodicAdvertisingInterval;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mDevice, mRssi, mScanRecord, mTimestampNanos,
- mEventType, mPrimaryPhy, mSecondaryPhy,
- mAdvertisingSid, mTxPower,
- mPeriodicAdvertisingInterval);
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- ScanResult other = (ScanResult) obj;
- return Objects.equals(mDevice, other.mDevice) && (mRssi == other.mRssi)
- && Objects.equals(mScanRecord, other.mScanRecord)
- && (mTimestampNanos == other.mTimestampNanos)
- && mEventType == other.mEventType
- && mPrimaryPhy == other.mPrimaryPhy
- && mSecondaryPhy == other.mSecondaryPhy
- && mAdvertisingSid == other.mAdvertisingSid
- && mTxPower == other.mTxPower
- && mPeriodicAdvertisingInterval == other.mPeriodicAdvertisingInterval;
- }
-
- @Override
- public String toString() {
- return "ScanResult{" + "device=" + mDevice + ", scanRecord="
- + Objects.toString(mScanRecord) + ", rssi=" + mRssi
- + ", timestampNanos=" + mTimestampNanos + ", eventType=" + mEventType
- + ", primaryPhy=" + mPrimaryPhy + ", secondaryPhy=" + mSecondaryPhy
- + ", advertisingSid=" + mAdvertisingSid + ", txPower=" + mTxPower
- + ", periodicAdvertisingInterval=" + mPeriodicAdvertisingInterval + '}';
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<ScanResult> CREATOR = new Creator<ScanResult>() {
- @Override
- public ScanResult createFromParcel(Parcel source) {
- return new ScanResult(source);
- }
-
- @Override
- public ScanResult[] newArray(int size) {
- return new ScanResult[size];
- }
- };
-
-}
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
deleted file mode 100644
index 1aa7cb5..0000000
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.SystemApi;
-import android.bluetooth.BluetoothDevice;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Bluetooth LE scan settings are passed to {@link BluetoothLeScanner#startScan} to define the
- * parameters for the scan.
- */
-public final class ScanSettings implements Parcelable {
-
- /**
- * A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for
- * other scan results without starting BLE scans themselves.
- */
- public static final int SCAN_MODE_OPPORTUNISTIC = -1;
-
- /**
- * Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the
- * least power. This mode is enforced if the scanning application is not in foreground.
- */
- public static final int SCAN_MODE_LOW_POWER = 0;
-
- /**
- * Perform Bluetooth LE scan in balanced power mode. Scan results are returned at a rate that
- * provides a good trade-off between scan frequency and power consumption.
- */
- public static final int SCAN_MODE_BALANCED = 1;
-
- /**
- * Scan using highest duty cycle. It's recommended to only use this mode when the application is
- * running in the foreground.
- */
- public static final int SCAN_MODE_LOW_LATENCY = 2;
-
- /**
- * Perform Bluetooth LE scan in ambient discovery mode. This mode has lower duty cycle and more
- * aggressive scan interval than balanced mode that provides a good trade-off between scan
- * latency and power consumption.
- *
- * @hide
- */
- @SystemApi
- public static final int SCAN_MODE_AMBIENT_DISCOVERY = 3;
-
- /**
- * Trigger a callback for every Bluetooth advertisement found that matches the filter criteria.
- * If no filter is active, all advertisement packets are reported.
- */
- public static final int CALLBACK_TYPE_ALL_MATCHES = 1;
-
- /**
- * A result callback is only triggered for the first advertisement packet received that matches
- * the filter criteria.
- */
- public static final int CALLBACK_TYPE_FIRST_MATCH = 2;
-
- /**
- * Receive a callback when advertisements are no longer received from a device that has been
- * previously reported by a first match callback.
- */
- public static final int CALLBACK_TYPE_MATCH_LOST = 4;
-
-
- /**
- * Determines how many advertisements to match per filter, as this is scarce hw resource
- */
- /**
- * Match one advertisement per filter
- */
- public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1;
-
- /**
- * Match few advertisement per filter, depends on current capability and availibility of
- * the resources in hw
- */
- public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2;
-
- /**
- * Match as many advertisement per filter as hw could allow, depends on current
- * capability and availibility of the resources in hw
- */
- public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3;
-
-
- /**
- * In Aggressive mode, hw will determine a match sooner even with feeble signal strength
- * and few number of sightings/match in a duration.
- */
- public static final int MATCH_MODE_AGGRESSIVE = 1;
-
- /**
- * For sticky mode, higher threshold of signal strength and sightings is required
- * before reporting by hw
- */
- public static final int MATCH_MODE_STICKY = 2;
-
- /**
- * Request full scan results which contain the device, rssi, advertising data, scan response
- * as well as the scan timestamp.
- *
- * @hide
- */
- @SystemApi
- public static final int SCAN_RESULT_TYPE_FULL = 0;
-
- /**
- * Request abbreviated scan results which contain the device, rssi and scan timestamp.
- * <p>
- * <b>Note:</b> It is possible for an application to get more scan results than it asked for, if
- * there are multiple apps using this type.
- *
- * @hide
- */
- @SystemApi
- public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1;
-
- /**
- * Use all supported PHYs for scanning.
- * This will check the controller capabilities, and start
- * the scan on 1Mbit and LE Coded PHYs if supported, or on
- * the 1Mbit PHY only.
- */
- public static final int PHY_LE_ALL_SUPPORTED = 255;
-
- // Bluetooth LE scan mode.
- private int mScanMode;
-
- // Bluetooth LE scan callback type
- private int mCallbackType;
-
- // Bluetooth LE scan result type
- private int mScanResultType;
-
- // Time of delay for reporting the scan result
- private long mReportDelayMillis;
-
- private int mMatchMode;
-
- private int mNumOfMatchesPerFilter;
-
- // Include only legacy advertising results
- private boolean mLegacy;
-
- private int mPhy;
-
- public int getScanMode() {
- return mScanMode;
- }
-
- public int getCallbackType() {
- return mCallbackType;
- }
-
- public int getScanResultType() {
- return mScanResultType;
- }
-
- /**
- * @hide
- */
- public int getMatchMode() {
- return mMatchMode;
- }
-
- /**
- * @hide
- */
- public int getNumOfMatches() {
- return mNumOfMatchesPerFilter;
- }
-
- /**
- * Returns whether only legacy advertisements will be returned.
- * Legacy advertisements include advertisements as specified
- * by the Bluetooth core specification 4.2 and below.
- */
- public boolean getLegacy() {
- return mLegacy;
- }
-
- /**
- * Returns the physical layer used during a scan.
- */
- public int getPhy() {
- return mPhy;
- }
-
- /**
- * Returns report delay timestamp based on the device clock.
- */
- public long getReportDelayMillis() {
- return mReportDelayMillis;
- }
-
- private ScanSettings(int scanMode, int callbackType, int scanResultType,
- long reportDelayMillis, int matchMode,
- int numOfMatchesPerFilter, boolean legacy, int phy) {
- mScanMode = scanMode;
- mCallbackType = callbackType;
- mScanResultType = scanResultType;
- mReportDelayMillis = reportDelayMillis;
- mNumOfMatchesPerFilter = numOfMatchesPerFilter;
- mMatchMode = matchMode;
- mLegacy = legacy;
- mPhy = phy;
- }
-
- private ScanSettings(Parcel in) {
- mScanMode = in.readInt();
- mCallbackType = in.readInt();
- mScanResultType = in.readInt();
- mReportDelayMillis = in.readLong();
- mMatchMode = in.readInt();
- mNumOfMatchesPerFilter = in.readInt();
- mLegacy = in.readInt() != 0;
- mPhy = in.readInt();
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mScanMode);
- dest.writeInt(mCallbackType);
- dest.writeInt(mScanResultType);
- dest.writeLong(mReportDelayMillis);
- dest.writeInt(mMatchMode);
- dest.writeInt(mNumOfMatchesPerFilter);
- dest.writeInt(mLegacy ? 1 : 0);
- dest.writeInt(mPhy);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<ScanSettings> CREATOR =
- new Creator<ScanSettings>() {
- @Override
- public ScanSettings[] newArray(int size) {
- return new ScanSettings[size];
- }
-
- @Override
- public ScanSettings createFromParcel(Parcel in) {
- return new ScanSettings(in);
- }
- };
-
- /**
- * Builder for {@link ScanSettings}.
- */
- public static final class Builder {
- private int mScanMode = SCAN_MODE_LOW_POWER;
- private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES;
- private int mScanResultType = SCAN_RESULT_TYPE_FULL;
- private long mReportDelayMillis = 0;
- private int mMatchMode = MATCH_MODE_AGGRESSIVE;
- private int mNumOfMatchesPerFilter = MATCH_NUM_MAX_ADVERTISEMENT;
- private boolean mLegacy = true;
- private int mPhy = PHY_LE_ALL_SUPPORTED;
-
- /**
- * Set scan mode for Bluetooth LE scan.
- *
- * @param scanMode The scan mode can be one of {@link ScanSettings#SCAN_MODE_LOW_POWER},
- * {@link ScanSettings#SCAN_MODE_BALANCED} or {@link ScanSettings#SCAN_MODE_LOW_LATENCY}.
- * @throws IllegalArgumentException If the {@code scanMode} is invalid.
- */
- public Builder setScanMode(int scanMode) {
- switch (scanMode) {
- case SCAN_MODE_OPPORTUNISTIC:
- case SCAN_MODE_LOW_POWER:
- case SCAN_MODE_BALANCED:
- case SCAN_MODE_LOW_LATENCY:
- case SCAN_MODE_AMBIENT_DISCOVERY:
- mScanMode = scanMode;
- break;
- default:
- throw new IllegalArgumentException("invalid scan mode " + scanMode);
- }
- return this;
- }
-
- /**
- * Set callback type for Bluetooth LE scan.
- *
- * @param callbackType The callback type flags for the scan.
- * @throws IllegalArgumentException If the {@code callbackType} is invalid.
- */
- public Builder setCallbackType(int callbackType) {
-
- if (!isValidCallbackType(callbackType)) {
- throw new IllegalArgumentException("invalid callback type - " + callbackType);
- }
- mCallbackType = callbackType;
- return this;
- }
-
- // Returns true if the callbackType is valid.
- private boolean isValidCallbackType(int callbackType) {
- if (callbackType == CALLBACK_TYPE_ALL_MATCHES
- || callbackType == CALLBACK_TYPE_FIRST_MATCH
- || callbackType == CALLBACK_TYPE_MATCH_LOST) {
- return true;
- }
- return callbackType == (CALLBACK_TYPE_FIRST_MATCH | CALLBACK_TYPE_MATCH_LOST);
- }
-
- /**
- * Set scan result type for Bluetooth LE scan.
- *
- * @param scanResultType Type for scan result, could be either {@link
- * ScanSettings#SCAN_RESULT_TYPE_FULL} or {@link ScanSettings#SCAN_RESULT_TYPE_ABBREVIATED}.
- * @throws IllegalArgumentException If the {@code scanResultType} is invalid.
- * @hide
- */
- @SystemApi
- public Builder setScanResultType(int scanResultType) {
- if (scanResultType < SCAN_RESULT_TYPE_FULL
- || scanResultType > SCAN_RESULT_TYPE_ABBREVIATED) {
- throw new IllegalArgumentException(
- "invalid scanResultType - " + scanResultType);
- }
- mScanResultType = scanResultType;
- return this;
- }
-
- /**
- * Set report delay timestamp for Bluetooth LE scan. If set to 0, you will be notified of
- * scan results immediately. If > 0, scan results are queued up and delivered after the
- * requested delay or 5000 milliseconds (whichever is higher). Note scan results may be
- * delivered sooner if the internal buffers fill up.
- *
- * @param reportDelayMillis how frequently scan results should be delivered in
- * milliseconds
- * @throws IllegalArgumentException if {@code reportDelayMillis} < 0
- */
- public Builder setReportDelay(long reportDelayMillis) {
- if (reportDelayMillis < 0) {
- throw new IllegalArgumentException("reportDelay must be > 0");
- }
- mReportDelayMillis = reportDelayMillis;
- return this;
- }
-
- /**
- * Set the number of matches for Bluetooth LE scan filters hardware match
- *
- * @param numOfMatches The num of matches can be one of
- * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT}
- * or {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or {@link
- * ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT}
- * @throws IllegalArgumentException If the {@code matchMode} is invalid.
- */
- public Builder setNumOfMatches(int numOfMatches) {
- if (numOfMatches < MATCH_NUM_ONE_ADVERTISEMENT
- || numOfMatches > MATCH_NUM_MAX_ADVERTISEMENT) {
- throw new IllegalArgumentException("invalid numOfMatches " + numOfMatches);
- }
- mNumOfMatchesPerFilter = numOfMatches;
- return this;
- }
-
- /**
- * Set match mode for Bluetooth LE scan filters hardware match
- *
- * @param matchMode The match mode can be one of {@link ScanSettings#MATCH_MODE_AGGRESSIVE}
- * or {@link ScanSettings#MATCH_MODE_STICKY}
- * @throws IllegalArgumentException If the {@code matchMode} is invalid.
- */
- public Builder setMatchMode(int matchMode) {
- if (matchMode < MATCH_MODE_AGGRESSIVE
- || matchMode > MATCH_MODE_STICKY) {
- throw new IllegalArgumentException("invalid matchMode " + matchMode);
- }
- mMatchMode = matchMode;
- return this;
- }
-
- /**
- * Set whether only legacy advertisments should be returned in scan results.
- * Legacy advertisements include advertisements as specified by the
- * Bluetooth core specification 4.2 and below. This is true by default
- * for compatibility with older apps.
- *
- * @param legacy true if only legacy advertisements will be returned
- */
- public Builder setLegacy(boolean legacy) {
- mLegacy = legacy;
- return this;
- }
-
- /**
- * Set the Physical Layer to use during this scan.
- * This is used only if {@link ScanSettings.Builder#setLegacy}
- * is set to false.
- * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}
- * may be used to check whether LE Coded phy is supported by calling
- * {@link android.bluetooth.BluetoothAdapter#isLeCodedPhySupported}.
- * Selecting an unsupported phy will result in failure to start scan.
- *
- * @param phy Can be one of {@link BluetoothDevice#PHY_LE_1M}, {@link
- * BluetoothDevice#PHY_LE_CODED} or {@link ScanSettings#PHY_LE_ALL_SUPPORTED}
- */
- public Builder setPhy(int phy) {
- mPhy = phy;
- return this;
- }
-
- /**
- * Build {@link ScanSettings}.
- */
- public ScanSettings build() {
- return new ScanSettings(mScanMode, mCallbackType, mScanResultType,
- mReportDelayMillis, mMatchMode,
- mNumOfMatchesPerFilter, mLegacy, mPhy);
- }
- }
-}
diff --git a/core/java/android/bluetooth/le/TransportBlock.java b/core/java/android/bluetooth/le/TransportBlock.java
deleted file mode 100644
index 18bad9c..0000000
--- a/core/java/android/bluetooth/le/TransportBlock.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-
-/**
- * Wrapper for Transport Discovery Data Transport Blocks.
- * This class represents a Transport Block from a Transport Discovery Data.
- *
- * @see TransportDiscoveryData
- * @see AdvertiseData
- */
-public final class TransportBlock implements Parcelable {
- private static final String TAG = "TransportBlock";
- private final int mOrgId;
- private final int mTdsFlags;
- private final int mTransportDataLength;
- private final byte[] mTransportData;
-
- /**
- * Creates an instance of TransportBlock from raw data.
- *
- * @param orgId the Organization ID
- * @param tdsFlags the TDS flags
- * @param transportDataLength the total length of the Transport Data
- * @param transportData the Transport Data
- */
- public TransportBlock(int orgId, int tdsFlags, int transportDataLength,
- @Nullable byte[] transportData) {
- mOrgId = orgId;
- mTdsFlags = tdsFlags;
- mTransportDataLength = transportDataLength;
- mTransportData = transportData;
- }
-
- private TransportBlock(Parcel in) {
- mOrgId = in.readInt();
- mTdsFlags = in.readInt();
- mTransportDataLength = in.readInt();
- if (mTransportDataLength > 0) {
- mTransportData = new byte[mTransportDataLength];
- in.readByteArray(mTransportData);
- } else {
- mTransportData = null;
- }
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mOrgId);
- dest.writeInt(mTdsFlags);
- dest.writeInt(mTransportDataLength);
- if (mTransportData != null) {
- dest.writeByteArray(mTransportData);
- }
- }
-
- /**
- * @hide
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * @hide
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- TransportBlock other = (TransportBlock) obj;
- return Arrays.equals(toByteArray(), other.toByteArray());
- }
-
- public static final @NonNull Creator<TransportBlock> CREATOR = new Creator<TransportBlock>() {
- @Override
- public TransportBlock createFromParcel(Parcel in) {
- return new TransportBlock(in);
- }
-
- @Override
- public TransportBlock[] newArray(int size) {
- return new TransportBlock[size];
- }
- };
-
- /**
- * Gets the Organization ID of the Transport Block which corresponds to one of the
- * the Bluetooth SIG Assigned Numbers.
- */
- public int getOrgId() {
- return mOrgId;
- }
-
- /**
- * Gets the TDS flags of the Transport Block which represents the role of the device and
- * information about its state and supported features.
- */
- public int getTdsFlags() {
- return mTdsFlags;
- }
-
- /**
- * Gets the total number of octets in the Transport Data field in this Transport Block.
- */
- public int getTransportDataLength() {
- return mTransportDataLength;
- }
-
- /**
- * Gets the Transport Data of the Transport Block which contains organization-specific data.
- */
- @Nullable
- public byte[] getTransportData() {
- return mTransportData;
- }
-
- /**
- * Converts this TransportBlock to byte array
- *
- * @return byte array representation of this Transport Block or null if the conversion failed
- */
- @Nullable
- public byte[] toByteArray() {
- try {
- ByteBuffer buffer = ByteBuffer.allocate(totalBytes());
- buffer.put((byte) mOrgId);
- buffer.put((byte) mTdsFlags);
- buffer.put((byte) mTransportDataLength);
- if (mTransportData != null) {
- buffer.put(mTransportData);
- }
- return buffer.array();
- } catch (BufferOverflowException e) {
- Log.e(TAG, "Error converting to byte array: " + e.toString());
- return null;
- }
- }
-
- /**
- * @return total byte count of this TransportBlock
- */
- public int totalBytes() {
- // 3 uint8 + byte[] length
- int size = 3 + mTransportDataLength;
- return size;
- }
-}
diff --git a/core/java/android/bluetooth/le/TransportDiscoveryData.java b/core/java/android/bluetooth/le/TransportDiscoveryData.java
deleted file mode 100644
index 2b52f19..0000000
--- a/core/java/android/bluetooth/le/TransportDiscoveryData.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.nio.BufferOverflowException;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Wrapper for Transport Discovery Data AD Type.
- * This class contains the Transport Discovery Data AD Type Code as well as
- * a list of potential Transport Blocks.
- *
- * @see AdvertiseData
- */
-public final class TransportDiscoveryData implements Parcelable {
- private static final String TAG = "TransportDiscoveryData";
- private final int mTransportDataType;
- private final List<TransportBlock> mTransportBlocks;
-
- /**
- * Creates a TransportDiscoveryData instance.
- *
- * @param transportDataType the Transport Discovery Data AD Type
- * @param transportBlocks the list of Transport Blocks
- */
- public TransportDiscoveryData(int transportDataType,
- @NonNull List<TransportBlock> transportBlocks) {
- mTransportDataType = transportDataType;
- mTransportBlocks = transportBlocks;
- }
-
- /**
- * Creates a TransportDiscoveryData instance from byte arrays.
- *
- * Uses the transport discovery data bytes and parses them into an usable class.
- *
- * @param transportDiscoveryData the raw discovery data
- */
- public TransportDiscoveryData(@NonNull byte[] transportDiscoveryData) {
- ByteBuffer byteBuffer = ByteBuffer.wrap(transportDiscoveryData);
- mTransportBlocks = new ArrayList();
- if (byteBuffer.remaining() > 0) {
- mTransportDataType = byteBuffer.get();
- } else {
- mTransportDataType = -1;
- }
- try {
- while (byteBuffer.remaining() > 0) {
- int orgId = byteBuffer.get();
- int tdsFlags = byteBuffer.get();
- int transportDataLength = byteBuffer.get();
- byte[] transportData = new byte[transportDataLength];
- byteBuffer.get(transportData, 0, transportDataLength);
- mTransportBlocks.add(new TransportBlock(orgId, tdsFlags,
- transportDataLength, transportData));
- }
- } catch (BufferUnderflowException e) {
- Log.e(TAG, "Error while parsing data: " + e.toString());
- }
- }
-
- private TransportDiscoveryData(Parcel in) {
- mTransportDataType = in.readInt();
- mTransportBlocks = in.createTypedArrayList(TransportBlock.CREATOR);
- }
-
- /**
- * @hide
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * @hide
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- TransportDiscoveryData other = (TransportDiscoveryData) obj;
- return Arrays.equals(toByteArray(), other.toByteArray());
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mTransportDataType);
- dest.writeTypedList(mTransportBlocks);
- }
-
- public static final @NonNull Creator<TransportDiscoveryData> CREATOR =
- new Creator<TransportDiscoveryData>() {
- @Override
- public TransportDiscoveryData createFromParcel(Parcel in) {
- return new TransportDiscoveryData(in);
- }
-
- @Override
- public TransportDiscoveryData[] newArray(int size) {
- return new TransportDiscoveryData[size];
- }
- };
-
- /**
- * Gets the transport data type.
- */
- public int getTransportDataType() {
- return mTransportDataType;
- }
-
- /**
- * @return the list of {@link TransportBlock} in this TransportDiscoveryData
- * or an empty list if there are no Transport Blocks
- */
- @NonNull
- public List<TransportBlock> getTransportBlocks() {
- if (mTransportBlocks == null) {
- return Collections.emptyList();
- }
- return mTransportBlocks;
- }
-
- /**
- * Converts this TransportDiscoveryData to byte array
- *
- * @return byte array representation of this Transport Discovery Data or null if the
- * conversion failed
- */
- @Nullable
- public byte[] toByteArray() {
- try {
- ByteBuffer buffer = ByteBuffer.allocate(totalBytes());
- buffer.put((byte) mTransportDataType);
- for (TransportBlock transportBlock : getTransportBlocks()) {
- buffer.put(transportBlock.toByteArray());
- }
- return buffer.array();
- } catch (BufferOverflowException e) {
- Log.e(TAG, "Error converting to byte array: " + e.toString());
- return null;
- }
- }
-
- /**
- * @return total byte count of this TransportDataDiscovery
- */
- public int totalBytes() {
- int size = 1; // Counting Transport Data Type here.
- for (TransportBlock transportBlock : getTransportBlocks()) {
- size += transportBlock.totalBytes();
- }
- return size;
- }
-}
diff --git a/core/java/android/bluetooth/le/TruncatedFilter.java b/core/java/android/bluetooth/le/TruncatedFilter.java
deleted file mode 100644
index 2592588..0000000
--- a/core/java/android/bluetooth/le/TruncatedFilter.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-
-import java.util.List;
-
-/**
- * A special scan filter that lets the client decide how the scan record should be stored.
- *
- * @deprecated this is not used anywhere
- *
- * @hide
- */
-@Deprecated
-@SystemApi
-@SuppressLint("AndroidFrameworkBluetoothPermission")
-public final class TruncatedFilter {
- private final ScanFilter mFilter;
- private final List<ResultStorageDescriptor> mStorageDescriptors;
-
- /**
- * Constructor for {@link TruncatedFilter}.
- *
- * @param filter Scan filter of the truncated filter.
- * @param storageDescriptors Describes how the scan should be stored.
- */
- public TruncatedFilter(ScanFilter filter, List<ResultStorageDescriptor> storageDescriptors) {
- mFilter = filter;
- mStorageDescriptors = storageDescriptors;
- }
-
- /**
- * Returns the scan filter.
- */
- public ScanFilter getFilter() {
- return mFilter;
- }
-
- /**
- * Returns a list of descriptor for scan result storage.
- */
- public List<ResultStorageDescriptor> getStorageDescriptors() {
- return mStorageDescriptors;
- }
-
-
-}
diff --git a/core/java/android/bluetooth/package.html b/core/java/android/bluetooth/package.html
deleted file mode 100644
index d9ca4f1..0000000
--- a/core/java/android/bluetooth/package.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<HTML>
-<BODY>
-<p>Provides classes that manage Bluetooth functionality, such as scanning for
-devices, connecting with devices, and managing data transfer between devices.
-The Bluetooth API supports both "Classic Bluetooth" and Bluetooth Low Energy.</p>
-
-<p>For more information about Classic Bluetooth, see the
-<a href="{@docRoot}guide/topics/connectivity/bluetooth.html">Bluetooth</a> guide.
-For more information about Bluetooth Low Energy, see the
-<a href="{@docRoot}guide/topics/connectivity/bluetooth-le.html">
-Bluetooth Low Energy</a> (BLE) guide.</p>
-{@more}
-
-<p>The Bluetooth APIs let applications:</p>
-<ul>
- <li>Scan for other Bluetooth devices (including BLE devices).</li>
- <li>Query the local Bluetooth adapter for paired Bluetooth devices.</li>
- <li>Establish RFCOMM channels/sockets.</li>
- <li>Connect to specified sockets on other devices.</li>
- <li>Transfer data to and from other devices.</li>
- <li>Communicate with BLE devices, such as proximity sensors, heart rate
- monitors, fitness devices, and so on.</li>
- <li>Act as a GATT client or a GATT server (BLE).</li>
-</ul>
-
-<p>
-To perform Bluetooth communication using these APIs, an application must
-declare the {@link android.Manifest.permission#BLUETOOTH} permission. Some
-additional functionality, such as requesting device discovery,
-also requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
-permission.
-</p>
-
-<p class="note"><strong>Note:</strong>
-Not all Android-powered devices provide Bluetooth functionality.</p>
-
-</BODY>
-</HTML>
diff --git a/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java b/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java
index c89d3b2..fe821e0 100644
--- a/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java
+++ b/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java
@@ -35,6 +35,4 @@
@Nullable
String getMaxSdkVersion();
- int getInitOrder();
-
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java b/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java
index 65d26b9..54196fd 100644
--- a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java
+++ b/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java
@@ -45,11 +45,10 @@
@Nullable
private String maxSdkVersion;
- private int initOrder;
-
public ParsedApexSystemServiceImpl() {
}
+
// Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
@@ -68,15 +67,13 @@
@NonNull String name,
@Nullable String jarPath,
@Nullable String minSdkVersion,
- @Nullable String maxSdkVersion,
- int initOrder) {
+ @Nullable String maxSdkVersion) {
this.name = name;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, name);
this.jarPath = jarPath;
this.minSdkVersion = minSdkVersion;
this.maxSdkVersion = maxSdkVersion;
- this.initOrder = initOrder;
// onConstructed(); // You can define this method to get a callback
}
@@ -102,11 +99,6 @@
}
@DataClass.Generated.Member
- public int getInitOrder() {
- return initOrder;
- }
-
- @DataClass.Generated.Member
public @NonNull ParsedApexSystemServiceImpl setName(@NonNull String value) {
name = value;
com.android.internal.util.AnnotationValidations.validate(
@@ -133,12 +125,6 @@
}
@DataClass.Generated.Member
- public @NonNull ParsedApexSystemServiceImpl setInitOrder( int value) {
- initOrder = value;
- return this;
- }
-
- @DataClass.Generated.Member
static Parcelling<String> sParcellingForName =
Parcelling.Cache.get(
Parcelling.BuiltIn.ForInternedString.class);
@@ -197,7 +183,6 @@
sParcellingForJarPath.parcel(jarPath, dest, flags);
sParcellingForMinSdkVersion.parcel(minSdkVersion, dest, flags);
sParcellingForMaxSdkVersion.parcel(maxSdkVersion, dest, flags);
- dest.writeInt(initOrder);
}
@Override
@@ -216,7 +201,6 @@
String _jarPath = sParcellingForJarPath.unparcel(in);
String _minSdkVersion = sParcellingForMinSdkVersion.unparcel(in);
String _maxSdkVersion = sParcellingForMaxSdkVersion.unparcel(in);
- int _initOrder = in.readInt();
this.name = _name;
com.android.internal.util.AnnotationValidations.validate(
@@ -224,7 +208,6 @@
this.jarPath = _jarPath;
this.minSdkVersion = _minSdkVersion;
this.maxSdkVersion = _maxSdkVersion;
- this.initOrder = _initOrder;
// onConstructed(); // You can define this method to get a callback
}
@@ -244,10 +227,10 @@
};
@DataClass.Generated(
- time = 1641307133386L,
+ time = 1638903241144L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java",
- inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nprivate int initOrder\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedApexSystemService]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)")
+ inputSignatures = "private @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.NonNull java.lang.String name\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String jarPath\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String minSdkVersion\nprivate @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) @android.annotation.Nullable java.lang.String maxSdkVersion\nclass ParsedApexSystemServiceImpl extends java.lang.Object implements [android.content.pm.parsing.component.ParsedApexSystemService]\n@com.android.internal.util.DataClass(genGetters=true, genAidl=false, genSetters=true, genParcelable=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java b/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java
index eca8976..26abf48 100644
--- a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java
+++ b/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java
@@ -53,13 +53,10 @@
R.styleable.AndroidManifestApexSystemService_minSdkVersion);
String maxSdkVersion = sa.getString(
R.styleable.AndroidManifestApexSystemService_maxSdkVersion);
- int initOrder = sa.getInt(R.styleable.AndroidManifestApexSystemService_initOrder, 0);
systemService.setName(className)
.setMinSdkVersion(minSdkVersion)
- .setMaxSdkVersion(maxSdkVersion)
- .setInitOrder(initOrder);
-
+ .setMaxSdkVersion(maxSdkVersion);
if (!TextUtils.isEmpty(jarPath)) {
systemService.setJarPath(jarPath);
}
diff --git a/core/java/android/net/PrivateDnsConnectivityChecker.java b/core/java/android/net/PrivateDnsConnectivityChecker.java
index cfd458c..ac97b36 100644
--- a/core/java/android/net/PrivateDnsConnectivityChecker.java
+++ b/core/java/android/net/PrivateDnsConnectivityChecker.java
@@ -44,7 +44,7 @@
*/
public static boolean canConnectToPrivateDnsServer(@NonNull String hostname) {
final SocketFactory factory = SSLSocketFactory.getDefault();
- TrafficStats.setThreadStatsTag(TrafficStats.TAG_SYSTEM_APP);
+ TrafficStats.setThreadStatsTagApp();
try (SSLSocket socket = (SSLSocket) factory.createSocket()) {
socket.setSoTimeout(CONNECTION_TIMEOUT_MS);
diff --git a/core/java/android/os/BatteryConsumer.java b/core/java/android/os/BatteryConsumer.java
index c607195..d2f788f 100644
--- a/core/java/android/os/BatteryConsumer.java
+++ b/core/java/android/os/BatteryConsumer.java
@@ -191,6 +191,7 @@
private static final int[] SUPPORTED_POWER_COMPONENTS_PER_PROCESS_STATE = {
POWER_COMPONENT_CPU,
POWER_COMPONENT_MOBILE_RADIO,
+ POWER_COMPONENT_WIFI,
};
static final int COLUMN_INDEX_BATTERY_CONSUMER_TYPE = 0;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 520730f..a453887 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -461,6 +461,12 @@
public abstract long getCountLocked(int which);
/**
+ * Returns the count accumulated by this Counter for the specified process state.
+ * If the counter does not support per-procstate tracking, returns 0.
+ */
+ public abstract long getCountForProcessState(@BatteryConsumer.ProcessState int procState);
+
+ /**
* Temporary for debugging.
*/
public abstract void logState(Printer pw, String prefix);
@@ -1096,6 +1102,17 @@
public abstract long getWifiMeasuredBatteryConsumptionUC();
/**
+ * Returns the battery consumption (in microcoulombs) of the uid's wifi usage when in the
+ * specified process state.
+ * Will return {@link #POWER_DATA_UNAVAILABLE} if data is unavailable.
+ *
+ * {@hide}
+ */
+ public abstract long getWifiMeasuredBatteryConsumptionUC(
+ @BatteryConsumer.ProcessState int processState);
+
+
+ /**
* Returns the battery consumption (in microcoulombs) used by this uid for each
* {@link android.hardware.power.stats.EnergyConsumer.ordinal} of (custom) energy consumer
* type {@link android.hardware.power.stats.EnergyConsumerType#OTHER}).
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index ae323226..9889eaa 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -1249,4 +1249,119 @@
return String.valueOf(mInner);
}
}
+
+ /**
+ * A Builder class to construct a DisplayCutout instance.
+ *
+ * <p>Note that this is only for tests purpose. For production code, developers should always
+ * use a {@link DisplayCutout} obtained from the system.</p>
+ */
+ public static final class Builder {
+ private Insets mSafeInsets = Insets.NONE;
+ private Insets mWaterfallInsets = Insets.NONE;
+ private Path mCutoutPath;
+ private final Rect mBoundingRectLeft = new Rect();
+ private final Rect mBoundingRectTop = new Rect();
+ private final Rect mBoundingRectRight = new Rect();
+ private final Rect mBoundingRectBottom = new Rect();
+
+ /**
+ * Begin building a DisplayCutout.
+ */
+ public Builder() {
+ }
+
+ /**
+ * Construct a new {@link DisplayCutout} with the set parameters.
+ */
+ @NonNull
+ public DisplayCutout build() {
+ final CutoutPathParserInfo info;
+ if (mCutoutPath != null) {
+ // Create a fake CutoutPathParserInfo and set it to sCachedCutoutPathParserInfo so
+ // that when getCutoutPath() is called, it will return the cached Path.
+ info = new CutoutPathParserInfo(0, 0, 0, "test", 0, 1f);
+ synchronized (CACHE_LOCK) {
+ DisplayCutout.sCachedCutoutPathParserInfo = info;
+ DisplayCutout.sCachedCutoutPath = mCutoutPath;
+ }
+ } else {
+ info = null;
+ }
+ return new DisplayCutout(mSafeInsets.toRect(), mWaterfallInsets, mBoundingRectLeft,
+ mBoundingRectTop, mBoundingRectRight, mBoundingRectBottom, info, false);
+ }
+
+ /**
+ * Set the safe insets. If not set, the default value is {@link Insets#NONE}.
+ */
+ @SuppressWarnings("MissingGetterMatchingBuilder")
+ @NonNull
+ public Builder setSafeInsets(@NonNull Insets safeInsets) {
+ mSafeInsets = safeInsets;
+ return this;
+ }
+
+ /**
+ * Set the waterfall insets of the DisplayCutout. If not set, the default value is
+ * {@link Insets#NONE}
+ */
+ @NonNull
+ public Builder setWaterfallInsets(@NonNull Insets waterfallInsets) {
+ mWaterfallInsets = waterfallInsets;
+ return this;
+ }
+
+ /**
+ * Set a bounding rectangle for a non-functional area on the display which is located on
+ * the left of the screen. If not set, the default value is an empty rectangle.
+ */
+ @NonNull
+ public Builder setBoundingRectLeft(@NonNull Rect boundingRectLeft) {
+ mBoundingRectLeft.set(boundingRectLeft);
+ return this;
+ }
+
+ /**
+ * Set a bounding rectangle for a non-functional area on the display which is located on
+ * the top of the screen. If not set, the default value is an empty rectangle.
+ */
+ @NonNull
+ public Builder setBoundingRectTop(@NonNull Rect boundingRectTop) {
+ mBoundingRectTop.set(boundingRectTop);
+ return this;
+ }
+
+ /**
+ * Set a bounding rectangle for a non-functional area on the display which is located on
+ * the right of the screen. If not set, the default value is an empty rectangle.
+ */
+ @NonNull
+ public Builder setBoundingRectRight(@NonNull Rect boundingRectRight) {
+ mBoundingRectRight.set(boundingRectRight);
+ return this;
+ }
+
+ /**
+ * Set a bounding rectangle for a non-functional area on the display which is located on
+ * the bottom of the screen. If not set, the default value is an empty rectangle.
+ */
+ @NonNull
+ public Builder setBoundingRectBottom(@NonNull Rect boundingRectBottom) {
+ mBoundingRectBottom.set(boundingRectBottom);
+ return this;
+ }
+
+ /**
+ * Set the cutout {@link Path}.
+ *
+ * Note that not support creating/testing multiple display cutouts with setCutoutPath() in
+ * parallel.
+ */
+ @NonNull
+ public Builder setCutoutPath(@NonNull Path cutoutPath) {
+ mCutoutPath = cutoutPath;
+ return this;
+ }
+ }
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9429c79..a4183ca8 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -164,7 +164,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 205;
+ static final int VERSION = 206;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -214,6 +214,26 @@
private static final double MILLISECONDS_IN_HOUR = 3600 * 1000;
private static final long MILLISECONDS_IN_YEAR = 365 * 24 * 3600 * 1000L;
+ private static final LongCounter ZERO_LONG_COUNTER = new LongCounter() {
+ @Override
+ public long getCountLocked(int which) {
+ return 0;
+ }
+
+ @Override
+ public long getCountForProcessState(int procState) {
+ return 0;
+ }
+
+ @Override
+ public void logState(Printer pw, String prefix) {
+ pw.println(prefix + "mCount=0");
+ }
+ };
+
+ private static final LongCounter[] ZERO_LONG_COUNTER_ARRAY =
+ new LongCounter[]{ZERO_LONG_COUNTER};
+
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
@@ -244,6 +264,7 @@
private static final int[] SUPPORTED_PER_PROCESS_STATE_STANDARD_ENERGY_BUCKETS = {
MeasuredEnergyStats.POWER_BUCKET_CPU,
MeasuredEnergyStats.POWER_BUCKET_MOBILE_RADIO,
+ MeasuredEnergyStats.POWER_BUCKET_WIFI,
};
// TimeInState counters need NUM_PROCESS_STATE states in order to accommodate
@@ -1742,7 +1763,7 @@
}
}
- private static class TimeMultiStateCounter implements TimeBaseObs {
+ private static class TimeMultiStateCounter extends LongCounter implements TimeBaseObs {
private final TimeBase mTimeBase;
private final LongMultiStateCounter mCounter;
@@ -1794,7 +1815,7 @@
/**
* Returns accumulated count for the specified state.
*/
- public long getCountLocked(int procState) {
+ public long getCountForProcessState(@BatteryConsumer.ProcessState int procState) {
return mCounter.getCount(procState);
}
@@ -1802,6 +1823,12 @@
return mCounter.getTotalCount();
}
+ @Override
+ public long getCountLocked(int statsType) {
+ return getTotalCountLocked();
+ }
+
+ @Override
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCounter=" + mCounter);
}
@@ -1947,6 +1974,14 @@
}
@Override
+ public long getCountForProcessState(int procState) {
+ if (procState == BatteryConsumer.PROCESS_STATE_ANY) {
+ return getCountLocked(STATS_SINCE_CHARGED);
+ }
+ return 0;
+ }
+
+ @Override
public void logState(Printer pw, String prefix) {
pw.println(prefix + "mCount=" + mCount);
}
@@ -3226,57 +3261,50 @@
public static class ControllerActivityCounterImpl extends ControllerActivityCounter
implements Parcelable {
- private final LongSamplingCounter mIdleTimeMillis;
+ private final Clock mClock;
+ private final TimeBase mTimeBase;
+ private int mNumTxStates;
+ private int mProcessState;
+ private TimeMultiStateCounter mIdleTimeMillis;
private final LongSamplingCounter mScanTimeMillis;
private final LongSamplingCounter mSleepTimeMillis;
- private final LongSamplingCounter mRxTimeMillis;
- private final LongSamplingCounter[] mTxTimeMillis;
+ private TimeMultiStateCounter mRxTimeMillis;
+ private TimeMultiStateCounter[] mTxTimeMillis;
private final LongSamplingCounter mPowerDrainMaMs;
private final LongSamplingCounter mMonitoredRailChargeConsumedMaMs;
- public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates) {
- mIdleTimeMillis = new LongSamplingCounter(timeBase);
+ public ControllerActivityCounterImpl(Clock clock, TimeBase timeBase, int numTxStates) {
+ mClock = clock;
+ mTimeBase = timeBase;
+ mNumTxStates = numTxStates;
mScanTimeMillis = new LongSamplingCounter(timeBase);
mSleepTimeMillis = new LongSamplingCounter(timeBase);
- mRxTimeMillis = new LongSamplingCounter(timeBase);
- mTxTimeMillis = new LongSamplingCounter[numTxStates];
- for (int i = 0; i < numTxStates; i++) {
- mTxTimeMillis[i] = new LongSamplingCounter(timeBase);
- }
mPowerDrainMaMs = new LongSamplingCounter(timeBase);
mMonitoredRailChargeConsumedMaMs = new LongSamplingCounter(timeBase);
}
- public ControllerActivityCounterImpl(TimeBase timeBase, int numTxStates, Parcel in) {
- mIdleTimeMillis = new LongSamplingCounter(timeBase, in);
+ public ControllerActivityCounterImpl(Clock clock, TimeBase timeBase, int numTxStates,
+ Parcel in) {
+ mClock = clock;
+ mTimeBase = timeBase;
+ mNumTxStates = numTxStates;
+ mIdleTimeMillis = readTimeMultiStateCounter(in, timeBase);
mScanTimeMillis = new LongSamplingCounter(timeBase, in);
mSleepTimeMillis = new LongSamplingCounter(timeBase, in);
- mRxTimeMillis = new LongSamplingCounter(timeBase, in);
- final int recordedTxStates = in.readInt();
- if (recordedTxStates != numTxStates) {
- throw new ParcelFormatException("inconsistent tx state lengths");
- }
+ mRxTimeMillis = readTimeMultiStateCounter(in, timeBase);
+ mTxTimeMillis = readTimeMultiStateCounters(in, timeBase, numTxStates);
- mTxTimeMillis = new LongSamplingCounter[numTxStates];
- for (int i = 0; i < numTxStates; i++) {
- mTxTimeMillis[i] = new LongSamplingCounter(timeBase, in);
- }
mPowerDrainMaMs = new LongSamplingCounter(timeBase, in);
mMonitoredRailChargeConsumedMaMs = new LongSamplingCounter(timeBase, in);
}
public void readSummaryFromParcel(Parcel in) {
- mIdleTimeMillis.readSummaryFromParcelLocked(in);
+ mIdleTimeMillis = readTimeMultiStateCounter(in, mTimeBase);
mScanTimeMillis.readSummaryFromParcelLocked(in);
mSleepTimeMillis.readSummaryFromParcelLocked(in);
- mRxTimeMillis.readSummaryFromParcelLocked(in);
- final int recordedTxStates = in.readInt();
- if (recordedTxStates != mTxTimeMillis.length) {
- throw new ParcelFormatException("inconsistent tx state lengths");
- }
- for (LongSamplingCounter counter : mTxTimeMillis) {
- counter.readSummaryFromParcelLocked(in);
- }
+ mRxTimeMillis = readTimeMultiStateCounter(in, mTimeBase);
+ mTxTimeMillis = readTimeMultiStateCounters(in, mTimeBase, mNumTxStates);
+
mPowerDrainMaMs.readSummaryFromParcelLocked(in);
mMonitoredRailChargeConsumedMaMs.readSummaryFromParcelLocked(in);
}
@@ -3287,52 +3315,98 @@
}
public void writeSummaryToParcel(Parcel dest) {
- mIdleTimeMillis.writeSummaryFromParcelLocked(dest);
+ writeTimeMultiStateCounter(dest, mIdleTimeMillis);
mScanTimeMillis.writeSummaryFromParcelLocked(dest);
mSleepTimeMillis.writeSummaryFromParcelLocked(dest);
- mRxTimeMillis.writeSummaryFromParcelLocked(dest);
- dest.writeInt(mTxTimeMillis.length);
- for (LongSamplingCounter counter : mTxTimeMillis) {
- counter.writeSummaryFromParcelLocked(dest);
- }
+ writeTimeMultiStateCounter(dest, mRxTimeMillis);
+ writeTimeMultiStateCounters(dest, mTxTimeMillis);
mPowerDrainMaMs.writeSummaryFromParcelLocked(dest);
mMonitoredRailChargeConsumedMaMs.writeSummaryFromParcelLocked(dest);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
- mIdleTimeMillis.writeToParcel(dest);
+ writeTimeMultiStateCounter(dest, mIdleTimeMillis);
mScanTimeMillis.writeToParcel(dest);
mSleepTimeMillis.writeToParcel(dest);
- mRxTimeMillis.writeToParcel(dest);
- dest.writeInt(mTxTimeMillis.length);
- for (LongSamplingCounter counter : mTxTimeMillis) {
- counter.writeToParcel(dest);
- }
+ writeTimeMultiStateCounter(dest, mRxTimeMillis);
+ writeTimeMultiStateCounters(dest, mTxTimeMillis);
mPowerDrainMaMs.writeToParcel(dest);
mMonitoredRailChargeConsumedMaMs.writeToParcel(dest);
}
+ private TimeMultiStateCounter readTimeMultiStateCounter(Parcel in, TimeBase timeBase) {
+ if (in.readBoolean()) {
+ final TimeMultiStateCounter counter =
+ new TimeMultiStateCounter(timeBase, in, mClock.elapsedRealtime());
+ if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
+ return counter;
+ }
+ }
+ return null;
+ }
+
+ private void writeTimeMultiStateCounter(Parcel dest, TimeMultiStateCounter counter) {
+ if (counter != null) {
+ dest.writeBoolean(true);
+ counter.writeToParcel(dest);
+ } else {
+ dest.writeBoolean(false);
+ }
+ }
+
+ private TimeMultiStateCounter[] readTimeMultiStateCounters(Parcel in, TimeBase timeBase,
+ int expectedNumCounters) {
+ if (in.readBoolean()) {
+ final int numCounters = in.readInt();
+ boolean valid = (numCounters == expectedNumCounters);
+ // Need to read counters out of the Parcel, even if all or some of them are
+ // invalid.
+ TimeMultiStateCounter[] counters = new TimeMultiStateCounter[numCounters];
+ for (int i = 0; i < numCounters; i++) {
+ final TimeMultiStateCounter counter =
+ new TimeMultiStateCounter(timeBase, in, mClock.elapsedRealtime());
+ if (counter.getStateCount() == BatteryConsumer.PROCESS_STATE_COUNT) {
+ counters[i] = counter;
+ } else {
+ valid = false;
+ }
+ }
+ if (valid) {
+ return counters;
+ }
+ }
+ return null;
+ }
+
+ private void writeTimeMultiStateCounters(Parcel dest, TimeMultiStateCounter[] counters) {
+ if (counters != null) {
+ dest.writeBoolean(true);
+ dest.writeInt(counters.length);
+ for (TimeMultiStateCounter counter : counters) {
+ counter.writeToParcel(dest);
+ }
+ } else {
+ dest.writeBoolean(false);
+ }
+ }
+
public void reset(boolean detachIfReset, long elapsedRealtimeUs) {
- mIdleTimeMillis.reset(detachIfReset, elapsedRealtimeUs);
+ resetIfNotNull(mIdleTimeMillis, detachIfReset, elapsedRealtimeUs);
mScanTimeMillis.reset(detachIfReset, elapsedRealtimeUs);
mSleepTimeMillis.reset(detachIfReset, elapsedRealtimeUs);
- mRxTimeMillis.reset(detachIfReset, elapsedRealtimeUs);
- for (LongSamplingCounter counter : mTxTimeMillis) {
- counter.reset(detachIfReset, elapsedRealtimeUs);
- }
+ resetIfNotNull(mRxTimeMillis, detachIfReset, elapsedRealtimeUs);
+ resetIfNotNull(mTxTimeMillis, detachIfReset, elapsedRealtimeUs);
mPowerDrainMaMs.reset(detachIfReset, elapsedRealtimeUs);
mMonitoredRailChargeConsumedMaMs.reset(detachIfReset, elapsedRealtimeUs);
}
public void detach() {
- mIdleTimeMillis.detach();
+ detachIfNotNull(mIdleTimeMillis);
mScanTimeMillis.detach();
mSleepTimeMillis.detach();
- mRxTimeMillis.detach();
- for (LongSamplingCounter counter : mTxTimeMillis) {
- counter.detach();
- }
+ detachIfNotNull(mRxTimeMillis);
+ detachIfNotNull(mTxTimeMillis);
mPowerDrainMaMs.detach();
mMonitoredRailChargeConsumedMaMs.detach();
}
@@ -3342,7 +3416,17 @@
* milliseconds.
*/
@Override
- public LongSamplingCounter getIdleTimeCounter() {
+ public LongCounter getIdleTimeCounter() {
+ if (mIdleTimeMillis == null) {
+ return ZERO_LONG_COUNTER;
+ }
+ return mIdleTimeMillis;
+ }
+
+ private TimeMultiStateCounter getOrCreateIdleTimeCounter() {
+ if (mIdleTimeMillis == null) {
+ mIdleTimeMillis = createTimeMultiStateCounter();
+ }
return mIdleTimeMillis;
}
@@ -3369,7 +3453,17 @@
* milliseconds.
*/
@Override
- public LongSamplingCounter getRxTimeCounter() {
+ public LongCounter getRxTimeCounter() {
+ if (mRxTimeMillis == null) {
+ return ZERO_LONG_COUNTER;
+ }
+ return mRxTimeMillis;
+ }
+
+ private TimeMultiStateCounter getOrCreateRxTimeCounter() {
+ if (mRxTimeMillis == null) {
+ mRxTimeMillis = createTimeMultiStateCounter();
+ }
return mRxTimeMillis;
}
@@ -3378,10 +3472,33 @@
* milliseconds.
*/
@Override
- public LongSamplingCounter[] getTxTimeCounters() {
+ public LongCounter[] getTxTimeCounters() {
+ if (mTxTimeMillis == null) {
+ return ZERO_LONG_COUNTER_ARRAY;
+ }
return mTxTimeMillis;
}
+ private TimeMultiStateCounter[] getOrCreateTxTimeCounters() {
+ if (mTxTimeMillis == null) {
+ mTxTimeMillis = new TimeMultiStateCounter[mNumTxStates];
+ for (int i = 0; i < mNumTxStates; i++) {
+ mTxTimeMillis[i] = createTimeMultiStateCounter();
+ }
+ }
+ return mTxTimeMillis;
+ }
+
+ private TimeMultiStateCounter createTimeMultiStateCounter() {
+ final long timestampMs = mClock.elapsedRealtime();
+ TimeMultiStateCounter counter = new TimeMultiStateCounter(mTimeBase,
+ BatteryConsumer.PROCESS_STATE_COUNT, timestampMs);
+ counter.setState(mapUidProcessStateToBatteryConsumerProcessState(mProcessState),
+ timestampMs);
+ counter.update(0, timestampMs);
+ return counter;
+ }
+
/**
* @return a LongSamplingCounter, measuring power use in milli-ampere milliseconds (mAmS).
*/
@@ -3398,6 +3515,21 @@
public LongSamplingCounter getMonitoredRailChargeConsumedMaMs() {
return mMonitoredRailChargeConsumedMaMs;
}
+
+ private void setState(int processState, long elapsedTimeMs) {
+ mProcessState = processState;
+ if (mIdleTimeMillis != null) {
+ mIdleTimeMillis.setState(processState, elapsedTimeMs);
+ }
+ if (mRxTimeMillis != null) {
+ mRxTimeMillis.setState(processState, elapsedTimeMs);
+ }
+ if (mTxTimeMillis != null) {
+ for (int i = 0; i < mTxTimeMillis.length; i++) {
+ mTxTimeMillis[i].setState(processState, elapsedTimeMs);
+ }
+ }
+ }
}
/** Get Resource Power Manager stats. Create a new one if it doesn't already exist. */
@@ -8234,6 +8366,11 @@
mapUidProcessStateToBatteryConsumerProcessState(procState);
getCpuActiveTimeCounter().setState(batteryConsumerProcessState, elapsedTimeMs);
getMobileRadioActiveTimeCounter().setState(batteryConsumerProcessState, elapsedTimeMs);
+ final ControllerActivityCounterImpl wifiControllerActivity =
+ getWifiControllerActivity();
+ if (wifiControllerActivity != null) {
+ wifiControllerActivity.setState(batteryConsumerProcessState, elapsedTimeMs);
+ }
final MeasuredEnergyStats energyStats =
getOrCreateMeasuredEnergyStatsIfSupportedLocked();
if (energyStats != null) {
@@ -8271,7 +8408,7 @@
long activeTime = 0;
for (int procState = 0; procState < BatteryConsumer.PROCESS_STATE_COUNT; procState++) {
- activeTime += mCpuActiveTimeMs.getCountLocked(procState);
+ activeTime += mCpuActiveTimeMs.getCountForProcessState(procState);
}
return activeTime;
}
@@ -8283,7 +8420,7 @@
return 0;
}
- return mCpuActiveTimeMs.getCountLocked(procState);
+ return mCpuActiveTimeMs.getCountForProcessState(procState);
}
@Override
@@ -8576,7 +8713,7 @@
}
@Override
- public ControllerActivityCounter getWifiControllerActivity() {
+ public ControllerActivityCounterImpl getWifiControllerActivity() {
return mWifiControllerActivity;
}
@@ -8592,24 +8729,24 @@
public ControllerActivityCounterImpl getOrCreateWifiControllerActivityLocked() {
if (mWifiControllerActivity == null) {
- mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- NUM_BT_TX_LEVELS);
+ mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mClock,
+ mBsi.mOnBatteryTimeBase, NUM_WIFI_TX_LEVELS);
}
return mWifiControllerActivity;
}
public ControllerActivityCounterImpl getOrCreateBluetoothControllerActivityLocked() {
if (mBluetoothControllerActivity == null) {
- mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- NUM_BT_TX_LEVELS);
+ mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mClock,
+ mBsi.mOnBatteryTimeBase, NUM_BT_TX_LEVELS);
}
return mBluetoothControllerActivity;
}
public ControllerActivityCounterImpl getOrCreateModemControllerActivityLocked() {
if (mModemControllerActivity == null) {
- mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.getNumTxPowerLevels());
+ mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mClock,
+ mBsi.mOnBatteryTimeBase, ModemActivityInfo.getNumTxPowerLevels());
}
return mModemControllerActivity;
}
@@ -8745,6 +8882,13 @@
return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_WIFI);
}
+ @GuardedBy("mBsi")
+ @Override
+ public long getWifiMeasuredBatteryConsumptionUC(int processState) {
+ return getMeasuredBatteryConsumptionUC(MeasuredEnergyStats.POWER_BUCKET_WIFI,
+ processState);
+ }
+
/**
* Gets the minimum of the uid's foreground activity time and its PROCESS_STATE_TOP time
* since last marked. Also sets the mark time for both these timers.
@@ -9341,7 +9485,7 @@
if (processState == BatteryConsumer.PROCESS_STATE_ANY) {
return mMobileRadioActiveTime.getTotalCountLocked();
} else {
- return mMobileRadioActiveTime.getCountLocked(processState);
+ return mMobileRadioActiveTime.getCountForProcessState(processState);
}
}
@@ -10291,22 +10435,22 @@
}
if (in.readInt() != 0) {
- mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- NUM_WIFI_TX_LEVELS, in);
+ mWifiControllerActivity = new ControllerActivityCounterImpl(mBsi.mClock,
+ mBsi.mOnBatteryTimeBase, NUM_WIFI_TX_LEVELS, in);
} else {
mWifiControllerActivity = null;
}
if (in.readInt() != 0) {
- mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- NUM_BT_TX_LEVELS, in);
+ mBluetoothControllerActivity = new ControllerActivityCounterImpl(mBsi.mClock,
+ mBsi.mOnBatteryTimeBase, NUM_BT_TX_LEVELS, in);
} else {
mBluetoothControllerActivity = null;
}
if (in.readInt() != 0) {
- mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mOnBatteryTimeBase,
- ModemActivityInfo.getNumTxPowerLevels(), in);
+ mModemControllerActivity = new ControllerActivityCounterImpl(mBsi.mClock,
+ mBsi.mOnBatteryTimeBase, ModemActivityInfo.getNumTxPowerLevels(), in);
} else {
mModemControllerActivity = null;
}
@@ -11273,6 +11417,13 @@
getMobileRadioActiveTimeCounter()
.setState(batteryConsumerProcessState, elapsedRealtimeMs);
+
+ final ControllerActivityCounterImpl wifiControllerActivity =
+ getWifiControllerActivity();
+ if (wifiControllerActivity != null) {
+ wifiControllerActivity.setState(batteryConsumerProcessState, elapsedRealtimeMs);
+ }
+
final MeasuredEnergyStats energyStats =
getOrCreateMeasuredEnergyStatsIfSupportedLocked();
if (energyStats != null) {
@@ -11681,10 +11832,11 @@
mNetworkByteActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
mNetworkPacketActivityCounters[i] = new LongSamplingCounter(mOnBatteryTimeBase);
}
- mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase, NUM_WIFI_TX_LEVELS);
- mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mWifiActivity = new ControllerActivityCounterImpl(mClock, mOnBatteryTimeBase,
+ NUM_WIFI_TX_LEVELS);
+ mBluetoothActivity = new ControllerActivityCounterImpl(mClock, mOnBatteryTimeBase,
NUM_BT_TX_LEVELS);
- mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mModemActivity = new ControllerActivityCounterImpl(mClock, mOnBatteryTimeBase,
ModemActivityInfo.getNumTxPowerLevels());
mMobileRadioActiveTimer = new StopwatchTimer(mClock, null, -400, null, mOnBatteryTimeBase);
mMobileRadioActivePerAppTimer = new StopwatchTimer(mClock, null, -401, null,
@@ -12613,7 +12765,8 @@
continue;
}
- final Uid u = getUidStatsLocked(mapUid(entry.uid), elapsedRealtimeMs, uptimeMs);
+ final int uid = mapUid(entry.uid);
+ final Uid u = getUidStatsLocked(uid, elapsedRealtimeMs, uptimeMs);
if (entry.rxBytes != 0) {
u.noteNetworkActivityLocked(NETWORK_WIFI_RX_DATA, entry.rxBytes,
entry.rxPackets);
@@ -12626,8 +12779,7 @@
mNetworkPacketActivityCounters[NETWORK_WIFI_RX_DATA].addCountLocked(
entry.rxPackets);
- // TODO(b/182845426): What if u was a mapped isolated uid? Shouldn't we sum?
- rxPackets.put(u.getUid(), entry.rxPackets);
+ add(rxPackets, uid, entry.rxPackets);
// Sum the total number of packets so that the Rx Power can
// be evenly distributed amongst the apps.
@@ -12646,8 +12798,7 @@
mNetworkPacketActivityCounters[NETWORK_WIFI_TX_DATA].addCountLocked(
entry.txPackets);
- // TODO(b/182845426): What if u was a mapped isolated uid? Shouldn't we sum?
- txPackets.put(u.getUid(), entry.txPackets);
+ add(txPackets, uid, entry.txPackets);
// Sum the total number of packets so that the Tx Power can
// be evenly distributed amongst the apps.
@@ -12774,9 +12925,10 @@
ControllerActivityCounterImpl activityCounter =
uid.getOrCreateWifiControllerActivityLocked();
- activityCounter.getRxTimeCounter().addCountLocked(scanRxTimeSinceMarkMs);
- activityCounter.getTxTimeCounters()[0].addCountLocked(
- scanTxTimeSinceMarkMs);
+ activityCounter.getOrCreateRxTimeCounter()
+ .increment(scanRxTimeSinceMarkMs, elapsedRealtimeMs);
+ activityCounter.getOrCreateTxTimeCounters()[0]
+ .increment(scanTxTimeSinceMarkMs, elapsedRealtimeMs);
leftOverRxTimeMs -= scanRxTimeSinceMarkMs;
leftOverTxTimeMs -= scanTxTimeSinceMarkMs;
}
@@ -12796,8 +12948,8 @@
Slog.d(TAG, " IdleTime for UID " + uid.getUid() + ": "
+ myIdleTimeMs + " ms");
}
- uid.getOrCreateWifiControllerActivityLocked().getIdleTimeCounter()
- .addCountLocked(myIdleTimeMs);
+ uid.getOrCreateWifiControllerActivityLocked().getOrCreateIdleTimeCounter()
+ .increment(myIdleTimeMs, elapsedRealtimeMs);
}
if (uidEstimatedConsumptionMah != null) {
@@ -12822,8 +12974,8 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, " TxTime for UID " + uid.getUid() + ": " + myTxTimeMs + " ms");
}
- uid.getOrCreateWifiControllerActivityLocked().getTxTimeCounters()[0]
- .addCountLocked(myTxTimeMs);
+ uid.getOrCreateWifiControllerActivityLocked().getOrCreateTxTimeCounters()[0]
+ .increment(myTxTimeMs, elapsedRealtimeMs);
if (uidEstimatedConsumptionMah != null) {
uidEstimatedConsumptionMah.add(uid.getUid(),
mWifiPowerCalculator.calcPowerFromControllerDataMah(
@@ -12841,8 +12993,8 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, " RxTime for UID " + uid.getUid() + ": " + myRxTimeMs + " ms");
}
- uid.getOrCreateWifiControllerActivityLocked().getRxTimeCounter()
- .addCountLocked(myRxTimeMs);
+ uid.getOrCreateWifiControllerActivityLocked().getOrCreateRxTimeCounter()
+ .increment(myRxTimeMs, elapsedRealtimeMs);
if (uidEstimatedConsumptionMah != null) {
uidEstimatedConsumptionMah.add(uid.getUid(),
mWifiPowerCalculator.calcPowerFromControllerDataMah(
@@ -12854,14 +13006,14 @@
// Update WiFi controller stats.
- mWifiActivity.getRxTimeCounter().addCountLocked(
- info.getControllerRxDurationMillis());
- mWifiActivity.getTxTimeCounters()[0].addCountLocked(
- info.getControllerTxDurationMillis());
+ mWifiActivity.getOrCreateRxTimeCounter().increment(
+ info.getControllerRxDurationMillis(), elapsedRealtimeMs);
+ mWifiActivity.getOrCreateTxTimeCounters()[0].increment(
+ info.getControllerTxDurationMillis(), elapsedRealtimeMs);
mWifiActivity.getScanTimeCounter().addCountLocked(
info.getControllerScanDurationMillis());
- mWifiActivity.getIdleTimeCounter().addCountLocked(
- info.getControllerIdleDurationMillis());
+ mWifiActivity.getOrCreateIdleTimeCounter().increment(
+ info.getControllerIdleDurationMillis(), elapsedRealtimeMs);
// POWER_WIFI_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
final double opVolt = mPowerProfile.getAveragePower(
@@ -12961,14 +13113,16 @@
if (deltaInfo != null) {
mHasModemReporting = true;
- mModemActivity.getIdleTimeCounter().addCountLocked(
- deltaInfo.getIdleTimeMillis());
+ mModemActivity.getOrCreateIdleTimeCounter()
+ .increment(deltaInfo.getIdleTimeMillis(), elapsedRealtimeMs);
mModemActivity.getSleepTimeCounter().addCountLocked(
deltaInfo.getSleepTimeMillis());
- mModemActivity.getRxTimeCounter().addCountLocked(deltaInfo.getReceiveTimeMillis());
+ mModemActivity.getOrCreateRxTimeCounter()
+ .increment(deltaInfo.getReceiveTimeMillis(), elapsedRealtimeMs);
for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) {
- mModemActivity.getTxTimeCounters()[lvl]
- .addCountLocked(deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl));
+ mModemActivity.getOrCreateTxTimeCounters()[lvl]
+ .increment(deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl),
+ elapsedRealtimeMs);
}
// POWER_MODEM_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
@@ -13086,7 +13240,8 @@
if (totalRxPackets > 0 && entry.rxPackets > 0) {
final long rxMs = (entry.rxPackets
* deltaInfo.getReceiveTimeMillis()) / totalRxPackets;
- activityCounter.getRxTimeCounter().addCountLocked(rxMs);
+ activityCounter.getOrCreateRxTimeCounter()
+ .increment(rxMs, elapsedRealtimeMs);
}
if (totalTxPackets > 0 && entry.txPackets > 0) {
@@ -13095,7 +13250,8 @@
long txMs = entry.txPackets
* deltaInfo.getTransmitDurationMillisAtPowerLevel(lvl);
txMs /= totalTxPackets;
- activityCounter.getTxTimeCounters()[lvl].addCountLocked(txMs);
+ activityCounter.getOrCreateTxTimeCounters()[lvl]
+ .increment(txMs, elapsedRealtimeMs);
}
}
}
@@ -13193,8 +13349,8 @@
energy = info.getControllerEnergyUsed();
if (!info.getUidTraffic().isEmpty()) {
for (UidTraffic traffic : info.getUidTraffic()) {
- uidRxBytes.put(traffic.getUid(), traffic.getRxBytes());
- uidTxBytes.put(traffic.getUid(), traffic.getTxBytes());
+ add(uidRxBytes, traffic.getUid(), traffic.getRxBytes());
+ add(uidTxBytes, traffic.getUid(), traffic.getTxBytes());
}
}
}
@@ -13317,8 +13473,10 @@
final ControllerActivityCounterImpl counter =
u.getOrCreateBluetoothControllerActivityLocked();
- counter.getRxTimeCounter().addCountLocked(scanTimeRxSinceMarkMs);
- counter.getTxTimeCounters()[0].addCountLocked(scanTimeTxSinceMarkMs);
+ counter.getOrCreateRxTimeCounter()
+ .increment(scanTimeRxSinceMarkMs, elapsedRealtimeMs);
+ counter.getOrCreateTxTimeCounters()[0]
+ .increment(scanTimeTxSinceMarkMs, elapsedRealtimeMs);
if (uidEstimatedConsumptionMah != null) {
uidEstimatedConsumptionMah.add(u.getUid(),
@@ -13385,7 +13543,7 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, "UID=" + uid + " rx_bytes=" + rxBytes + " rx_time=" + timeRxMs);
}
- counter.getRxTimeCounter().addCountLocked(timeRxMs);
+ counter.getOrCreateRxTimeCounter().increment(timeRxMs, elapsedRealtimeMs);
if (uidEstimatedConsumptionMah != null) {
uidEstimatedConsumptionMah.add(u.getUid(),
@@ -13398,7 +13556,8 @@
if (DEBUG_ENERGY) {
Slog.d(TAG, "UID=" + uid + " tx_bytes=" + txBytes + " tx_time=" + timeTxMs);
}
- counter.getTxTimeCounters()[0].addCountLocked(timeTxMs);
+ counter.getOrCreateTxTimeCounters()[0]
+ .increment(timeTxMs, elapsedRealtimeMs);
if (uidEstimatedConsumptionMah != null) {
uidEstimatedConsumptionMah.add(u.getUid(),
@@ -13408,9 +13567,9 @@
}
}
- mBluetoothActivity.getRxTimeCounter().addCountLocked(rxTimeMs);
- mBluetoothActivity.getTxTimeCounters()[0].addCountLocked(txTimeMs);
- mBluetoothActivity.getIdleTimeCounter().addCountLocked(idleTimeMs);
+ mBluetoothActivity.getOrCreateRxTimeCounter().increment(rxTimeMs, elapsedRealtimeMs);
+ mBluetoothActivity.getOrCreateTxTimeCounters()[0].increment(txTimeMs, elapsedRealtimeMs);
+ mBluetoothActivity.getOrCreateIdleTimeCounter().increment(idleTimeMs, elapsedRealtimeMs);
// POWER_BLUETOOTH_CONTROLLER_OPERATING_VOLTAGE is measured in mV, so convert to V.
final double opVolt = mPowerProfile.getAveragePower(
@@ -16288,6 +16447,7 @@
@GuardedBy("this")
public void readSummaryFromParcel(Parcel in) throws ParcelFormatException {
final int version = in.readInt();
+
if (version != VERSION) {
Slog.w("BatteryStats", "readFromParcel: version got " + version
+ ", expected " + VERSION + "; erasing old stats");
@@ -17447,15 +17607,15 @@
}
mWifiActiveTimer = new StopwatchTimer(mClock, null, -900, null,
mOnBatteryTimeBase, in);
- mWifiActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mWifiActivity = new ControllerActivityCounterImpl(mClock, mOnBatteryTimeBase,
NUM_WIFI_TX_LEVELS, in);
for (int i=0; i<mGpsSignalQualityTimer.length; i++) {
mGpsSignalQualityTimer[i] = new StopwatchTimer(mClock, null, -1000 - i,
null, mOnBatteryTimeBase, in);
}
- mBluetoothActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mBluetoothActivity = new ControllerActivityCounterImpl(mClock, mOnBatteryTimeBase,
NUM_BT_TX_LEVELS, in);
- mModemActivity = new ControllerActivityCounterImpl(mOnBatteryTimeBase,
+ mModemActivity = new ControllerActivityCounterImpl(mClock, mOnBatteryTimeBase,
ModemActivityInfo.getNumTxPowerLevels(), in);
mHasWifiReporting = in.readInt() != 0;
mHasBluetoothReporting = in.readInt() != 0;
@@ -17980,4 +18140,8 @@
pw.println();
dumpMeasuredEnergyStatsLocked(pw);
}
+
+ private static void add(SparseLongArray array, int key, long delta) {
+ array.put(key, array.get(key) + delta);
+ }
}
diff --git a/core/java/com/android/internal/os/WifiPowerCalculator.java b/core/java/com/android/internal/os/WifiPowerCalculator.java
index 3915b0e..2a71ac6 100644
--- a/core/java/com/android/internal/os/WifiPowerCalculator.java
+++ b/core/java/com/android/internal/os/WifiPowerCalculator.java
@@ -25,6 +25,7 @@
import android.util.Log;
import android.util.SparseArray;
+import java.util.Arrays;
import java.util.List;
/**
@@ -34,6 +35,9 @@
public class WifiPowerCalculator extends PowerCalculator {
private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
private static final String TAG = "WifiPowerCalculator";
+
+ private static final BatteryConsumer.Key[] UNINITIALIZED_KEYS = new BatteryConsumer.Key[0];
+
private final UsageBasedPowerEstimator mIdlePowerEstimator;
private final UsageBasedPowerEstimator mTxPowerEstimator;
private final UsageBasedPowerEstimator mRxPowerEstimator;
@@ -51,6 +55,9 @@
public long wifiTxPackets;
public long wifiRxBytes;
public long wifiTxBytes;
+
+ public BatteryConsumer.Key[] keys;
+ public double[] powerPerKeyMah;
}
public WifiPowerCalculator(PowerProfile profile) {
@@ -77,7 +84,7 @@
@Override
public void calculate(BatteryUsageStats.Builder builder, BatteryStats batteryStats,
long rawRealtimeUs, long rawUptimeUs, BatteryUsageStatsQuery query) {
-
+ BatteryConsumer.Key[] keys = UNINITIALIZED_KEYS;
long totalAppDurationMs = 0;
double totalAppPowerMah = 0;
final PowerDurationAndTraffic powerDurationAndTraffic = new PowerDurationAndTraffic();
@@ -85,9 +92,20 @@
builder.getUidBatteryConsumerBuilders();
for (int i = uidBatteryConsumerBuilders.size() - 1; i >= 0; i--) {
final UidBatteryConsumer.Builder app = uidBatteryConsumerBuilders.valueAt(i);
+ if (keys == UNINITIALIZED_KEYS) {
+ if (query.isProcessStateDataNeeded()) {
+ keys = app.getKeys(BatteryConsumer.POWER_COMPONENT_WIFI);
+ powerDurationAndTraffic.keys = keys;
+ powerDurationAndTraffic.powerPerKeyMah = new double[keys.length];
+ } else {
+ keys = null;
+ }
+ }
+
final long consumptionUC =
app.getBatteryStatsUid().getWifiMeasuredBatteryConsumptionUC();
final int powerModel = getPowerModel(consumptionUC, query);
+
calculateApp(powerDurationAndTraffic, app.getBatteryStatsUid(), powerModel,
rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED,
batteryStats.hasWifiActivityReporting(), consumptionUC);
@@ -99,6 +117,20 @@
powerDurationAndTraffic.durationMs);
app.setConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI,
powerDurationAndTraffic.powerMah, powerModel);
+
+ if (query.isProcessStateDataNeeded() && keys != null) {
+ for (int j = 0; j < keys.length; j++) {
+ BatteryConsumer.Key key = keys[j];
+ final int processState = key.processState;
+ if (processState == BatteryConsumer.PROCESS_STATE_UNSPECIFIED) {
+ // Already populated with the total across all process states
+ continue;
+ }
+
+ app.setConsumedPower(key, powerDurationAndTraffic.powerPerKeyMah[j],
+ powerModel);
+ }
+ }
}
final long consumptionUC = batteryStats.getWifiMeasuredBatteryConsumptionUC();
@@ -193,21 +225,23 @@
BatteryStats.NETWORK_WIFI_TX_DATA,
statsType);
- if (powerModel == BatteryConsumer.POWER_MODEL_MEASURED_ENERGY) {
- powerDurationAndTraffic.powerMah = uCtoMah(consumptionUC);
- }
-
if (hasWifiActivityReporting && mHasWifiPowerController) {
final BatteryStats.ControllerActivityCounter counter = u.getWifiControllerActivity();
if (counter != null) {
- final long idleTime = counter.getIdleTimeCounter().getCountLocked(statsType);
- final long txTime = counter.getTxTimeCounters()[0].getCountLocked(statsType);
- final long rxTime = counter.getRxTimeCounter().getCountLocked(statsType);
+ final BatteryStats.LongCounter rxTimeCounter = counter.getRxTimeCounter();
+ final BatteryStats.LongCounter txTimeCounter = counter.getTxTimeCounters()[0];
+ final BatteryStats.LongCounter idleTimeCounter = counter.getIdleTimeCounter();
+
+ final long rxTime = rxTimeCounter.getCountLocked(statsType);
+ final long txTime = txTimeCounter.getCountLocked(statsType);
+ final long idleTime = idleTimeCounter.getCountLocked(statsType);
powerDurationAndTraffic.durationMs = idleTime + rxTime + txTime;
if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
powerDurationAndTraffic.powerMah
= calcPowerFromControllerDataMah(rxTime, txTime, idleTime);
+ } else {
+ powerDurationAndTraffic.powerMah = uCtoMah(consumptionUC);
}
if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
@@ -215,9 +249,32 @@
+ "ms tx=" + txTime + "ms power=" + formatCharge(
powerDurationAndTraffic.powerMah));
}
+
+ if (powerDurationAndTraffic.keys != null) {
+ for (int i = 0; i < powerDurationAndTraffic.keys.length; i++) {
+ final int processState = powerDurationAndTraffic.keys[i].processState;
+ if (processState == BatteryConsumer.PROCESS_STATE_UNSPECIFIED) {
+ continue;
+ }
+
+ if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+ powerDurationAndTraffic.powerPerKeyMah[i] =
+ calcPowerFromControllerDataMah(
+ rxTimeCounter.getCountForProcessState(processState),
+ txTimeCounter.getCountForProcessState(processState),
+ idleTimeCounter.getCountForProcessState(processState));
+ } else {
+ powerDurationAndTraffic.powerPerKeyMah[i] =
+ uCtoMah(u.getWifiMeasuredBatteryConsumptionUC(processState));
+ }
+ }
+ }
} else {
powerDurationAndTraffic.durationMs = 0;
powerDurationAndTraffic.powerMah = 0;
+ if (powerDurationAndTraffic.powerPerKeyMah != null) {
+ Arrays.fill(powerDurationAndTraffic.powerPerKeyMah, 0);
+ }
}
} else {
final long wifiRunningTime = u.getWifiRunningTime(rawRealtimeUs, statsType) / 1000;
@@ -233,6 +290,14 @@
powerDurationAndTraffic.wifiRxPackets,
powerDurationAndTraffic.wifiTxPackets,
wifiRunningTime, wifiScanTimeMs, batchTimeMs);
+ } else {
+ powerDurationAndTraffic.powerMah = uCtoMah(consumptionUC);
+ }
+
+ if (powerDurationAndTraffic.powerPerKeyMah != null) {
+ // Per-process state attribution is not supported in the absence of WiFi
+ // activity reporting
+ Arrays.fill(powerDurationAndTraffic.powerPerKeyMah, 0);
}
if (DEBUG && powerDurationAndTraffic.powerMah != 0) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d6bbe71..d0b9f88 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -716,6 +716,7 @@
<!-- Added in T -->
<protected-broadcast android:name="android.intent.action.REFRESH_SAFETY_SOURCES" />
+ <protected-broadcast android:name="android.app.action.DEVICE_POLICY_RESOURCE_UPDATED" />
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index e055749..a595433 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2829,14 +2829,6 @@
<attr name="path" />
<attr name="minSdkVersion" />
<attr name="maxSdkVersion" />
- <!-- The order in which the apex system services are initiated. When there are dependencies
- among apex system services, setting this attribute for each of them ensures that they are
- created in the order required by those dependencies. The apex-system-services that are
- started manually within SystemServer ignore the initOrder and are not considered for
- automatic starting of the other services.
- The value is a simple integer, with higher number being initialized first. If not specified,
- the default order is 0. -->
- <attr name="initOrder" format="integer" />
</declare-styleable>
<!-- The <code>receiver</code> tag declares an
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
index 1b1f64a..bd987a0 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
+++ b/core/tests/batterystatstests/BatteryStatsViewer/AndroidManifest.xml
@@ -16,8 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.core.batterystatsviewer"
- android:sharedUserId="android.uid.system">
+ package="com.android.frameworks.core.batterystatsviewer">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BATTERY_STATS"/>
diff --git a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index eb378b9..6a53f68 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -130,23 +130,20 @@
|| powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) {
addEntry(metricTitle, EntryType.UID_POWER_MODELED,
requestedBatteryConsumer.getConsumedPower(component),
- totalPowerByComponentMah[component]
- );
+ totalPowerByComponentMah[component]);
+ addProcessStateEntries(metricTitle, EntryType.UID_POWER_MODELED_PROCESS_STATE,
+ requestedBatteryConsumer, component);
} else {
addEntry(metricTitle + " (measured)", EntryType.UID_POWER_MEASURED,
requestedBatteryConsumer.getConsumedPower(component),
- totalPowerByComponentMah[component]
- );
+ totalPowerByComponentMah[component]);
addProcessStateEntries(metricTitle, EntryType.UID_POWER_MEASURED_PROCESS_STATE,
- requestedBatteryConsumer, component
- );
+ requestedBatteryConsumer, component);
addEntry(metricTitle + " (modeled)", EntryType.UID_POWER_MODELED,
requestedModeledBatteryConsumer.getConsumedPower(component),
- totalModeledPowerByComponentMah[component]
- );
+ totalModeledPowerByComponentMah[component]);
addProcessStateEntries(metricTitle, EntryType.UID_POWER_MODELED_PROCESS_STATE,
- requestedModeledBatteryConsumer, component
- );
+ requestedModeledBatteryConsumer, component);
}
}
diff --git a/core/tests/bluetoothtests/Android.bp b/core/tests/bluetoothtests/Android.bp
deleted file mode 100644
index 68416dd..0000000
--- a/core/tests/bluetoothtests/Android.bp
+++ /dev/null
@@ -1,24 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
- name: "BluetoothTests",
- // Include all test java files.
- srcs: ["src/**/*.java"],
- libs: [
- "android.test.runner",
- "android.test.base",
- ],
- static_libs: [
- "junit",
- "modules-utils-bytesmatcher",
- ],
- platform_apis: true,
- certificate: "platform",
-}
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
deleted file mode 100644
index 75583d5..0000000
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.bluetooth.tests"
- android:sharedUserId="android.uid.bluetooth" >
-
- <uses-permission android:name="android.permission.BLUETOOTH" />
- <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
- <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
- <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
- <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
- <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" />
- <uses-permission android:name="android.permission.BROADCAST_STICKY" />
- <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
- <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
- <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
- <uses-permission android:name="android.permission.RECEIVE_SMS" />
- <uses-permission android:name="android.permission.READ_SMS"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.WRITE_SETTINGS" />
- <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
-
- <application >
- <uses-library android:name="android.test.runner" />
- </application>
- <instrumentation android:name="android.bluetooth.BluetoothTestRunner"
- android:targetPackage="com.android.bluetooth.tests"
- android:label="Bluetooth Tests" />
- <instrumentation android:name="android.bluetooth.BluetoothInstrumentation"
- android:targetPackage="com.android.bluetooth.tests"
- android:label="Bluetooth Test Utils" />
-
-</manifest>
diff --git a/core/tests/bluetoothtests/AndroidTest.xml b/core/tests/bluetoothtests/AndroidTest.xml
deleted file mode 100644
index f93c4eb..0000000
--- a/core/tests/bluetoothtests/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2020 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for Bluetooth test cases">
- <option name="test-suite-tag" value="apct"/>
- <option name="test-suite-tag" value="apct-instrumentation"/>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="BluetoothTests.apk" />
- </target_preparer>
-
- <option name="test-suite-tag" value="apct"/>
- <option name="test-tag" value="BluetoothTests"/>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.bluetooth.tests" />
- <option name="hidden-api-checks" value="false"/>
- <option name="runner" value="android.bluetooth.BluetoothTestRunner"/>
- </test>
-</configuration>
diff --git a/core/tests/bluetoothtests/OWNERS b/core/tests/bluetoothtests/OWNERS
deleted file mode 100644
index 98bb877..0000000
--- a/core/tests/bluetoothtests/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /core/java/android/bluetooth/OWNERS
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
deleted file mode 100644
index bd55426..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * Unit test cases for {@link BluetoothCodecConfig}.
- * <p>
- * To run this test, use:
- * runtest --path core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecConfigTest.java
- */
-public class BluetoothCodecConfigTest extends TestCase {
- private static final int[] kCodecTypeArray = new int[] {
- BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
- BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
- BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID,
- };
- private static final int[] kCodecPriorityArray = new int[] {
- BluetoothCodecConfig.CODEC_PRIORITY_DISABLED,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST,
- };
- private static final int[] kSampleRateArray = new int[] {
- BluetoothCodecConfig.SAMPLE_RATE_NONE,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.SAMPLE_RATE_88200,
- BluetoothCodecConfig.SAMPLE_RATE_96000,
- BluetoothCodecConfig.SAMPLE_RATE_176400,
- BluetoothCodecConfig.SAMPLE_RATE_192000,
- };
- private static final int[] kBitsPerSampleArray = new int[] {
- BluetoothCodecConfig.BITS_PER_SAMPLE_NONE,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.BITS_PER_SAMPLE_24,
- BluetoothCodecConfig.BITS_PER_SAMPLE_32,
- };
- private static final int[] kChannelModeArray = new int[] {
- BluetoothCodecConfig.CHANNEL_MODE_NONE,
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- };
- private static final long[] kCodecSpecific1Array = new long[] { 1000, 1001, 1002, 1003, };
- private static final long[] kCodecSpecific2Array = new long[] { 2000, 2001, 2002, 2003, };
- private static final long[] kCodecSpecific3Array = new long[] { 3000, 3001, 3002, 3003, };
- private static final long[] kCodecSpecific4Array = new long[] { 4000, 4001, 4002, 4003, };
-
- private static final int kTotalConfigs = kCodecTypeArray.length * kCodecPriorityArray.length *
- kSampleRateArray.length * kBitsPerSampleArray.length * kChannelModeArray.length *
- kCodecSpecific1Array.length * kCodecSpecific2Array.length * kCodecSpecific3Array.length *
- kCodecSpecific4Array.length;
-
- private int selectCodecType(int configId) {
- int left = kCodecTypeArray.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kCodecTypeArray.length;
- return kCodecTypeArray[index];
- }
-
- private int selectCodecPriority(int configId) {
- int left = kCodecTypeArray.length * kCodecPriorityArray.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kCodecPriorityArray.length;
- return kCodecPriorityArray[index];
- }
-
- private int selectSampleRate(int configId) {
- int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kSampleRateArray.length;
- return kSampleRateArray[index];
- }
-
- private int selectBitsPerSample(int configId) {
- int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length *
- kBitsPerSampleArray.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kBitsPerSampleArray.length;
- return kBitsPerSampleArray[index];
- }
-
- private int selectChannelMode(int configId) {
- int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length *
- kBitsPerSampleArray.length * kChannelModeArray.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kChannelModeArray.length;
- return kChannelModeArray[index];
- }
-
- private long selectCodecSpecific1(int configId) {
- int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length *
- kBitsPerSampleArray.length * kChannelModeArray.length * kCodecSpecific1Array.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kCodecSpecific1Array.length;
- return kCodecSpecific1Array[index];
- }
-
- private long selectCodecSpecific2(int configId) {
- int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length *
- kBitsPerSampleArray.length * kChannelModeArray.length * kCodecSpecific1Array.length *
- kCodecSpecific2Array.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kCodecSpecific2Array.length;
- return kCodecSpecific2Array[index];
- }
-
- private long selectCodecSpecific3(int configId) {
- int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length *
- kBitsPerSampleArray.length * kChannelModeArray.length * kCodecSpecific1Array.length *
- kCodecSpecific2Array.length * kCodecSpecific3Array.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kCodecSpecific3Array.length;
- return kCodecSpecific3Array[index];
- }
-
- private long selectCodecSpecific4(int configId) {
- int left = kCodecTypeArray.length * kCodecPriorityArray.length * kSampleRateArray.length *
- kBitsPerSampleArray.length * kChannelModeArray.length * kCodecSpecific1Array.length *
- kCodecSpecific2Array.length * kCodecSpecific3Array.length *
- kCodecSpecific4Array.length;
- int right = kTotalConfigs / left;
- int index = configId / right;
- index = index % kCodecSpecific4Array.length;
- return kCodecSpecific4Array[index];
- }
-
- @SmallTest
- public void testBluetoothCodecConfig_valid_get_methods() {
-
- for (int config_id = 0; config_id < kTotalConfigs; config_id++) {
- int codec_type = selectCodecType(config_id);
- int codec_priority = selectCodecPriority(config_id);
- int sample_rate = selectSampleRate(config_id);
- int bits_per_sample = selectBitsPerSample(config_id);
- int channel_mode = selectChannelMode(config_id);
- long codec_specific1 = selectCodecSpecific1(config_id);
- long codec_specific2 = selectCodecSpecific2(config_id);
- long codec_specific3 = selectCodecSpecific3(config_id);
- long codec_specific4 = selectCodecSpecific4(config_id);
-
- BluetoothCodecConfig bcc = buildBluetoothCodecConfig(codec_type, codec_priority,
- sample_rate, bits_per_sample,
- channel_mode, codec_specific1,
- codec_specific2, codec_specific3,
- codec_specific4);
-
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) {
- assertTrue(bcc.isMandatoryCodec());
- } else {
- assertFalse(bcc.isMandatoryCodec());
- }
-
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC) {
- assertEquals("SBC", bcc.getCodecName());
- }
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC) {
- assertEquals("AAC", bcc.getCodecName());
- }
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX) {
- assertEquals("aptX", bcc.getCodecName());
- }
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD) {
- assertEquals("aptX HD", bcc.getCodecName());
- }
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC) {
- assertEquals("LDAC", bcc.getCodecName());
- }
- if (codec_type == BluetoothCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
- assertEquals("INVALID CODEC", bcc.getCodecName());
- }
-
- assertEquals(codec_type, bcc.getCodecType());
- assertEquals(codec_priority, bcc.getCodecPriority());
- assertEquals(sample_rate, bcc.getSampleRate());
- assertEquals(bits_per_sample, bcc.getBitsPerSample());
- assertEquals(channel_mode, bcc.getChannelMode());
- assertEquals(codec_specific1, bcc.getCodecSpecific1());
- assertEquals(codec_specific2, bcc.getCodecSpecific2());
- assertEquals(codec_specific3, bcc.getCodecSpecific3());
- assertEquals(codec_specific4, bcc.getCodecSpecific4());
- }
- }
-
- @SmallTest
- public void testBluetoothCodecConfig_equals() {
- BluetoothCodecConfig bcc1 =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- BluetoothCodecConfig bcc2_same =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
- assertTrue(bcc1.equals(bcc2_same));
-
- BluetoothCodecConfig bcc3_codec_type =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
- assertFalse(bcc1.equals(bcc3_codec_type));
-
- BluetoothCodecConfig bcc4_codec_priority =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_HIGHEST,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
- assertFalse(bcc1.equals(bcc4_codec_priority));
-
- BluetoothCodecConfig bcc5_sample_rate =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
- assertFalse(bcc1.equals(bcc5_sample_rate));
-
- BluetoothCodecConfig bcc6_bits_per_sample =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_24,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
- assertFalse(bcc1.equals(bcc6_bits_per_sample));
-
- BluetoothCodecConfig bcc7_channel_mode =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
- assertFalse(bcc1.equals(bcc7_channel_mode));
-
- BluetoothCodecConfig bcc8_codec_specific1 =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1001, 2000, 3000, 4000);
- assertFalse(bcc1.equals(bcc8_codec_specific1));
-
- BluetoothCodecConfig bcc9_codec_specific2 =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2002, 3000, 4000);
- assertFalse(bcc1.equals(bcc9_codec_specific2));
-
- BluetoothCodecConfig bcc10_codec_specific3 =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3003, 4000);
- assertFalse(bcc1.equals(bcc10_codec_specific3));
-
- BluetoothCodecConfig bcc11_codec_specific4 =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4004);
- assertFalse(bcc1.equals(bcc11_codec_specific4));
- }
-
- private BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType,
- int codecPriority, int sampleRate, int bitsPerSample, int channelMode,
- long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) {
- return new BluetoothCodecConfig.Builder()
- .setCodecType(sourceCodecType)
- .setCodecPriority(codecPriority)
- .setSampleRate(sampleRate)
- .setBitsPerSample(bitsPerSample)
- .setChannelMode(channelMode)
- .setCodecSpecific1(codecSpecific1)
- .setCodecSpecific2(codecSpecific2)
- .setCodecSpecific3(codecSpecific3)
- .setCodecSpecific4(codecSpecific4)
- .build();
-
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
deleted file mode 100644
index 1cb2dca..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Unit test cases for {@link BluetoothCodecStatus}.
- * <p>
- * To run this test, use:
- * runtest --path core/tests/bluetoothtests/src/android/bluetooth/BluetoothCodecStatusTest.java
- */
-public class BluetoothCodecStatusTest extends TestCase {
-
- // Codec configs: A and B are same; C is different
- private static final BluetoothCodecConfig config_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig config_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig config_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- // Local capabilities: A and B are same; C is different
- private static final BluetoothCodecConfig local_capability1_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability1_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability1_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
-
- private static final BluetoothCodecConfig local_capability2_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability2_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability2_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability3_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability3_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability3_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability4_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_24,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability4_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_24,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability4_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_24,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability5_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000 |
- BluetoothCodecConfig.SAMPLE_RATE_88200 |
- BluetoothCodecConfig.SAMPLE_RATE_96000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_24 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_32,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability5_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000 |
- BluetoothCodecConfig.SAMPLE_RATE_88200 |
- BluetoothCodecConfig.SAMPLE_RATE_96000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_24 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_32,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig local_capability5_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000 |
- BluetoothCodecConfig.SAMPLE_RATE_88200 |
- BluetoothCodecConfig.SAMPLE_RATE_96000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_24 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_32,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
-
- // Selectable capabilities: A and B are same; C is different
- private static final BluetoothCodecConfig selectable_capability1_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability1_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability1_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_SBC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability2_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability2_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability2_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_AAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability3_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability3_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability3_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability4_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_24,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability4_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_24,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability4_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_APTX_HD,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100,
- BluetoothCodecConfig.BITS_PER_SAMPLE_24,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability5_A =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000 |
- BluetoothCodecConfig.SAMPLE_RATE_88200 |
- BluetoothCodecConfig.SAMPLE_RATE_96000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_24 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_32,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability5_B =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000 |
- BluetoothCodecConfig.SAMPLE_RATE_88200 |
- BluetoothCodecConfig.SAMPLE_RATE_96000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_24 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_32,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO |
- BluetoothCodecConfig.CHANNEL_MODE_MONO,
- 1000, 2000, 3000, 4000);
-
- private static final BluetoothCodecConfig selectable_capability5_C =
- buildBluetoothCodecConfig(BluetoothCodecConfig.SOURCE_CODEC_TYPE_LDAC,
- BluetoothCodecConfig.CODEC_PRIORITY_DEFAULT,
- BluetoothCodecConfig.SAMPLE_RATE_44100 |
- BluetoothCodecConfig.SAMPLE_RATE_48000 |
- BluetoothCodecConfig.SAMPLE_RATE_88200 |
- BluetoothCodecConfig.SAMPLE_RATE_96000,
- BluetoothCodecConfig.BITS_PER_SAMPLE_16 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_24 |
- BluetoothCodecConfig.BITS_PER_SAMPLE_32,
- BluetoothCodecConfig.CHANNEL_MODE_STEREO,
- 1000, 2000, 3000, 4000);
-
- private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_A =
- new ArrayList() {{
- add(local_capability1_A);
- add(local_capability2_A);
- add(local_capability3_A);
- add(local_capability4_A);
- add(local_capability5_A);
- }};
-
- private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_B =
- new ArrayList() {{
- add(local_capability1_B);
- add(local_capability2_B);
- add(local_capability3_B);
- add(local_capability4_B);
- add(local_capability5_B);
- }};
-
- private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_B_REORDERED =
- new ArrayList() {{
- add(local_capability5_B);
- add(local_capability4_B);
- add(local_capability2_B);
- add(local_capability3_B);
- add(local_capability1_B);
- }};
-
- private static final List<BluetoothCodecConfig> LOCAL_CAPABILITY_C =
- new ArrayList() {{
- add(local_capability1_C);
- add(local_capability2_C);
- add(local_capability3_C);
- add(local_capability4_C);
- add(local_capability5_C);
- }};
-
- private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_A =
- new ArrayList() {{
- add(selectable_capability1_A);
- add(selectable_capability2_A);
- add(selectable_capability3_A);
- add(selectable_capability4_A);
- add(selectable_capability5_A);
- }};
-
- private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_B =
- new ArrayList() {{
- add(selectable_capability1_B);
- add(selectable_capability2_B);
- add(selectable_capability3_B);
- add(selectable_capability4_B);
- add(selectable_capability5_B);
- }};
-
- private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_B_REORDERED =
- new ArrayList() {{
- add(selectable_capability5_B);
- add(selectable_capability4_B);
- add(selectable_capability2_B);
- add(selectable_capability3_B);
- add(selectable_capability1_B);
- }};
-
- private static final List<BluetoothCodecConfig> SELECTABLE_CAPABILITY_C =
- new ArrayList() {{
- add(selectable_capability1_C);
- add(selectable_capability2_C);
- add(selectable_capability3_C);
- add(selectable_capability4_C);
- add(selectable_capability5_C);
- }};
-
- private static final BluetoothCodecStatus bcs_A =
- new BluetoothCodecStatus(config_A, LOCAL_CAPABILITY_A, SELECTABLE_CAPABILITY_A);
- private static final BluetoothCodecStatus bcs_B =
- new BluetoothCodecStatus(config_B, LOCAL_CAPABILITY_B, SELECTABLE_CAPABILITY_B);
- private static final BluetoothCodecStatus bcs_B_reordered =
- new BluetoothCodecStatus(config_B, LOCAL_CAPABILITY_B_REORDERED,
- SELECTABLE_CAPABILITY_B_REORDERED);
- private static final BluetoothCodecStatus bcs_C =
- new BluetoothCodecStatus(config_C, LOCAL_CAPABILITY_C, SELECTABLE_CAPABILITY_C);
-
- @SmallTest
- public void testBluetoothCodecStatus_get_methods() {
-
- assertTrue(Objects.equals(bcs_A.getCodecConfig(), config_A));
- assertTrue(Objects.equals(bcs_A.getCodecConfig(), config_B));
- assertFalse(Objects.equals(bcs_A.getCodecConfig(), config_C));
-
- assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_A));
- assertTrue(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_B));
- assertFalse(bcs_A.getCodecsLocalCapabilities().equals(LOCAL_CAPABILITY_C));
-
- assertTrue(bcs_A.getCodecsSelectableCapabilities()
- .equals(SELECTABLE_CAPABILITY_A));
- assertTrue(bcs_A.getCodecsSelectableCapabilities()
- .equals(SELECTABLE_CAPABILITY_B));
- assertFalse(bcs_A.getCodecsSelectableCapabilities()
- .equals(SELECTABLE_CAPABILITY_C));
- }
-
- @SmallTest
- public void testBluetoothCodecStatus_equals() {
- assertTrue(bcs_A.equals(bcs_B));
- assertTrue(bcs_B.equals(bcs_A));
- assertTrue(bcs_A.equals(bcs_B_reordered));
- assertTrue(bcs_B_reordered.equals(bcs_A));
- assertFalse(bcs_A.equals(bcs_C));
- assertFalse(bcs_C.equals(bcs_A));
- }
-
- private static BluetoothCodecConfig buildBluetoothCodecConfig(int sourceCodecType,
- int codecPriority, int sampleRate, int bitsPerSample, int channelMode,
- long codecSpecific1, long codecSpecific2, long codecSpecific3, long codecSpecific4) {
- return new BluetoothCodecConfig.Builder()
- .setCodecType(sourceCodecType)
- .setCodecPriority(codecPriority)
- .setSampleRate(sampleRate)
- .setBitsPerSample(bitsPerSample)
- .setChannelMode(channelMode)
- .setCodecSpecific1(codecSpecific1)
- .setCodecSpecific2(codecSpecific2)
- .setCodecSpecific3(codecSpecific3)
- .setCodecSpecific4(codecSpecific4)
- .build();
-
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
deleted file mode 100644
index 37b2a50..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.bluetooth;
-
-import android.app.Activity;
-import android.app.Instrumentation;
-import android.content.Context;
-import android.os.Bundle;
-
-import junit.framework.Assert;
-
-import java.util.Set;
-
-public class BluetoothInstrumentation extends Instrumentation {
-
- private BluetoothTestUtils mUtils = null;
- private BluetoothAdapter mAdapter = null;
- private Bundle mArgs = null;
- private Bundle mSuccessResult = null;
-
- private BluetoothTestUtils getBluetoothTestUtils() {
- if (mUtils == null) {
- mUtils = new BluetoothTestUtils(getContext(),
- BluetoothInstrumentation.class.getSimpleName());
- }
- return mUtils;
- }
-
- private BluetoothAdapter getBluetoothAdapter() {
- if (mAdapter == null) {
- mAdapter = ((BluetoothManager)getContext().getSystemService(
- Context.BLUETOOTH_SERVICE)).getAdapter();
- }
- return mAdapter;
- }
-
- @Override
- public void onCreate(Bundle arguments) {
- super.onCreate(arguments);
- mArgs = arguments;
- // create the default result response, but only use it in success code path
- mSuccessResult = new Bundle();
- mSuccessResult.putString("result", "SUCCESS");
- start();
- }
-
- @Override
- public void onStart() {
- String command = mArgs.getString("command");
- if ("enable".equals(command)) {
- enable();
- } else if ("disable".equals(command)) {
- disable();
- } else if ("unpairAll".equals(command)) {
- unpairAll();
- } else if ("getName".equals(command)) {
- getName();
- } else if ("getAddress".equals(command)) {
- getAddress();
- } else if ("getBondedDevices".equals(command)) {
- getBondedDevices();
- } else {
- finish(null);
- }
- }
-
- public void enable() {
- getBluetoothTestUtils().enable(getBluetoothAdapter());
- finish(mSuccessResult);
- }
-
- public void disable() {
- getBluetoothTestUtils().disable(getBluetoothAdapter());
- finish(mSuccessResult);
- }
-
- public void unpairAll() {
- getBluetoothTestUtils().unpairAll(getBluetoothAdapter());
- finish(mSuccessResult);
- }
-
- public void getName() {
- String name = getBluetoothAdapter().getName();
- mSuccessResult.putString("name", name);
- finish(mSuccessResult);
- }
-
- public void getAddress() {
- String name = getBluetoothAdapter().getAddress();
- mSuccessResult.putString("address", name);
- finish(mSuccessResult);
- }
-
- public void getBondedDevices() {
- Set<BluetoothDevice> devices = getBluetoothAdapter().getBondedDevices();
- int i = 0;
- for (BluetoothDevice device : devices) {
- mSuccessResult.putString(String.format("device-%02d", i), device.getAddress());
- i++;
- }
- finish(mSuccessResult);
- }
-
- public void finish(Bundle result) {
- if (result == null) {
- result = new Bundle();
- }
- finish(Activity.RESULT_OK, result);
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java
deleted file mode 100644
index c3d707c..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothLeAudioCodecConfigTest.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * Unit test cases for {@link BluetoothLeAudioCodecConfig}.
- */
-public class BluetoothLeAudioCodecConfigTest extends TestCase {
- private int[] mCodecTypeArray = new int[] {
- BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3,
- BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID,
- };
-
- @SmallTest
- public void testBluetoothLeAudioCodecConfig_valid_get_methods() {
-
- for (int codecIdx = 0; codecIdx < mCodecTypeArray.length; codecIdx++) {
- int codecType = mCodecTypeArray[codecIdx];
-
- BluetoothLeAudioCodecConfig leAudioCodecConfig =
- buildBluetoothLeAudioCodecConfig(codecType);
-
- if (codecType == BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_LC3) {
- assertEquals("LC3", leAudioCodecConfig.getCodecName());
- }
- if (codecType == BluetoothLeAudioCodecConfig.SOURCE_CODEC_TYPE_INVALID) {
- assertEquals("INVALID CODEC", leAudioCodecConfig.getCodecName());
- }
-
- assertEquals(codecType, leAudioCodecConfig.getCodecType());
- }
- }
-
- private BluetoothLeAudioCodecConfig buildBluetoothLeAudioCodecConfig(int sourceCodecType) {
- return new BluetoothLeAudioCodecConfig.Builder()
- .setCodecType(sourceCodecType)
- .build();
-
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothRebootStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothRebootStressTest.java
deleted file mode 100644
index 33e9dd7..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothRebootStressTest.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.content.Context;
-import android.test.InstrumentationTestCase;
-
-/**
- * Instrumentation test case for stress test involving rebooting the device.
- * <p>
- * This test case tests that bluetooth is enabled after a device reboot. Because
- * the device will reboot, the instrumentation must be driven by a script on the
- * host side.
- */
-public class BluetoothRebootStressTest extends InstrumentationTestCase {
- private static final String TAG = "BluetoothRebootStressTest";
- private static final String OUTPUT_FILE = "BluetoothRebootStressTestOutput.txt";
-
- private BluetoothTestUtils mTestUtils;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- Context context = getInstrumentation().getTargetContext();
- mTestUtils = new BluetoothTestUtils(context, TAG, OUTPUT_FILE);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
-
- mTestUtils.close();
- }
-
- /**
- * Test method used to start the test by turning bluetooth on.
- */
- public void testStart() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- mTestUtils.enable(adapter);
- }
-
- /**
- * Test method used in the middle iterations of the test to check if
- * bluetooth is on. Does not toggle bluetooth after the check. Assumes that
- * bluetooth has been turned on by {@code #testStart()}
- */
- public void testMiddleNoToggle() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
- assertTrue(adapter.isEnabled());
- }
-
- /**
- * Test method used in the middle iterations of the test to check if
- * bluetooth is on. Toggles bluetooth after the check. Assumes that
- * bluetooth has been turned on by {@code #testStart()}
- */
- public void testMiddleToggle() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
- assertTrue(adapter.isEnabled());
-
- mTestUtils.disable(adapter);
- mTestUtils.enable(adapter);
- }
-
- /**
- * Test method used in the stop the test by turning bluetooth off. Assumes
- * that bluetooth has been turned on by {@code #testStart()}
- */
- public void testStop() {
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-
- assertTrue(adapter.isEnabled());
-
- mTestUtils.disable(adapter);
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
deleted file mode 100644
index 89dbe3f..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
+++ /dev/null
@@ -1,393 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.content.Context;
-import android.test.InstrumentationTestCase;
-
-/**
- * Stress test suite for Bluetooth related functions.
- *
- * Includes tests for enabling/disabling bluetooth, enabling/disabling discoverable mode,
- * starting/stopping scans, connecting/disconnecting to HFP, A2DP, HID, PAN profiles, and verifying
- * that remote connections/disconnections occur for the PAN profile.
- * <p>
- * This test suite uses {@link android.bluetooth.BluetoothTestRunner} to for parameters such as the
- * number of iterations and the addresses of remote Bluetooth devices.
- */
-public class BluetoothStressTest extends InstrumentationTestCase {
- private static final String TAG = "BluetoothStressTest";
- private static final String OUTPUT_FILE = "BluetoothStressTestOutput.txt";
- /** The amount of time to sleep between issuing start/stop SCO in ms. */
- private static final long SCO_SLEEP_TIME = 2 * 1000;
-
- private BluetoothAdapter mAdapter;
- private BluetoothTestUtils mTestUtils;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- Context context = getInstrumentation().getTargetContext();
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- mTestUtils = new BluetoothTestUtils(context, TAG, OUTPUT_FILE);
-
- // Start all tests in a disabled state.
- if (mAdapter.isEnabled()) {
- mTestUtils.disable(mAdapter);
- }
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- mTestUtils.close();
- }
-
- /**
- * Stress test for enabling and disabling Bluetooth.
- */
- public void testEnable() {
- int iterations = BluetoothTestRunner.sEnableIterations;
- if (iterations == 0) {
- return;
- }
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("enable iteration " + (i + 1) + " of " + iterations);
- mTestUtils.enable(mAdapter);
- mTestUtils.disable(mAdapter);
- }
- }
-
- /**
- * Stress test for putting the device in and taking the device out of discoverable mode.
- */
- public void testDiscoverable() {
- int iterations = BluetoothTestRunner.sDiscoverableIterations;
- if (iterations == 0) {
- return;
- }
-
- mTestUtils.enable(mAdapter);
- mTestUtils.undiscoverable(mAdapter);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("discoverable iteration " + (i + 1) + " of " + iterations);
- mTestUtils.discoverable(mAdapter);
- mTestUtils.undiscoverable(mAdapter);
- }
- }
-
- /**
- * Stress test for starting and stopping Bluetooth scans.
- */
- public void testScan() {
- int iterations = BluetoothTestRunner.sScanIterations;
- if (iterations == 0) {
- return;
- }
-
- mTestUtils.enable(mAdapter);
- mTestUtils.stopScan(mAdapter);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("scan iteration " + (i + 1) + " of " + iterations);
- mTestUtils.startScan(mAdapter);
- mTestUtils.stopScan(mAdapter);
- }
- }
-
- /**
- * Stress test for enabling and disabling the PAN NAP profile.
- */
- public void testEnablePan() {
- int iterations = BluetoothTestRunner.sEnablePanIterations;
- if (iterations == 0) {
- return;
- }
-
- mTestUtils.enable(mAdapter);
- mTestUtils.disablePan(mAdapter);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
- + iterations);
- mTestUtils.enablePan(mAdapter);
- mTestUtils.disablePan(mAdapter);
- }
- }
-
- /**
- * Stress test for pairing and unpairing with a remote device.
- * <p>
- * In this test, the local device initiates pairing with a remote device, and then unpairs with
- * the device after the pairing has successfully completed.
- */
- public void testPair() {
- int iterations = BluetoothTestRunner.sPairIterations;
- if (iterations == 0) {
- return;
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.unpair(mAdapter, device);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("pair iteration " + (i + 1) + " of " + iterations);
- mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
- BluetoothTestRunner.sDevicePairPin);
- mTestUtils.unpair(mAdapter, device);
- }
- }
-
- /**
- * Stress test for accepting a pairing request and unpairing with a remote device.
- * <p>
- * In this test, the local device waits for a pairing request from a remote device. It accepts
- * the request and then unpairs after the paring has successfully completed.
- */
- public void testAcceptPair() {
- int iterations = BluetoothTestRunner.sPairIterations;
- if (iterations == 0) {
- return;
- }
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.unpair(mAdapter, device);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations);
- mTestUtils.acceptPair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
- BluetoothTestRunner.sDevicePairPin);
- mTestUtils.unpair(mAdapter, device);
- }
- }
-
- /**
- * Stress test for connecting and disconnecting with an A2DP source.
- * <p>
- * In this test, the local device plays the role of an A2DP sink, and initiates connections and
- * disconnections with an A2DP source.
- */
- public void testConnectA2dp() {
- int iterations = BluetoothTestRunner.sConnectA2dpIterations;
- if (iterations == 0) {
- return;
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.unpair(mAdapter, device);
- mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
- BluetoothTestRunner.sDevicePairPin);
- mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.A2DP, null);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("connectA2dp iteration " + (i + 1) + " of " + iterations);
- mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.A2DP,
- String.format("connectA2dp(device=%s)", device));
- mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.A2DP,
- String.format("disconnectA2dp(device=%s)", device));
- }
-
- mTestUtils.unpair(mAdapter, device);
- }
-
- /**
- * Stress test for connecting and disconnecting the HFP with a hands free device.
- * <p>
- * In this test, the local device plays the role of an HFP audio gateway, and initiates
- * connections and disconnections with a hands free device.
- */
- public void testConnectHeadset() {
- int iterations = BluetoothTestRunner.sConnectHeadsetIterations;
- if (iterations == 0) {
- return;
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.unpair(mAdapter, device);
- mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
- BluetoothTestRunner.sDevicePairPin);
- mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("connectHeadset iteration " + (i + 1) + " of " + iterations);
- mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HEADSET,
- String.format("connectHeadset(device=%s)", device));
- mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET,
- String.format("disconnectHeadset(device=%s)", device));
- }
-
- mTestUtils.unpair(mAdapter, device);
- }
-
- /**
- * Stress test for connecting and disconnecting with a HID device.
- * <p>
- * In this test, the local device plays the role of a HID host, and initiates connections and
- * disconnections with a HID device.
- */
- public void testConnectInput() {
- int iterations = BluetoothTestRunner.sConnectInputIterations;
- if (iterations == 0) {
- return;
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.unpair(mAdapter, device);
- mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
- BluetoothTestRunner.sDevicePairPin);
- mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HID_HOST, null);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
- mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HID_HOST,
- String.format("connectInput(device=%s)", device));
- mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HID_HOST,
- String.format("disconnectInput(device=%s)", device));
- }
-
- mTestUtils.unpair(mAdapter, device);
- }
-
- /**
- * Stress test for connecting and disconnecting with a PAN NAP.
- * <p>
- * In this test, the local device plays the role of a PANU, and initiates connections and
- * disconnections with a NAP.
- */
- public void testConnectPan() {
- int iterations = BluetoothTestRunner.sConnectPanIterations;
- if (iterations == 0) {
- return;
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.unpair(mAdapter, device);
- mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
- BluetoothTestRunner.sDevicePairPin);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
- mTestUtils.connectPan(mAdapter, device);
- mTestUtils.disconnectPan(mAdapter, device);
- }
-
- mTestUtils.unpair(mAdapter, device);
- }
-
- /**
- * Stress test for verifying a PANU connecting and disconnecting with the device.
- * <p>
- * In this test, the local device plays the role of a NAP which a remote PANU connects and
- * disconnects from.
- */
- public void testIncomingPanConnection() {
- int iterations = BluetoothTestRunner.sConnectPanIterations;
- if (iterations == 0) {
- return;
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.disablePan(mAdapter);
- mTestUtils.enablePan(mAdapter);
- mTestUtils.unpair(mAdapter, device);
- mTestUtils.acceptPair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
- BluetoothTestRunner.sDevicePairPin);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
- + iterations);
- mTestUtils.incomingPanConnection(mAdapter, device);
- mTestUtils.incomingPanDisconnection(mAdapter, device);
- }
-
- mTestUtils.unpair(mAdapter, device);
- mTestUtils.disablePan(mAdapter);
- }
-
- /**
- * Stress test for verifying that AudioManager can open and close SCO connections.
- * <p>
- * In this test, a HSP connection is opened with an external headset and the SCO connection is
- * repeatibly opened and closed.
- */
- public void testStartStopSco() {
- int iterations = BluetoothTestRunner.sStartStopScoIterations;
- if (iterations == 0) {
- return;
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.unpair(mAdapter, device);
- mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
- BluetoothTestRunner.sDevicePairPin);
- mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null);
- mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HEADSET, null);
- mTestUtils.stopSco(mAdapter, device);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations);
- mTestUtils.startSco(mAdapter, device);
- sleep(SCO_SLEEP_TIME);
- mTestUtils.stopSco(mAdapter, device);
- sleep(SCO_SLEEP_TIME);
- }
-
- mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null);
- mTestUtils.unpair(mAdapter, device);
- }
-
- /* Make sure there is at least 1 unread message in the last week on remote device */
- public void testMceSetMessageStatus() {
- int iterations = BluetoothTestRunner.sMceSetMessageStatusIterations;
- if (iterations == 0) {
- return;
- }
-
- BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
- mTestUtils.enable(mAdapter);
- mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.MAP_CLIENT, null);
- mTestUtils.mceGetUnreadMessage(mAdapter, device);
-
- for (int i = 0; i < iterations; i++) {
- mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.READ);
- mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.UNREAD);
- }
-
- /**
- * It is hard to find device to support set undeleted status, so just
- * set deleted in 1 iteration
- **/
- mTestUtils.mceSetMessageStatus(mAdapter, device, BluetoothMapClient.DELETED);
- }
-
- private void sleep(long time) {
- try {
- Thread.sleep(time);
- } catch (InterruptedException e) {
- }
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java
deleted file mode 100644
index d19c2c3..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestRunner.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import junit.framework.TestSuite;
-
-import android.os.Bundle;
-import android.test.InstrumentationTestRunner;
-import android.test.InstrumentationTestSuite;
-import android.util.Log;
-
-/**
- * Instrumentation test runner for Bluetooth tests.
- * <p>
- * To run:
- * <pre>
- * {@code
- * adb shell am instrument \
- * [-e enable_iterations <iterations>] \
- * [-e discoverable_iterations <iterations>] \
- * [-e scan_iterations <iterations>] \
- * [-e enable_pan_iterations <iterations>] \
- * [-e pair_iterations <iterations>] \
- * [-e connect_a2dp_iterations <iterations>] \
- * [-e connect_headset_iterations <iterations>] \
- * [-e connect_input_iterations <iterations>] \
- * [-e connect_pan_iterations <iterations>] \
- * [-e start_stop_sco_iterations <iterations>] \
- * [-e mce_set_message_status_iterations <iterations>] \
- * [-e pair_address <address>] \
- * [-e headset_address <address>] \
- * [-e a2dp_address <address>] \
- * [-e input_address <address>] \
- * [-e pan_address <address>] \
- * [-e pair_pin <pin>] \
- * [-e pair_passkey <passkey>] \
- * -w com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner
- * }
- * </pre>
- */
-public class BluetoothTestRunner extends InstrumentationTestRunner {
- private static final String TAG = "BluetoothTestRunner";
-
- public static int sEnableIterations = 100;
- public static int sDiscoverableIterations = 1000;
- public static int sScanIterations = 1000;
- public static int sEnablePanIterations = 1000;
- public static int sPairIterations = 100;
- public static int sConnectHeadsetIterations = 100;
- public static int sConnectA2dpIterations = 100;
- public static int sConnectInputIterations = 100;
- public static int sConnectPanIterations = 100;
- public static int sStartStopScoIterations = 100;
- public static int sMceSetMessageStatusIterations = 100;
-
- public static String sDeviceAddress = "";
- public static byte[] sDevicePairPin = {'1', '2', '3', '4'};
- public static int sDevicePairPasskey = 123456;
-
- @Override
- public TestSuite getAllTests() {
- TestSuite suite = new InstrumentationTestSuite(this);
- suite.addTestSuite(BluetoothStressTest.class);
- return suite;
- }
-
- @Override
- public ClassLoader getLoader() {
- return BluetoothTestRunner.class.getClassLoader();
- }
-
- @Override
- public void onCreate(Bundle arguments) {
- String val = arguments.getString("enable_iterations");
- if (val != null) {
- try {
- sEnableIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("discoverable_iterations");
- if (val != null) {
- try {
- sDiscoverableIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("scan_iterations");
- if (val != null) {
- try {
- sScanIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("enable_pan_iterations");
- if (val != null) {
- try {
- sEnablePanIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("pair_iterations");
- if (val != null) {
- try {
- sPairIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("connect_a2dp_iterations");
- if (val != null) {
- try {
- sConnectA2dpIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("connect_headset_iterations");
- if (val != null) {
- try {
- sConnectHeadsetIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("connect_input_iterations");
- if (val != null) {
- try {
- sConnectInputIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("connect_pan_iterations");
- if (val != null) {
- try {
- sConnectPanIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("start_stop_sco_iterations");
- if (val != null) {
- try {
- sStartStopScoIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("mce_set_message_status_iterations");
- if (val != null) {
- try {
- sMceSetMessageStatusIterations = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- val = arguments.getString("device_address");
- if (val != null) {
- sDeviceAddress = val;
- }
-
- val = arguments.getString("device_pair_pin");
- if (val != null) {
- byte[] pin = BluetoothDevice.convertPinToBytes(val);
- if (pin != null) {
- sDevicePairPin = pin;
- }
- }
-
- val = arguments.getString("device_pair_passkey");
- if (val != null) {
- try {
- sDevicePairPasskey = Integer.parseInt(val);
- } catch (NumberFormatException e) {
- // Invalid argument, fall back to default value
- }
- }
-
- Log.i(TAG, String.format("enable_iterations=%d", sEnableIterations));
- Log.i(TAG, String.format("discoverable_iterations=%d", sDiscoverableIterations));
- Log.i(TAG, String.format("scan_iterations=%d", sScanIterations));
- Log.i(TAG, String.format("pair_iterations=%d", sPairIterations));
- Log.i(TAG, String.format("connect_a2dp_iterations=%d", sConnectA2dpIterations));
- Log.i(TAG, String.format("connect_headset_iterations=%d", sConnectHeadsetIterations));
- Log.i(TAG, String.format("connect_input_iterations=%d", sConnectInputIterations));
- Log.i(TAG, String.format("connect_pan_iterations=%d", sConnectPanIterations));
- Log.i(TAG, String.format("start_stop_sco_iterations=%d", sStartStopScoIterations));
- Log.i(TAG, String.format("device_address=%s", sDeviceAddress));
- Log.i(TAG, String.format("device_pair_pin=%s", new String(sDevicePairPin)));
- Log.i(TAG, String.format("device_pair_passkey=%d", sDevicePairPasskey));
-
- // Call onCreate last since we want to set the static variables first.
- super.onCreate(arguments);
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
deleted file mode 100644
index 8eb6ebc..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ /dev/null
@@ -1,1651 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.bluetooth.BluetoothPan;
-import android.bluetooth.BluetoothProfile;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.media.AudioManager;
-import android.os.Environment;
-import android.util.Log;
-
-import junit.framework.Assert;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-public class BluetoothTestUtils extends Assert {
-
- /** Timeout for enable/disable in ms. */
- private static final int ENABLE_DISABLE_TIMEOUT = 20000;
- /** Timeout for discoverable/undiscoverable in ms. */
- private static final int DISCOVERABLE_UNDISCOVERABLE_TIMEOUT = 5000;
- /** Timeout for starting/stopping a scan in ms. */
- private static final int START_STOP_SCAN_TIMEOUT = 5000;
- /** Timeout for pair/unpair in ms. */
- private static final int PAIR_UNPAIR_TIMEOUT = 20000;
- /** Timeout for connecting/disconnecting a profile in ms. */
- private static final int CONNECT_DISCONNECT_PROFILE_TIMEOUT = 20000;
- /** Timeout to start or stop a SCO channel in ms. */
- private static final int START_STOP_SCO_TIMEOUT = 10000;
- /** Timeout to connect a profile proxy in ms. */
- private static final int CONNECT_PROXY_TIMEOUT = 5000;
- /** Time between polls in ms. */
- private static final int POLL_TIME = 100;
- /** Timeout to get map message in ms. */
- private static final int GET_UNREAD_MESSAGE_TIMEOUT = 10000;
- /** Timeout to set map message status in ms. */
- private static final int SET_MESSAGE_STATUS_TIMEOUT = 2000;
-
- private abstract class FlagReceiver extends BroadcastReceiver {
- private int mExpectedFlags = 0;
- private int mFiredFlags = 0;
- private long mCompletedTime = -1;
-
- public FlagReceiver(int expectedFlags) {
- mExpectedFlags = expectedFlags;
- }
-
- public int getFiredFlags() {
- synchronized (this) {
- return mFiredFlags;
- }
- }
-
- public long getCompletedTime() {
- synchronized (this) {
- return mCompletedTime;
- }
- }
-
- protected void setFiredFlag(int flag) {
- synchronized (this) {
- mFiredFlags |= flag;
- if ((mFiredFlags & mExpectedFlags) == mExpectedFlags) {
- mCompletedTime = System.currentTimeMillis();
- }
- }
- }
- }
-
- private class BluetoothReceiver extends FlagReceiver {
- private static final int DISCOVERY_STARTED_FLAG = 1;
- private static final int DISCOVERY_FINISHED_FLAG = 1 << 1;
- private static final int SCAN_MODE_NONE_FLAG = 1 << 2;
- private static final int SCAN_MODE_CONNECTABLE_FLAG = 1 << 3;
- private static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG = 1 << 4;
- private static final int STATE_OFF_FLAG = 1 << 5;
- private static final int STATE_TURNING_ON_FLAG = 1 << 6;
- private static final int STATE_ON_FLAG = 1 << 7;
- private static final int STATE_TURNING_OFF_FLAG = 1 << 8;
- private static final int STATE_GET_MESSAGE_FINISHED_FLAG = 1 << 9;
- private static final int STATE_SET_MESSAGE_STATUS_FINISHED_FLAG = 1 << 10;
-
- public BluetoothReceiver(int expectedFlags) {
- super(expectedFlags);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {
- setFiredFlag(DISCOVERY_STARTED_FLAG);
- } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {
- setFiredFlag(DISCOVERY_FINISHED_FLAG);
- } else if (BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(intent.getAction())) {
- int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, -1);
- assertNotSame(-1, mode);
- switch (mode) {
- case BluetoothAdapter.SCAN_MODE_NONE:
- setFiredFlag(SCAN_MODE_NONE_FLAG);
- break;
- case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
- setFiredFlag(SCAN_MODE_CONNECTABLE_FLAG);
- break;
- case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
- setFiredFlag(SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG);
- break;
- }
- } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
- int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
- assertNotSame(-1, state);
- switch (state) {
- case BluetoothAdapter.STATE_OFF:
- setFiredFlag(STATE_OFF_FLAG);
- break;
- case BluetoothAdapter.STATE_TURNING_ON:
- setFiredFlag(STATE_TURNING_ON_FLAG);
- break;
- case BluetoothAdapter.STATE_ON:
- setFiredFlag(STATE_ON_FLAG);
- break;
- case BluetoothAdapter.STATE_TURNING_OFF:
- setFiredFlag(STATE_TURNING_OFF_FLAG);
- break;
- }
- }
- }
- }
-
- private class PairReceiver extends FlagReceiver {
- private static final int STATE_BONDED_FLAG = 1;
- private static final int STATE_BONDING_FLAG = 1 << 1;
- private static final int STATE_NONE_FLAG = 1 << 2;
-
- private BluetoothDevice mDevice;
- private int mPasskey;
- private byte[] mPin;
-
- public PairReceiver(BluetoothDevice device, int passkey, byte[] pin, int expectedFlags) {
- super(expectedFlags);
-
- mDevice = device;
- mPasskey = passkey;
- mPin = pin;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
- return;
- }
-
- if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
- int varient = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, -1);
- assertNotSame(-1, varient);
- switch (varient) {
- case BluetoothDevice.PAIRING_VARIANT_PIN:
- case BluetoothDevice.PAIRING_VARIANT_PIN_16_DIGITS:
- mDevice.setPin(mPin);
- break;
- case BluetoothDevice.PAIRING_VARIANT_PASSKEY:
- break;
- case BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION:
- case BluetoothDevice.PAIRING_VARIANT_CONSENT:
- mDevice.setPairingConfirmation(true);
- break;
- case BluetoothDevice.PAIRING_VARIANT_OOB_CONSENT:
- break;
- }
- } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
- int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1);
- assertNotSame(-1, state);
- switch (state) {
- case BluetoothDevice.BOND_NONE:
- setFiredFlag(STATE_NONE_FLAG);
- break;
- case BluetoothDevice.BOND_BONDING:
- setFiredFlag(STATE_BONDING_FLAG);
- break;
- case BluetoothDevice.BOND_BONDED:
- setFiredFlag(STATE_BONDED_FLAG);
- break;
- }
- }
- }
- }
-
- private class ConnectProfileReceiver extends FlagReceiver {
- private static final int STATE_DISCONNECTED_FLAG = 1;
- private static final int STATE_CONNECTING_FLAG = 1 << 1;
- private static final int STATE_CONNECTED_FLAG = 1 << 2;
- private static final int STATE_DISCONNECTING_FLAG = 1 << 3;
-
- private BluetoothDevice mDevice;
- private int mProfile;
- private String mConnectionAction;
-
- public ConnectProfileReceiver(BluetoothDevice device, int profile, int expectedFlags) {
- super(expectedFlags);
-
- mDevice = device;
- mProfile = profile;
-
- switch (mProfile) {
- case BluetoothProfile.A2DP:
- mConnectionAction = BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED;
- break;
- case BluetoothProfile.HEADSET:
- mConnectionAction = BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED;
- break;
- case BluetoothProfile.HID_HOST:
- mConnectionAction = BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED;
- break;
- case BluetoothProfile.PAN:
- mConnectionAction = BluetoothPan.ACTION_CONNECTION_STATE_CHANGED;
- break;
- case BluetoothProfile.MAP_CLIENT:
- mConnectionAction = BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED;
- break;
- default:
- mConnectionAction = null;
- }
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mConnectionAction != null && mConnectionAction.equals(intent.getAction())) {
- if (!mDevice.equals(intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE))) {
- return;
- }
-
- int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
- assertNotSame(-1, state);
- switch (state) {
- case BluetoothProfile.STATE_DISCONNECTED:
- setFiredFlag(STATE_DISCONNECTED_FLAG);
- break;
- case BluetoothProfile.STATE_CONNECTING:
- setFiredFlag(STATE_CONNECTING_FLAG);
- break;
- case BluetoothProfile.STATE_CONNECTED:
- setFiredFlag(STATE_CONNECTED_FLAG);
- break;
- case BluetoothProfile.STATE_DISCONNECTING:
- setFiredFlag(STATE_DISCONNECTING_FLAG);
- break;
- }
- }
- }
- }
-
- private class ConnectPanReceiver extends ConnectProfileReceiver {
- private int mRole;
-
- public ConnectPanReceiver(BluetoothDevice device, int role, int expectedFlags) {
- super(device, BluetoothProfile.PAN, expectedFlags);
-
- mRole = role;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mRole != intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, -1)) {
- return;
- }
-
- super.onReceive(context, intent);
- }
- }
-
- private class StartStopScoReceiver extends FlagReceiver {
- private static final int STATE_CONNECTED_FLAG = 1;
- private static final int STATE_DISCONNECTED_FLAG = 1 << 1;
-
- public StartStopScoReceiver(int expectedFlags) {
- super(expectedFlags);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED.equals(intent.getAction())) {
- int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
- AudioManager.SCO_AUDIO_STATE_ERROR);
- assertNotSame(AudioManager.SCO_AUDIO_STATE_ERROR, state);
- switch(state) {
- case AudioManager.SCO_AUDIO_STATE_CONNECTED:
- setFiredFlag(STATE_CONNECTED_FLAG);
- break;
- case AudioManager.SCO_AUDIO_STATE_DISCONNECTED:
- setFiredFlag(STATE_DISCONNECTED_FLAG);
- break;
- }
- }
- }
- }
-
-
- private class MceSetMessageStatusReceiver extends FlagReceiver {
- private static final int MESSAGE_RECEIVED_FLAG = 1;
- private static final int STATUS_CHANGED_FLAG = 1 << 1;
-
- public MceSetMessageStatusReceiver(int expectedFlags) {
- super(expectedFlags);
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (BluetoothMapClient.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
- String handle = intent.getStringExtra(BluetoothMapClient.EXTRA_MESSAGE_HANDLE);
- assertNotNull(handle);
- setFiredFlag(MESSAGE_RECEIVED_FLAG);
- mMsgHandle = handle;
- } else if (BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED.equals(intent.getAction())) {
- int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE);
- assertEquals(result, BluetoothMapClient.RESULT_SUCCESS);
- setFiredFlag(STATUS_CHANGED_FLAG);
- } else if (BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED.equals(intent.getAction())) {
- int result = intent.getIntExtra(BluetoothMapClient.EXTRA_RESULT_CODE, BluetoothMapClient.RESULT_FAILURE);
- assertEquals(result, BluetoothMapClient.RESULT_SUCCESS);
- setFiredFlag(STATUS_CHANGED_FLAG);
- }
- }
- }
-
- private BluetoothProfile.ServiceListener mServiceListener =
- new BluetoothProfile.ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- synchronized (this) {
- switch (profile) {
- case BluetoothProfile.A2DP:
- mA2dp = (BluetoothA2dp) proxy;
- break;
- case BluetoothProfile.HEADSET:
- mHeadset = (BluetoothHeadset) proxy;
- break;
- case BluetoothProfile.HID_HOST:
- mInput = (BluetoothHidHost) proxy;
- break;
- case BluetoothProfile.PAN:
- mPan = (BluetoothPan) proxy;
- break;
- case BluetoothProfile.MAP_CLIENT:
- mMce = (BluetoothMapClient) proxy;
- break;
- }
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- synchronized (this) {
- switch (profile) {
- case BluetoothProfile.A2DP:
- mA2dp = null;
- break;
- case BluetoothProfile.HEADSET:
- mHeadset = null;
- break;
- case BluetoothProfile.HID_HOST:
- mInput = null;
- break;
- case BluetoothProfile.PAN:
- mPan = null;
- break;
- case BluetoothProfile.MAP_CLIENT:
- mMce = null;
- break;
- }
- }
- }
- };
-
- private List<BroadcastReceiver> mReceivers = new ArrayList<BroadcastReceiver>();
-
- private BufferedWriter mOutputWriter;
- private String mTag;
- private String mOutputFile;
-
- private Context mContext;
- private BluetoothA2dp mA2dp = null;
- private BluetoothHeadset mHeadset = null;
- private BluetoothHidHost mInput = null;
- private BluetoothPan mPan = null;
- private BluetoothMapClient mMce = null;
- private String mMsgHandle = null;
-
- /**
- * Creates a utility instance for testing Bluetooth.
- *
- * @param context The context of the application using the utility.
- * @param tag The log tag of the application using the utility.
- */
- public BluetoothTestUtils(Context context, String tag) {
- this(context, tag, null);
- }
-
- /**
- * Creates a utility instance for testing Bluetooth.
- *
- * @param context The context of the application using the utility.
- * @param tag The log tag of the application using the utility.
- * @param outputFile The path to an output file if the utility is to write results to a
- * separate file.
- */
- public BluetoothTestUtils(Context context, String tag, String outputFile) {
- mContext = context;
- mTag = tag;
- mOutputFile = outputFile;
-
- if (mOutputFile == null) {
- mOutputWriter = null;
- } else {
- try {
- mOutputWriter = new BufferedWriter(new FileWriter(new File(
- Environment.getExternalStorageDirectory(), mOutputFile), true));
- } catch (IOException e) {
- Log.w(mTag, "Test output file could not be opened", e);
- mOutputWriter = null;
- }
- }
- }
-
- /**
- * Closes the utility instance and unregisters any BroadcastReceivers.
- */
- public void close() {
- while (!mReceivers.isEmpty()) {
- mContext.unregisterReceiver(mReceivers.remove(0));
- }
-
- if (mOutputWriter != null) {
- try {
- mOutputWriter.close();
- } catch (IOException e) {
- Log.w(mTag, "Test output file could not be closed", e);
- }
- }
- }
-
- /**
- * Enables Bluetooth and checks to make sure that Bluetooth was turned on and that the correct
- * actions were broadcast.
- *
- * @param adapter The BT adapter.
- */
- public void enable(BluetoothAdapter adapter) {
- writeOutput("Enabling Bluetooth adapter.");
- assertFalse(adapter.isEnabled());
- int btState = adapter.getState();
- final Semaphore completionSemaphore = new Semaphore(0);
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
- return;
- }
- final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
- BluetoothAdapter.ERROR);
- if (state == BluetoothAdapter.STATE_ON) {
- completionSemaphore.release();
- }
- }
- };
-
- final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
- mContext.registerReceiver(receiver, filter);
- // Note: for Wear Local Edition builds, which have Permission Review Mode enabled to
- // obey China CMIIT, BluetoothAdapter may not startup immediately on methods enable/disable.
- // So no assertion applied here.
- adapter.enable();
- boolean success = false;
- try {
- success = completionSemaphore.tryAcquire(ENABLE_DISABLE_TIMEOUT, TimeUnit.MILLISECONDS);
- writeOutput(String.format("enable() completed in 0 ms"));
- } catch (final InterruptedException e) {
- // This should never happen but just in case it does, the test will fail anyway.
- }
- mContext.unregisterReceiver(receiver);
- if (!success) {
- fail(String.format("enable() timeout: state=%d (expected %d)", btState,
- BluetoothAdapter.STATE_ON));
- }
- }
-
- /**
- * Disables Bluetooth and checks to make sure that Bluetooth was turned off and that the correct
- * actions were broadcast.
- *
- * @param adapter The BT adapter.
- */
- public void disable(BluetoothAdapter adapter) {
- writeOutput("Disabling Bluetooth adapter.");
- assertTrue(adapter.isEnabled());
- int btState = adapter.getState();
- final Semaphore completionSemaphore = new Semaphore(0);
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (!BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
- return;
- }
- final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
- BluetoothAdapter.ERROR);
- if (state == BluetoothAdapter.STATE_OFF) {
- completionSemaphore.release();
- }
- }
- };
-
- final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
- mContext.registerReceiver(receiver, filter);
- // Note: for Wear Local Edition builds, which have Permission Review Mode enabled to
- // obey China CMIIT, BluetoothAdapter may not startup immediately on methods enable/disable.
- // So no assertion applied here.
- adapter.disable();
- boolean success = false;
- try {
- success = completionSemaphore.tryAcquire(ENABLE_DISABLE_TIMEOUT, TimeUnit.MILLISECONDS);
- writeOutput(String.format("disable() completed in 0 ms"));
- } catch (final InterruptedException e) {
- // This should never happen but just in case it does, the test will fail anyway.
- }
- mContext.unregisterReceiver(receiver);
- if (!success) {
- fail(String.format("disable() timeout: state=%d (expected %d)", btState,
- BluetoothAdapter.STATE_OFF));
- }
- }
-
- /**
- * Puts the local device into discoverable mode and checks to make sure that the local device
- * is in discoverable mode and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- */
- public void discoverable(BluetoothAdapter adapter) {
- if (!adapter.isEnabled()) {
- fail("discoverable() bluetooth not enabled");
- }
-
- int scanMode = adapter.getScanMode();
- if (scanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
- return;
- }
-
- final Semaphore completionSemaphore = new Semaphore(0);
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
- return;
- }
- final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
- BluetoothAdapter.SCAN_MODE_NONE);
- if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
- completionSemaphore.release();
- }
- }
- };
-
- final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
- mContext.registerReceiver(receiver, filter);
- assertEquals(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE),
- BluetoothStatusCodes.SUCCESS);
- boolean success = false;
- try {
- success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT,
- TimeUnit.MILLISECONDS);
- writeOutput(String.format("discoverable() completed in 0 ms"));
- } catch (final InterruptedException e) {
- // This should never happen but just in case it does, the test will fail anyway.
- }
- mContext.unregisterReceiver(receiver);
- if (!success) {
- fail(String.format("discoverable() timeout: scanMode=%d (expected %d)", scanMode,
- BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
- }
- }
-
- /**
- * Puts the local device into connectable only mode and checks to make sure that the local
- * device is in in connectable mode and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- */
- public void undiscoverable(BluetoothAdapter adapter) {
- if (!adapter.isEnabled()) {
- fail("undiscoverable() bluetooth not enabled");
- }
-
- int scanMode = adapter.getScanMode();
- if (scanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
- return;
- }
-
- final Semaphore completionSemaphore = new Semaphore(0);
- final BroadcastReceiver receiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
- return;
- }
- final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
- BluetoothAdapter.SCAN_MODE_NONE);
- if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
- completionSemaphore.release();
- }
- }
- };
-
- final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
- mContext.registerReceiver(receiver, filter);
- assertEquals(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE),
- BluetoothStatusCodes.SUCCESS);
- boolean success = false;
- try {
- success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT,
- TimeUnit.MILLISECONDS);
- writeOutput(String.format("undiscoverable() completed in 0 ms"));
- } catch (InterruptedException e) {
- // This should never happen but just in case it does, the test will fail anyway.
- }
- mContext.unregisterReceiver(receiver);
- if (!success) {
- fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d)", scanMode,
- BluetoothAdapter.SCAN_MODE_CONNECTABLE));
- }
- }
-
- /**
- * Starts a scan for remote devices and checks to make sure that the local device is scanning
- * and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- */
- public void startScan(BluetoothAdapter adapter) {
- int mask = BluetoothReceiver.DISCOVERY_STARTED_FLAG;
-
- if (!adapter.isEnabled()) {
- fail("startScan() bluetooth not enabled");
- }
-
- if (adapter.isDiscovering()) {
- return;
- }
-
- BluetoothReceiver receiver = getBluetoothReceiver(mask);
-
- long start = System.currentTimeMillis();
- assertTrue(adapter.startDiscovery());
-
- while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
- if (adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
- writeOutput(String.format("startScan() completed in %d ms",
- (receiver.getCompletedTime() - start)));
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("startScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
- adapter.isDiscovering(), firedFlags, mask));
- }
-
- /**
- * Stops a scan for remote devices and checks to make sure that the local device is not scanning
- * and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- */
- public void stopScan(BluetoothAdapter adapter) {
- int mask = BluetoothReceiver.DISCOVERY_FINISHED_FLAG;
-
- if (!adapter.isEnabled()) {
- fail("stopScan() bluetooth not enabled");
- }
-
- if (!adapter.isDiscovering()) {
- return;
- }
-
- BluetoothReceiver receiver = getBluetoothReceiver(mask);
-
- long start = System.currentTimeMillis();
- assertTrue(adapter.cancelDiscovery());
-
- while (System.currentTimeMillis() - start < START_STOP_SCAN_TIMEOUT) {
- if (!adapter.isDiscovering() && ((receiver.getFiredFlags() & mask) == mask)) {
- writeOutput(String.format("stopScan() completed in %d ms",
- (receiver.getCompletedTime() - start)));
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("stopScan() timeout: isDiscovering=%b, flags=0x%x (expected 0x%x)",
- adapter.isDiscovering(), firedFlags, mask));
-
- }
-
- /**
- * Enables PAN tethering on the local device and checks to make sure that tethering is enabled.
- *
- * @param adapter The BT adapter.
- */
- public void enablePan(BluetoothAdapter adapter) {
- if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
- assertNotNull(mPan);
-
- long start = System.currentTimeMillis();
- mPan.setBluetoothTethering(true);
- long stop = System.currentTimeMillis();
- assertTrue(mPan.isTetheringOn());
-
- writeOutput(String.format("enablePan() completed in %d ms", (stop - start)));
- }
-
- /**
- * Disables PAN tethering on the local device and checks to make sure that tethering is
- * disabled.
- *
- * @param adapter The BT adapter.
- */
- public void disablePan(BluetoothAdapter adapter) {
- if (mPan == null) mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
- assertNotNull(mPan);
-
- long start = System.currentTimeMillis();
- mPan.setBluetoothTethering(false);
- long stop = System.currentTimeMillis();
- assertFalse(mPan.isTetheringOn());
-
- writeOutput(String.format("disablePan() completed in %d ms", (stop - start)));
- }
-
- /**
- * Initiates a pairing with a remote device and checks to make sure that the devices are paired
- * and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
- * @param pin The pairing pin if pairing requires a pin. Any value if not.
- */
- public void pair(BluetoothAdapter adapter, BluetoothDevice device, int passkey, byte[] pin) {
- pairOrAcceptPair(adapter, device, passkey, pin, true);
- }
-
- /**
- * Accepts a pairing with a remote device and checks to make sure that the devices are paired
- * and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
- * @param pin The pairing pin if pairing requires a pin. Any value if not.
- */
- public void acceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
- byte[] pin) {
- pairOrAcceptPair(adapter, device, passkey, pin, false);
- }
-
- /**
- * Helper method used by {@link #pair(BluetoothAdapter, BluetoothDevice, int, byte[])} and
- * {@link #acceptPair(BluetoothAdapter, BluetoothDevice, int, byte[])} to either pair or accept
- * a pairing request.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- * @param passkey The pairing passkey if pairing requires a passkey. Any value if not.
- * @param pin The pairing pin if pairing requires a pin. Any value if not.
- * @param shouldPair Whether to pair or accept the pair.
- */
- private void pairOrAcceptPair(BluetoothAdapter adapter, BluetoothDevice device, int passkey,
- byte[] pin, boolean shouldPair) {
- int mask = PairReceiver.STATE_BONDING_FLAG | PairReceiver.STATE_BONDED_FLAG;
- long start = -1;
- String methodName;
- if (shouldPair) {
- methodName = String.format("pair(device=%s)", device);
- } else {
- methodName = String.format("acceptPair(device=%s)", device);
- }
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- PairReceiver receiver = getPairReceiver(device, passkey, pin, mask);
-
- int state = device.getBondState();
- switch (state) {
- case BluetoothDevice.BOND_NONE:
- assertFalse(adapter.getBondedDevices().contains(device));
- start = System.currentTimeMillis();
- if (shouldPair) {
- assertTrue(device.createBond());
- }
- break;
- case BluetoothDevice.BOND_BONDING:
- mask = 0; // Don't check for received intents since we might have missed them.
- break;
- case BluetoothDevice.BOND_BONDED:
- assertTrue(adapter.getBondedDevices().contains(device));
- return;
- default:
- removeReceiver(receiver);
- fail(String.format("%s invalid state: state=%d", methodName, state));
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
- state = device.getBondState();
- if (state == BluetoothDevice.BOND_BONDED && (receiver.getFiredFlags() & mask) == mask) {
- assertTrue(adapter.getBondedDevices().contains(device));
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms", methodName,
- (finish - start)));
- } else {
- writeOutput(String.format("%s completed", methodName));
- }
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
- methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
- }
-
- /**
- * Deletes a pairing with a remote device and checks to make sure that the devices are unpaired
- * and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void unpair(BluetoothAdapter adapter, BluetoothDevice device) {
- int mask = PairReceiver.STATE_NONE_FLAG;
- long start = -1;
- String methodName = String.format("unpair(device=%s)", device);
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- PairReceiver receiver = getPairReceiver(device, 0, null, mask);
-
- int state = device.getBondState();
- switch (state) {
- case BluetoothDevice.BOND_NONE:
- assertFalse(adapter.getBondedDevices().contains(device));
- removeReceiver(receiver);
- return;
- case BluetoothDevice.BOND_BONDING:
- start = System.currentTimeMillis();
- assertTrue(device.removeBond());
- break;
- case BluetoothDevice.BOND_BONDED:
- assertTrue(adapter.getBondedDevices().contains(device));
- start = System.currentTimeMillis();
- assertTrue(device.removeBond());
- break;
- default:
- removeReceiver(receiver);
- fail(String.format("%s invalid state: state=%d", methodName, state));
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < PAIR_UNPAIR_TIMEOUT) {
- if (device.getBondState() == BluetoothDevice.BOND_NONE
- && (receiver.getFiredFlags() & mask) == mask) {
- assertFalse(adapter.getBondedDevices().contains(device));
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms", methodName,
- (finish - start)));
- } else {
- writeOutput(String.format("%s completed", methodName));
- }
- removeReceiver(receiver);
- return;
- }
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
- methodName, state, BluetoothDevice.BOND_BONDED, firedFlags, mask));
- }
-
- /**
- * Deletes all pairings of remote devices
- * @param adapter the BT adapter
- */
- public void unpairAll(BluetoothAdapter adapter) {
- Set<BluetoothDevice> devices = adapter.getBondedDevices();
- for (BluetoothDevice device : devices) {
- unpair(adapter, device);
- }
- }
-
- /**
- * Connects a profile from the local device to a remote device and checks to make sure that the
- * profile is connected and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- * @param profile The profile to connect. One of {@link BluetoothProfile#A2DP},
- * {@link BluetoothProfile#HEADSET}, {@link BluetoothProfile#HID_HOST} or {@link BluetoothProfile#MAP_CLIENT}..
- * @param methodName The method name to printed in the logs. If null, will be
- * "connectProfile(profile=<profile>, device=<device>)"
- */
- public void connectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
- String methodName) {
- if (methodName == null) {
- methodName = String.format("connectProfile(profile=%d, device=%s)", profile, device);
- }
- int mask = (ConnectProfileReceiver.STATE_CONNECTING_FLAG
- | ConnectProfileReceiver.STATE_CONNECTED_FLAG);
- long start = -1;
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired", methodName));
- }
-
- BluetoothProfile proxy = connectProxy(adapter, profile);
- assertNotNull(proxy);
-
- ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
-
- int state = proxy.getConnectionState(device);
- switch (state) {
- case BluetoothProfile.STATE_CONNECTED:
- removeReceiver(receiver);
- return;
- case BluetoothProfile.STATE_CONNECTING:
- mask = 0; // Don't check for received intents since we might have missed them.
- break;
- case BluetoothProfile.STATE_DISCONNECTED:
- case BluetoothProfile.STATE_DISCONNECTING:
- start = System.currentTimeMillis();
- if (profile == BluetoothProfile.A2DP) {
- assertTrue(((BluetoothA2dp)proxy).connect(device));
- } else if (profile == BluetoothProfile.HEADSET) {
- assertTrue(((BluetoothHeadset)proxy).connect(device));
- } else if (profile == BluetoothProfile.HID_HOST) {
- assertTrue(((BluetoothHidHost)proxy).connect(device));
- } else if (profile == BluetoothProfile.MAP_CLIENT) {
- assertTrue(((BluetoothMapClient)proxy).connect(device));
- }
- break;
- default:
- removeReceiver(receiver);
- fail(String.format("%s invalid state: state=%d", methodName, state));
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
- state = proxy.getConnectionState(device);
- if (state == BluetoothProfile.STATE_CONNECTED
- && (receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms", methodName,
- (finish - start)));
- } else {
- writeOutput(String.format("%s completed", methodName));
- }
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
- methodName, state, BluetoothProfile.STATE_CONNECTED, firedFlags, mask));
- }
-
- /**
- * Disconnects a profile between the local device and a remote device and checks to make sure
- * that the profile is disconnected and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- * @param profile The profile to disconnect. One of {@link BluetoothProfile#A2DP},
- * {@link BluetoothProfile#HEADSET}, or {@link BluetoothProfile#HID_HOST}.
- * @param methodName The method name to printed in the logs. If null, will be
- * "connectProfile(profile=<profile>, device=<device>)"
- */
- public void disconnectProfile(BluetoothAdapter adapter, BluetoothDevice device, int profile,
- String methodName) {
- if (methodName == null) {
- methodName = String.format("disconnectProfile(profile=%d, device=%s)", profile, device);
- }
- int mask = (ConnectProfileReceiver.STATE_DISCONNECTING_FLAG
- | ConnectProfileReceiver.STATE_DISCONNECTED_FLAG);
- long start = -1;
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired", methodName));
- }
-
- BluetoothProfile proxy = connectProxy(adapter, profile);
- assertNotNull(proxy);
-
- ConnectProfileReceiver receiver = getConnectProfileReceiver(device, profile, mask);
-
- int state = proxy.getConnectionState(device);
- switch (state) {
- case BluetoothProfile.STATE_CONNECTED:
- case BluetoothProfile.STATE_CONNECTING:
- start = System.currentTimeMillis();
- if (profile == BluetoothProfile.A2DP) {
- assertTrue(((BluetoothA2dp)proxy).disconnect(device));
- } else if (profile == BluetoothProfile.HEADSET) {
- assertTrue(((BluetoothHeadset)proxy).disconnect(device));
- } else if (profile == BluetoothProfile.HID_HOST) {
- assertTrue(((BluetoothHidHost)proxy).disconnect(device));
- } else if (profile == BluetoothProfile.MAP_CLIENT) {
- assertTrue(((BluetoothMapClient)proxy).disconnect(device));
- }
- break;
- case BluetoothProfile.STATE_DISCONNECTED:
- removeReceiver(receiver);
- return;
- case BluetoothProfile.STATE_DISCONNECTING:
- mask = 0; // Don't check for received intents since we might have missed them.
- break;
- default:
- removeReceiver(receiver);
- fail(String.format("%s invalid state: state=%d", methodName, state));
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
- state = proxy.getConnectionState(device);
- if (state == BluetoothProfile.STATE_DISCONNECTED
- && (receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms", methodName,
- (finish - start)));
- } else {
- writeOutput(String.format("%s completed", methodName));
- }
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%x)",
- methodName, state, BluetoothProfile.STATE_DISCONNECTED, firedFlags, mask));
- }
-
- /**
- * Connects the PANU to a remote NAP and checks to make sure that the PANU is connected and that
- * the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void connectPan(BluetoothAdapter adapter, BluetoothDevice device) {
- connectPanOrIncomingPanConnection(adapter, device, true);
- }
-
- /**
- * Checks that a remote PANU connects to the local NAP correctly and that the correct actions
- * were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void incomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device) {
- connectPanOrIncomingPanConnection(adapter, device, false);
- }
-
- /**
- * Helper method used by {@link #connectPan(BluetoothAdapter, BluetoothDevice)} and
- * {@link #incomingPanConnection(BluetoothAdapter, BluetoothDevice)} to either connect to a
- * remote NAP or verify that a remote device connected to the local NAP.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- * @param connect If the method should initiate the connection (is PANU)
- */
- private void connectPanOrIncomingPanConnection(BluetoothAdapter adapter, BluetoothDevice device,
- boolean connect) {
- long start = -1;
- int mask, role;
- String methodName;
-
- if (connect) {
- methodName = String.format("connectPan(device=%s)", device);
- mask = (ConnectProfileReceiver.STATE_CONNECTED_FLAG |
- ConnectProfileReceiver.STATE_CONNECTING_FLAG);
- role = BluetoothPan.LOCAL_PANU_ROLE;
- } else {
- methodName = String.format("incomingPanConnection(device=%s)", device);
- mask = ConnectProfileReceiver.STATE_CONNECTED_FLAG;
- role = BluetoothPan.LOCAL_NAP_ROLE;
- }
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired", methodName));
- }
-
- mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
- assertNotNull(mPan);
- ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
-
- int state = mPan.getConnectionState(device);
- switch (state) {
- case BluetoothPan.STATE_CONNECTED:
- removeReceiver(receiver);
- return;
- case BluetoothPan.STATE_CONNECTING:
- mask = 0; // Don't check for received intents since we might have missed them.
- break;
- case BluetoothPan.STATE_DISCONNECTED:
- case BluetoothPan.STATE_DISCONNECTING:
- start = System.currentTimeMillis();
- if (role == BluetoothPan.LOCAL_PANU_ROLE) {
- Log.i("BT", "connect to pan");
- assertTrue(mPan.connect(device));
- }
- break;
- default:
- removeReceiver(receiver);
- fail(String.format("%s invalid state: state=%d", methodName, state));
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
- state = mPan.getConnectionState(device);
- if (state == BluetoothPan.STATE_CONNECTED
- && (receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms", methodName,
- (finish - start)));
- } else {
- writeOutput(String.format("%s completed", methodName));
- }
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
- methodName, state, BluetoothPan.STATE_CONNECTED, firedFlags, mask));
- }
-
- /**
- * Disconnects the PANU from a remote NAP and checks to make sure that the PANU is disconnected
- * and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void disconnectPan(BluetoothAdapter adapter, BluetoothDevice device) {
- disconnectFromRemoteOrVerifyConnectNap(adapter, device, true);
- }
-
- /**
- * Checks that a remote PANU disconnects from the local NAP correctly and that the correct
- * actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void incomingPanDisconnection(BluetoothAdapter adapter, BluetoothDevice device) {
- disconnectFromRemoteOrVerifyConnectNap(adapter, device, false);
- }
-
- /**
- * Helper method used by {@link #disconnectPan(BluetoothAdapter, BluetoothDevice)} and
- * {@link #incomingPanDisconnection(BluetoothAdapter, BluetoothDevice)} to either disconnect
- * from a remote NAP or verify that a remote device disconnected from the local NAP.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- * @param disconnect Whether the method should connect or verify.
- */
- private void disconnectFromRemoteOrVerifyConnectNap(BluetoothAdapter adapter,
- BluetoothDevice device, boolean disconnect) {
- long start = -1;
- int mask, role;
- String methodName;
-
- if (disconnect) {
- methodName = String.format("disconnectPan(device=%s)", device);
- mask = (ConnectProfileReceiver.STATE_DISCONNECTED_FLAG |
- ConnectProfileReceiver.STATE_DISCONNECTING_FLAG);
- role = BluetoothPan.LOCAL_PANU_ROLE;
- } else {
- methodName = String.format("incomingPanDisconnection(device=%s)", device);
- mask = ConnectProfileReceiver.STATE_DISCONNECTED_FLAG;
- role = BluetoothPan.LOCAL_NAP_ROLE;
- }
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired", methodName));
- }
-
- mPan = (BluetoothPan) connectProxy(adapter, BluetoothProfile.PAN);
- assertNotNull(mPan);
- ConnectPanReceiver receiver = getConnectPanReceiver(device, role, mask);
-
- int state = mPan.getConnectionState(device);
- switch (state) {
- case BluetoothPan.STATE_CONNECTED:
- case BluetoothPan.STATE_CONNECTING:
- start = System.currentTimeMillis();
- if (role == BluetoothPan.LOCAL_PANU_ROLE) {
- assertTrue(mPan.disconnect(device));
- }
- break;
- case BluetoothPan.STATE_DISCONNECTED:
- removeReceiver(receiver);
- return;
- case BluetoothPan.STATE_DISCONNECTING:
- mask = 0; // Don't check for received intents since we might have missed them.
- break;
- default:
- removeReceiver(receiver);
- fail(String.format("%s invalid state: state=%d", methodName, state));
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < CONNECT_DISCONNECT_PROFILE_TIMEOUT) {
- state = mPan.getConnectionState(device);
- if (state == BluetoothHidHost.STATE_DISCONNECTED
- && (receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms", methodName,
- (finish - start)));
- } else {
- writeOutput(String.format("%s completed", methodName));
- }
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
- methodName, state, BluetoothHidHost.STATE_DISCONNECTED, firedFlags, mask));
- }
-
- /**
- * Opens a SCO channel using {@link android.media.AudioManager#startBluetoothSco()} and checks
- * to make sure that the channel is opened and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void startSco(BluetoothAdapter adapter, BluetoothDevice device) {
- startStopSco(adapter, device, true);
- }
-
- /**
- * Closes a SCO channel using {@link android.media.AudioManager#stopBluetoothSco()} and checks
- * to make sure that the channel is closed and that the correct actions were broadcast.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- */
- public void stopSco(BluetoothAdapter adapter, BluetoothDevice device) {
- startStopSco(adapter, device, false);
- }
- /**
- * Helper method for {@link #startSco(BluetoothAdapter, BluetoothDevice)} and
- * {@link #stopSco(BluetoothAdapter, BluetoothDevice)}.
- *
- * @param adapter The BT adapter.
- * @param device The remote device.
- * @param isStart Whether the SCO channel should be opened.
- */
- private void startStopSco(BluetoothAdapter adapter, BluetoothDevice device, boolean isStart) {
- long start = -1;
- int mask;
- String methodName;
-
- if (isStart) {
- methodName = String.format("startSco(device=%s)", device);
- mask = StartStopScoReceiver.STATE_CONNECTED_FLAG;
- } else {
- methodName = String.format("stopSco(device=%s)", device);
- mask = StartStopScoReceiver.STATE_DISCONNECTED_FLAG;
- }
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired", methodName));
- }
-
- AudioManager manager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- assertNotNull(manager);
-
- if (!manager.isBluetoothScoAvailableOffCall()) {
- fail(String.format("%s device does not support SCO", methodName));
- }
-
- boolean isScoOn = manager.isBluetoothScoOn();
- if (isStart == isScoOn) {
- return;
- }
-
- StartStopScoReceiver receiver = getStartStopScoReceiver(mask);
- start = System.currentTimeMillis();
- if (isStart) {
- manager.startBluetoothSco();
- } else {
- manager.stopBluetoothSco();
- }
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < START_STOP_SCO_TIMEOUT) {
- isScoOn = manager.isBluetoothScoOn();
- if (isStart == isScoOn && (receiver.getFiredFlags() & mask) == mask) {
- long finish = receiver.getCompletedTime();
- if (start != -1 && finish != -1) {
- writeOutput(String.format("%s completed in %d ms", methodName,
- (finish - start)));
- } else {
- writeOutput(String.format("%s completed", methodName));
- }
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: on=%b (expected %b), flags=0x%x (expected 0x%x)",
- methodName, isScoOn, isStart, firedFlags, mask));
- }
-
- /**
- * Writes a string to the logcat and a file if a file has been specified in the constructor.
- *
- * @param s The string to be written.
- */
- public void writeOutput(String s) {
- Log.i(mTag, s);
- if (mOutputWriter == null) {
- return;
- }
- try {
- mOutputWriter.write(s + "\n");
- mOutputWriter.flush();
- } catch (IOException e) {
- Log.w(mTag, "Could not write to output file", e);
- }
- }
-
- public void mceGetUnreadMessage(BluetoothAdapter adapter, BluetoothDevice device) {
- int mask;
- String methodName = "getUnreadMessage";
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired", methodName));
- }
-
- mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT);
- assertNotNull(mMce);
-
- if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
- fail(String.format("%s device is not connected", methodName));
- }
-
- mMsgHandle = null;
- mask = MceSetMessageStatusReceiver.MESSAGE_RECEIVED_FLAG;
- MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask);
- assertTrue(mMce.getUnreadMessages(device));
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < GET_UNREAD_MESSAGE_TIMEOUT) {
- if ((receiver.getFiredFlags() & mask) == mask) {
- writeOutput(String.format("%s completed", methodName));
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
- methodName, mMce.getConnectionState(device), BluetoothMapClient.STATE_CONNECTED, firedFlags, mask));
- }
-
- /**
- * Set a message to read/unread/deleted/undeleted
- */
- public void mceSetMessageStatus(BluetoothAdapter adapter, BluetoothDevice device, int status) {
- int mask;
- String methodName = "setMessageStatus";
-
- if (!adapter.isEnabled()) {
- fail(String.format("%s bluetooth not enabled", methodName));
- }
-
- if (!adapter.getBondedDevices().contains(device)) {
- fail(String.format("%s device not paired", methodName));
- }
-
- mMce = (BluetoothMapClient) connectProxy(adapter, BluetoothProfile.MAP_CLIENT);
- assertNotNull(mMce);
-
- if (mMce.getConnectionState(device) != BluetoothProfile.STATE_CONNECTED) {
- fail(String.format("%s device is not connected", methodName));
- }
-
- assertNotNull(mMsgHandle);
- mask = MceSetMessageStatusReceiver.STATUS_CHANGED_FLAG;
- MceSetMessageStatusReceiver receiver = getMceSetMessageStatusReceiver(device, mask);
-
- assertTrue(mMce.setMessageStatus(device, mMsgHandle, status));
-
- long s = System.currentTimeMillis();
- while (System.currentTimeMillis() - s < SET_MESSAGE_STATUS_TIMEOUT) {
- if ((receiver.getFiredFlags() & mask) == mask) {
- writeOutput(String.format("%s completed", methodName));
- removeReceiver(receiver);
- return;
- }
- sleep(POLL_TIME);
- }
-
- int firedFlags = receiver.getFiredFlags();
- removeReceiver(receiver);
- fail(String.format("%s timeout: state=%d (expected %d), flags=0x%x (expected 0x%s)",
- methodName, mMce.getConnectionState(device), BluetoothPan.STATE_CONNECTED, firedFlags, mask));
- }
-
- private void addReceiver(BroadcastReceiver receiver, String[] actions) {
- IntentFilter filter = new IntentFilter();
- for (String action: actions) {
- filter.addAction(action);
- }
- mContext.registerReceiver(receiver, filter);
- mReceivers.add(receiver);
- }
-
- private BluetoothReceiver getBluetoothReceiver(int expectedFlags) {
- String[] actions = {
- BluetoothAdapter.ACTION_DISCOVERY_FINISHED,
- BluetoothAdapter.ACTION_DISCOVERY_STARTED,
- BluetoothAdapter.ACTION_SCAN_MODE_CHANGED,
- BluetoothAdapter.ACTION_STATE_CHANGED};
- BluetoothReceiver receiver = new BluetoothReceiver(expectedFlags);
- addReceiver(receiver, actions);
- return receiver;
- }
-
- private PairReceiver getPairReceiver(BluetoothDevice device, int passkey, byte[] pin,
- int expectedFlags) {
- String[] actions = {
- BluetoothDevice.ACTION_PAIRING_REQUEST,
- BluetoothDevice.ACTION_BOND_STATE_CHANGED};
- PairReceiver receiver = new PairReceiver(device, passkey, pin, expectedFlags);
- addReceiver(receiver, actions);
- return receiver;
- }
-
- private ConnectProfileReceiver getConnectProfileReceiver(BluetoothDevice device, int profile,
- int expectedFlags) {
- String[] actions = {
- BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED,
- BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
- BluetoothHidHost.ACTION_CONNECTION_STATE_CHANGED,
- BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED};
- ConnectProfileReceiver receiver = new ConnectProfileReceiver(device, profile,
- expectedFlags);
- addReceiver(receiver, actions);
- return receiver;
- }
-
- private ConnectPanReceiver getConnectPanReceiver(BluetoothDevice device, int role,
- int expectedFlags) {
- String[] actions = {BluetoothPan.ACTION_CONNECTION_STATE_CHANGED};
- ConnectPanReceiver receiver = new ConnectPanReceiver(device, role, expectedFlags);
- addReceiver(receiver, actions);
- return receiver;
- }
-
- private StartStopScoReceiver getStartStopScoReceiver(int expectedFlags) {
- String[] actions = {AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED};
- StartStopScoReceiver receiver = new StartStopScoReceiver(expectedFlags);
- addReceiver(receiver, actions);
- return receiver;
- }
-
- private MceSetMessageStatusReceiver getMceSetMessageStatusReceiver(BluetoothDevice device,
- int expectedFlags) {
- String[] actions = {BluetoothMapClient.ACTION_MESSAGE_RECEIVED,
- BluetoothMapClient.ACTION_MESSAGE_READ_STATUS_CHANGED,
- BluetoothMapClient.ACTION_MESSAGE_DELETED_STATUS_CHANGED};
- MceSetMessageStatusReceiver receiver = new MceSetMessageStatusReceiver(expectedFlags);
- addReceiver(receiver, actions);
- return receiver;
- }
-
- private void removeReceiver(BroadcastReceiver receiver) {
- mContext.unregisterReceiver(receiver);
- mReceivers.remove(receiver);
- }
-
- private BluetoothProfile connectProxy(BluetoothAdapter adapter, int profile) {
- switch (profile) {
- case BluetoothProfile.A2DP:
- if (mA2dp != null) {
- return mA2dp;
- }
- break;
- case BluetoothProfile.HEADSET:
- if (mHeadset != null) {
- return mHeadset;
- }
- break;
- case BluetoothProfile.HID_HOST:
- if (mInput != null) {
- return mInput;
- }
- break;
- case BluetoothProfile.PAN:
- if (mPan != null) {
- return mPan;
- }
- case BluetoothProfile.MAP_CLIENT:
- if (mMce != null) {
- return mMce;
- }
- break;
- default:
- return null;
- }
- adapter.getProfileProxy(mContext, mServiceListener, profile);
- long s = System.currentTimeMillis();
- switch (profile) {
- case BluetoothProfile.A2DP:
- while (mA2dp == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
- sleep(POLL_TIME);
- }
- return mA2dp;
- case BluetoothProfile.HEADSET:
- while (mHeadset == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
- sleep(POLL_TIME);
- }
- return mHeadset;
- case BluetoothProfile.HID_HOST:
- while (mInput == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
- sleep(POLL_TIME);
- }
- return mInput;
- case BluetoothProfile.PAN:
- while (mPan == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
- sleep(POLL_TIME);
- }
- return mPan;
- case BluetoothProfile.MAP_CLIENT:
- while (mMce == null && System.currentTimeMillis() - s < CONNECT_PROXY_TIMEOUT) {
- sleep(POLL_TIME);
- }
- return mMce;
- default:
- return null;
- }
- }
-
- private void sleep(long time) {
- try {
- Thread.sleep(time);
- } catch (InterruptedException e) {
- }
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
deleted file mode 100644
index 536d722..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothUuidTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.os.ParcelUuid;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * Unit test cases for {@link BluetoothUuid}.
- * <p>
- * To run this test, use adb shell am instrument -e class 'android.bluetooth.BluetoothUuidTest' -w
- * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
- */
-public class BluetoothUuidTest extends TestCase {
-
- @SmallTest
- public void testUuidParser() {
- byte[] uuid16 = new byte[] {
- 0x0B, 0x11 };
- assertEquals(ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB"),
- BluetoothUuid.parseUuidFrom(uuid16));
-
- byte[] uuid32 = new byte[] {
- 0x0B, 0x11, 0x33, (byte) 0xFE };
- assertEquals(ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB"),
- BluetoothUuid.parseUuidFrom(uuid32));
-
- byte[] uuid128 = new byte[] {
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, (byte) 0xFF };
- assertEquals(ParcelUuid.fromString("FF0F0E0D-0C0B-0A09-0807-0060504030201"),
- BluetoothUuid.parseUuidFrom(uuid128));
- }
-
- @SmallTest
- public void testUuidType() {
- assertTrue(BluetoothUuid.is16BitUuid(
- ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB")));
- assertFalse(BluetoothUuid.is32BitUuid(
- ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB")));
-
- assertFalse(BluetoothUuid.is16BitUuid(
- ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB")));
- assertTrue(BluetoothUuid.is32BitUuid(
- ParcelUuid.fromString("FE33110B-0000-1000-8000-00805F9B34FB")));
- assertFalse(BluetoothUuid.is32BitUuid(
- ParcelUuid.fromString("FE33110B-1000-1000-8000-00805F9B34FB")));
-
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
deleted file mode 100644
index e58d905..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/AdvertiseDataTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * Unit test cases for {@link AdvertiseData}.
- * <p>
- * To run the test, use adb shell am instrument -e class 'android.bluetooth.le.AdvertiseDataTest' -w
- * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
- */
-public class AdvertiseDataTest extends TestCase {
-
- private AdvertiseData.Builder mAdvertiseDataBuilder;
-
- @Override
- protected void setUp() throws Exception {
- mAdvertiseDataBuilder = new AdvertiseData.Builder();
- }
-
- @SmallTest
- public void testEmptyData() {
- Parcel parcel = Parcel.obtain();
- AdvertiseData data = mAdvertiseDataBuilder.build();
- data.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- AdvertiseData dataFromParcel =
- AdvertiseData.CREATOR.createFromParcel(parcel);
- assertEquals(data, dataFromParcel);
- }
-
- @SmallTest
- public void testEmptyServiceUuid() {
- Parcel parcel = Parcel.obtain();
- AdvertiseData data = mAdvertiseDataBuilder.setIncludeDeviceName(true).build();
- data.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- AdvertiseData dataFromParcel =
- AdvertiseData.CREATOR.createFromParcel(parcel);
- assertEquals(data, dataFromParcel);
- }
-
- @SmallTest
- public void testEmptyManufacturerData() {
- Parcel parcel = Parcel.obtain();
- int manufacturerId = 50;
- byte[] manufacturerData = new byte[0];
- AdvertiseData data =
- mAdvertiseDataBuilder.setIncludeDeviceName(true)
- .addManufacturerData(manufacturerId, manufacturerData).build();
- data.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- AdvertiseData dataFromParcel =
- AdvertiseData.CREATOR.createFromParcel(parcel);
- assertEquals(data, dataFromParcel);
- }
-
- @SmallTest
- public void testEmptyServiceData() {
- Parcel parcel = Parcel.obtain();
- ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- byte[] serviceData = new byte[0];
- AdvertiseData data =
- mAdvertiseDataBuilder.setIncludeDeviceName(true)
- .addServiceData(uuid, serviceData).build();
- data.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- AdvertiseData dataFromParcel =
- AdvertiseData.CREATOR.createFromParcel(parcel);
- assertEquals(data, dataFromParcel);
- }
-
- @SmallTest
- public void testServiceUuid() {
- Parcel parcel = Parcel.obtain();
- ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
-
- AdvertiseData data =
- mAdvertiseDataBuilder.setIncludeDeviceName(true)
- .addServiceUuid(uuid).addServiceUuid(uuid2).build();
- data.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- AdvertiseData dataFromParcel =
- AdvertiseData.CREATOR.createFromParcel(parcel);
- assertEquals(data, dataFromParcel);
- }
-
- @SmallTest
- public void testManufacturerData() {
- Parcel parcel = Parcel.obtain();
- ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
-
- int manufacturerId = 50;
- byte[] manufacturerData = new byte[] {
- (byte) 0xF0, 0x00, 0x02, 0x15 };
- AdvertiseData data =
- mAdvertiseDataBuilder.setIncludeDeviceName(true)
- .addServiceUuid(uuid).addServiceUuid(uuid2)
- .addManufacturerData(manufacturerId, manufacturerData).build();
-
- data.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- AdvertiseData dataFromParcel =
- AdvertiseData.CREATOR.createFromParcel(parcel);
- assertEquals(data, dataFromParcel);
- }
-
- @SmallTest
- public void testServiceData() {
- Parcel parcel = Parcel.obtain();
- ParcelUuid uuid = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- byte[] serviceData = new byte[] {
- (byte) 0xF0, 0x00, 0x02, 0x15 };
- AdvertiseData data =
- mAdvertiseDataBuilder.setIncludeDeviceName(true)
- .addServiceData(uuid, serviceData).build();
- data.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- AdvertiseData dataFromParcel =
- AdvertiseData.CREATOR.createFromParcel(parcel);
- assertEquals(data, dataFromParcel);
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java
deleted file mode 100644
index 35da4bc..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanFilterTest.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.le.ScanFilter;
-import android.bluetooth.le.ScanRecord;
-import android.os.Parcel;
-import android.os.ParcelUuid;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * Unit test cases for Bluetooth LE scan filters.
- * <p>
- * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanFilterTest' -w
- * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
- */
-public class ScanFilterTest extends TestCase {
-
- private static final String DEVICE_MAC = "01:02:03:04:05:AB";
- private ScanResult mScanResult;
- private ScanFilter.Builder mFilterBuilder;
-
- @Override
- protected void setUp() throws Exception {
- byte[] scanRecord = new byte[] {
- 0x02, 0x01, 0x1a, // advertising flags
- 0x05, 0x02, 0x0b, 0x11, 0x0a, 0x11, // 16 bit service uuids
- 0x04, 0x09, 0x50, 0x65, 0x64, // setName
- 0x02, 0x0A, (byte) 0xec, // tx power level
- 0x05, 0x16, 0x0b, 0x11, 0x50, 0x64, // service data
- 0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data
- 0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble
- };
-
- BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
- BluetoothDevice device = adapter.getRemoteDevice(DEVICE_MAC);
- mScanResult = new ScanResult(device, ScanRecord.parseFromBytes(scanRecord),
- -10, 1397545200000000L);
- mFilterBuilder = new ScanFilter.Builder();
- }
-
- @SmallTest
- public void testsetNameFilter() {
- ScanFilter filter = mFilterBuilder.setDeviceName("Ped").build();
- assertTrue("setName filter fails", filter.matches(mScanResult));
-
- filter = mFilterBuilder.setDeviceName("Pem").build();
- assertFalse("setName filter fails", filter.matches(mScanResult));
-
- }
-
- @SmallTest
- public void testDeviceFilter() {
- ScanFilter filter = mFilterBuilder.setDeviceAddress(DEVICE_MAC).build();
- assertTrue("device filter fails", filter.matches(mScanResult));
-
- filter = mFilterBuilder.setDeviceAddress("11:22:33:44:55:66").build();
- assertFalse("device filter fails", filter.matches(mScanResult));
- }
-
- @SmallTest
- public void testsetServiceUuidFilter() {
- ScanFilter filter = mFilterBuilder.setServiceUuid(
- ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB")).build();
- assertTrue("uuid filter fails", filter.matches(mScanResult));
-
- filter = mFilterBuilder.setServiceUuid(
- ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB")).build();
- assertFalse("uuid filter fails", filter.matches(mScanResult));
-
- filter = mFilterBuilder
- .setServiceUuid(ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"),
- ParcelUuid.fromString("FFFFFFF0-FFFF-FFFF-FFFF-FFFFFFFFFFFF"))
- .build();
- assertTrue("uuid filter fails", filter.matches(mScanResult));
- }
-
- @SmallTest
- public void testsetServiceDataFilter() {
- byte[] setServiceData = new byte[] {
- 0x50, 0x64 };
- ParcelUuid serviceDataUuid = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
- ScanFilter filter = mFilterBuilder.setServiceData(serviceDataUuid, setServiceData).build();
- assertTrue("service data filter fails", filter.matches(mScanResult));
-
- byte[] emptyData = new byte[0];
- filter = mFilterBuilder.setServiceData(serviceDataUuid, emptyData).build();
- assertTrue("service data filter fails", filter.matches(mScanResult));
-
- byte[] prefixData = new byte[] {
- 0x50 };
- filter = mFilterBuilder.setServiceData(serviceDataUuid, prefixData).build();
- assertTrue("service data filter fails", filter.matches(mScanResult));
-
- byte[] nonMatchData = new byte[] {
- 0x51, 0x64 };
- byte[] mask = new byte[] {
- (byte) 0x00, (byte) 0xFF };
- filter = mFilterBuilder.setServiceData(serviceDataUuid, nonMatchData, mask).build();
- assertTrue("partial service data filter fails", filter.matches(mScanResult));
-
- filter = mFilterBuilder.setServiceData(serviceDataUuid, nonMatchData).build();
- assertFalse("service data filter fails", filter.matches(mScanResult));
- }
-
- @SmallTest
- public void testManufacturerSpecificData() {
- byte[] setManufacturerData = new byte[] {
- 0x02, 0x15 };
- int manufacturerId = 0xE0;
- ScanFilter filter =
- mFilterBuilder.setManufacturerData(manufacturerId, setManufacturerData).build();
- assertTrue("manufacturer data filter fails", filter.matches(mScanResult));
-
- byte[] emptyData = new byte[0];
- filter = mFilterBuilder.setManufacturerData(manufacturerId, emptyData).build();
- assertTrue("manufacturer data filter fails", filter.matches(mScanResult));
-
- byte[] prefixData = new byte[] {
- 0x02 };
- filter = mFilterBuilder.setManufacturerData(manufacturerId, prefixData).build();
- assertTrue("manufacturer data filter fails", filter.matches(mScanResult));
-
- // Test data mask
- byte[] nonMatchData = new byte[] {
- 0x02, 0x14 };
- filter = mFilterBuilder.setManufacturerData(manufacturerId, nonMatchData).build();
- assertFalse("manufacturer data filter fails", filter.matches(mScanResult));
- byte[] mask = new byte[] {
- (byte) 0xFF, (byte) 0x00
- };
- filter = mFilterBuilder.setManufacturerData(manufacturerId, nonMatchData, mask).build();
- assertTrue("partial setManufacturerData filter fails", filter.matches(mScanResult));
- }
-
- @SmallTest
- public void testReadWriteParcel() {
- ScanFilter filter = mFilterBuilder.build();
- testReadWriteParcelForFilter(filter);
-
- filter = mFilterBuilder.setDeviceName("Ped").build();
- testReadWriteParcelForFilter(filter);
-
- filter = mFilterBuilder.setDeviceAddress("11:22:33:44:55:66").build();
- testReadWriteParcelForFilter(filter);
-
- filter = mFilterBuilder.setServiceUuid(
- ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB")).build();
- testReadWriteParcelForFilter(filter);
-
- filter = mFilterBuilder.setServiceUuid(
- ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB"),
- ParcelUuid.fromString("FFFFFFF0-FFFF-FFFF-FFFF-FFFFFFFFFFFF")).build();
- testReadWriteParcelForFilter(filter);
-
- byte[] serviceData = new byte[] {
- 0x50, 0x64 };
-
- ParcelUuid serviceDataUuid = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
- filter = mFilterBuilder.setServiceData(serviceDataUuid, serviceData).build();
- testReadWriteParcelForFilter(filter);
-
- filter = mFilterBuilder.setServiceData(serviceDataUuid, new byte[0]).build();
- testReadWriteParcelForFilter(filter);
-
- byte[] serviceDataMask = new byte[] {
- (byte) 0xFF, (byte) 0xFF };
- filter = mFilterBuilder.setServiceData(serviceDataUuid, serviceData, serviceDataMask)
- .build();
- testReadWriteParcelForFilter(filter);
-
- byte[] manufacturerData = new byte[] {
- 0x02, 0x15 };
- int manufacturerId = 0xE0;
- filter = mFilterBuilder.setManufacturerData(manufacturerId, manufacturerData).build();
- testReadWriteParcelForFilter(filter);
-
- filter = mFilterBuilder.setServiceData(serviceDataUuid, new byte[0]).build();
- testReadWriteParcelForFilter(filter);
-
- byte[] manufacturerDataMask = new byte[] {
- (byte) 0xFF, (byte) 0xFF
- };
- filter = mFilterBuilder.setManufacturerData(manufacturerId, manufacturerData,
- manufacturerDataMask).build();
- testReadWriteParcelForFilter(filter);
- }
-
- private void testReadWriteParcelForFilter(ScanFilter filter) {
- Parcel parcel = Parcel.obtain();
- filter.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- ScanFilter filterFromParcel =
- ScanFilter.CREATOR.createFromParcel(parcel);
- assertEquals(filter, filterFromParcel);
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
deleted file mode 100644
index 4e817d4..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanRecordTest.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.os.ParcelUuid;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.internal.util.HexDump;
-import com.android.modules.utils.BytesMatcher;
-
-import junit.framework.TestCase;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Predicate;
-
-/**
- * Unit test cases for {@link ScanRecord}.
- * <p>
- * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanRecordTest' -w
- * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
- */
-public class ScanRecordTest extends TestCase {
- /**
- * Example raw beacons captured from a Blue Charm BC011
- */
- private static final String RECORD_URL = "0201060303AAFE1716AAFE10EE01626C7565636861726D626561636F6E730009168020691E0EFE13551109426C7565436861726D5F313639363835000000";
- private static final String RECORD_UUID = "0201060303AAFE1716AAFE00EE626C7565636861726D31000000000001000009168020691E0EFE13551109426C7565436861726D5F313639363835000000";
- private static final String RECORD_TLM = "0201060303AAFE1116AAFE20000BF017000008874803FB93540916802069080EFE13551109426C7565436861726D5F313639363835000000000000000000";
- private static final String RECORD_IBEACON = "0201061AFF4C000215426C7565436861726D426561636F6E730EFE1355C509168020691E0EFE13551109426C7565436861726D5F31363936383500000000";
-
- @SmallTest
- public void testMatchesAnyField_Eddystone_Parser() {
- final List<String> found = new ArrayList<>();
- final Predicate<byte[]> matcher = (v) -> {
- found.add(HexDump.toHexString(v));
- return false;
- };
- ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_URL))
- .matchesAnyField(matcher);
-
- assertEquals(Arrays.asList(
- "020106",
- "0303AAFE",
- "1716AAFE10EE01626C7565636861726D626561636F6E7300",
- "09168020691E0EFE1355",
- "1109426C7565436861726D5F313639363835"), found);
- }
-
- @SmallTest
- public void testMatchesAnyField_Eddystone() {
- final BytesMatcher matcher = BytesMatcher.decode("⊆0016AAFE/00FFFFFF");
- assertMatchesAnyField(RECORD_URL, matcher);
- assertMatchesAnyField(RECORD_UUID, matcher);
- assertMatchesAnyField(RECORD_TLM, matcher);
- assertNotMatchesAnyField(RECORD_IBEACON, matcher);
- }
-
- @SmallTest
- public void testMatchesAnyField_iBeacon_Parser() {
- final List<String> found = new ArrayList<>();
- final Predicate<byte[]> matcher = (v) -> {
- found.add(HexDump.toHexString(v));
- return false;
- };
- ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(RECORD_IBEACON))
- .matchesAnyField(matcher);
-
- assertEquals(Arrays.asList(
- "020106",
- "1AFF4C000215426C7565436861726D426561636F6E730EFE1355C5",
- "09168020691E0EFE1355",
- "1109426C7565436861726D5F313639363835"), found);
- }
-
- @SmallTest
- public void testMatchesAnyField_iBeacon() {
- final BytesMatcher matcher = BytesMatcher.decode("⊆00FF4C0002/00FFFFFFFF");
- assertNotMatchesAnyField(RECORD_URL, matcher);
- assertNotMatchesAnyField(RECORD_UUID, matcher);
- assertNotMatchesAnyField(RECORD_TLM, matcher);
- assertMatchesAnyField(RECORD_IBEACON, matcher);
- }
-
- @SmallTest
- public void testParser() {
- byte[] scanRecord = new byte[] {
- 0x02, 0x01, 0x1a, // advertising flags
- 0x05, 0x02, 0x0b, 0x11, 0x0a, 0x11, // 16 bit service uuids
- 0x04, 0x09, 0x50, 0x65, 0x64, // name
- 0x02, 0x0A, (byte) 0xec, // tx power level
- 0x05, 0x16, 0x0b, 0x11, 0x50, 0x64, // service data
- 0x05, (byte) 0xff, (byte) 0xe0, 0x00, 0x02, 0x15, // manufacturer specific data
- 0x03, 0x50, 0x01, 0x02, // an unknown data type won't cause trouble
- };
- ScanRecord data = ScanRecord.parseFromBytes(scanRecord);
- assertEquals(0x1a, data.getAdvertiseFlags());
- ParcelUuid uuid1 = ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
- ParcelUuid uuid2 = ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
- assertTrue(data.getServiceUuids().contains(uuid1));
- assertTrue(data.getServiceUuids().contains(uuid2));
-
- assertEquals("Ped", data.getDeviceName());
- assertEquals(-20, data.getTxPowerLevel());
-
- assertTrue(data.getManufacturerSpecificData().get(0x00E0) != null);
- assertArrayEquals(new byte[] {
- 0x02, 0x15 }, data.getManufacturerSpecificData().get(0x00E0));
-
- assertTrue(data.getServiceData().containsKey(uuid2));
- assertArrayEquals(new byte[] {
- 0x50, 0x64 }, data.getServiceData().get(uuid2));
- }
-
- // Assert two byte arrays are equal.
- private static void assertArrayEquals(byte[] expected, byte[] actual) {
- if (!Arrays.equals(expected, actual)) {
- fail("expected:<" + Arrays.toString(expected) +
- "> but was:<" + Arrays.toString(actual) + ">");
- }
-
- }
-
- private static void assertMatchesAnyField(String record, BytesMatcher matcher) {
- assertTrue(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record))
- .matchesAnyField(matcher));
- }
-
- private static void assertNotMatchesAnyField(String record, BytesMatcher matcher) {
- assertFalse(ScanRecord.parseFromBytes(HexDump.hexStringToByteArray(record))
- .matchesAnyField(matcher));
- }
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanResultTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanResultTest.java
deleted file mode 100644
index 01d5c59..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanResultTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * Unit test cases for Bluetooth LE scans.
- * <p>
- * To run this test, use adb shell am instrument -e class 'android.bluetooth.ScanResultTest' -w
- * 'com.android.bluetooth.tests/android.bluetooth.BluetoothTestRunner'
- */
-public class ScanResultTest extends TestCase {
-
- /**
- * Test read and write parcel of ScanResult
- */
- @SmallTest
- public void testScanResultParceling() {
- BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(
- "01:02:03:04:05:06");
- byte[] scanRecord = new byte[] {
- 1, 2, 3 };
- int rssi = -10;
- long timestampMicros = 10000L;
-
- ScanResult result = new ScanResult(device, ScanRecord.parseFromBytes(scanRecord), rssi,
- timestampMicros);
- Parcel parcel = Parcel.obtain();
- result.writeToParcel(parcel, 0);
- // Need to reset parcel data position to the beginning.
- parcel.setDataPosition(0);
- ScanResult resultFromParcel = ScanResult.CREATOR.createFromParcel(parcel);
- assertEquals(result, resultFromParcel);
- }
-
-}
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java b/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java
deleted file mode 100644
index 7c42c3b..0000000
--- a/core/tests/bluetoothtests/src/android/bluetooth/le/ScanSettingsTest.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth.le;
-
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-/**
- * Test for Bluetooth LE {@link ScanSettings}.
- */
-public class ScanSettingsTest extends TestCase {
-
- @SmallTest
- public void testCallbackType() {
- ScanSettings.Builder builder = new ScanSettings.Builder();
- builder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES);
- builder.setCallbackType(ScanSettings.CALLBACK_TYPE_FIRST_MATCH);
- builder.setCallbackType(ScanSettings.CALLBACK_TYPE_MATCH_LOST);
- builder.setCallbackType(
- ScanSettings.CALLBACK_TYPE_FIRST_MATCH | ScanSettings.CALLBACK_TYPE_MATCH_LOST);
- try {
- builder.setCallbackType(
- ScanSettings.CALLBACK_TYPE_ALL_MATCHES | ScanSettings.CALLBACK_TYPE_MATCH_LOST);
- fail("should have thrown IllegalArgumentException!");
- } catch (IllegalArgumentException e) {
- // nothing to do
- }
-
- try {
- builder.setCallbackType(
- ScanSettings.CALLBACK_TYPE_ALL_MATCHES |
- ScanSettings.CALLBACK_TYPE_FIRST_MATCH);
- fail("should have thrown IllegalArgumentException!");
- } catch (IllegalArgumentException e) {
- // nothing to do
- }
-
- try {
- builder.setCallbackType(
- ScanSettings.CALLBACK_TYPE_ALL_MATCHES |
- ScanSettings.CALLBACK_TYPE_FIRST_MATCH |
- ScanSettings.CALLBACK_TYPE_MATCH_LOST);
- fail("should have thrown IllegalArgumentException!");
- } catch (IllegalArgumentException e) {
- // nothing to do
- }
-
- }
-}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
index 69e617a..9699275 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsTest.java
@@ -83,7 +83,7 @@
final Parcel parcel = Parcel.obtain();
parcel.writeParcelable(outBatteryUsageStats, 0);
- assertThat(parcel.dataSize()).isLessThan(5500);
+ assertThat(parcel.dataSize()).isLessThan(6000);
parcel.setDataPosition(0);
diff --git a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
index e7ce9a0..a787357 100644
--- a/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/WifiPowerCalculatorTest.java
@@ -25,6 +25,8 @@
import android.net.NetworkCapabilities;
import android.net.NetworkStats;
import android.os.BatteryConsumer;
+import android.os.BatteryStats;
+import android.os.BatteryUsageStatsQuery;
import android.os.Process;
import android.os.UidBatteryConsumer;
import android.os.WorkSource;
@@ -40,6 +42,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
+@SuppressWarnings("GuardedBy")
public class WifiPowerCalculatorTest {
private static final double PRECISION = 0.00001;
@@ -66,14 +69,18 @@
batteryStats.noteNetworkInterfaceForTransports("wifi",
new int[]{NetworkCapabilities.TRANSPORT_WIFI});
- NetworkStats networkStats = new NetworkStats(10000, 1)
- .insertEntry("wifi", APP_UID, 0, 0, 1000, 100, 2000, 20, 100)
- .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
- mStatsRule.setNetworkStats(networkStats);
+ mStatsRule.setNetworkStats(buildNetworkStats(10000, 1000, 100, 2000, 20));
return batteryStats;
}
+ private NetworkStats buildNetworkStats(long elapsedRealtime, int rxBytes, int rxPackets,
+ int txBytes, int txPackets) {
+ return new NetworkStats(elapsedRealtime, 1)
+ .insertEntry("wifi", APP_UID, 0, 0, rxBytes, rxPackets, txBytes, txPackets, 100)
+ .insertEntry("wifi", Process.WIFI_UID, 0, 0, 1111, 111, 2222, 22, 111);
+ }
+
/** Sets up an WifiActivityEnergyInfo for ActivityController-model-based tests. */
private WifiActivityEnergyInfo setupPowerControllerBasedModelEnergyNumbersInfo() {
return new WifiActivityEnergyInfo(10000,
@@ -115,6 +122,61 @@
}
@Test
+ public void testPowerControllerBasedModel_powerProfile_byProcessState() {
+ final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
+
+ mStatsRule.setTime(1000, 1000);
+
+ BatteryStatsImpl.Uid uid = batteryStats.getUidStatsLocked(APP_UID);
+ uid.setProcessStateForTest(
+ BatteryStats.Uid.PROCESS_STATE_FOREGROUND, 1000);
+
+ batteryStats.updateWifiState(new WifiActivityEnergyInfo(2000,
+ WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000),
+ POWER_DATA_UNAVAILABLE, 2000, 2000,
+ mNetworkStatsManager);
+
+ uid.setProcessStateForTest(
+ BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 3000);
+
+ mStatsRule.setNetworkStats(buildNetworkStats(4000, 5000, 200, 7000, 80));
+
+ batteryStats.updateWifiState(new WifiActivityEnergyInfo(4000,
+ WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000),
+ POWER_DATA_UNAVAILABLE, 4000, 4000,
+ mNetworkStatsManager);
+
+ WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
+ mStatsRule.apply(new BatteryUsageStatsQuery.Builder()
+ .powerProfileModeledOnly()
+ .includePowerModels()
+ .includeProcessStateData()
+ .build(), calculator);
+
+ UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+ assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isEqualTo(12423);
+ assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isWithin(PRECISION).of(2.0214666);
+ assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isEqualTo(BatteryConsumer.POWER_MODEL_POWER_PROFILE);
+
+ final BatteryConsumer.Key foreground = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_WIFI,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND);
+ final BatteryConsumer.Key background = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_WIFI,
+ BatteryConsumer.PROCESS_STATE_BACKGROUND);
+ final BatteryConsumer.Key fgs = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_WIFI,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+
+ assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(1.1214666);
+ assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.9);
+ assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
+ }
+
+ @Test
public void testPowerControllerBasedModel_measured() {
final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
final WifiActivityEnergyInfo energyInfo = setupPowerControllerBasedModelEnergyNumbersInfo();
@@ -148,6 +210,60 @@
.isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
}
+ @Test
+ public void testPowerControllerBasedModel_measured_byProcessState() {
+ final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
+
+ mStatsRule.setTime(1000, 1000);
+
+ BatteryStatsImpl.Uid uid = batteryStats.getUidStatsLocked(APP_UID);
+ uid.setProcessStateForTest(
+ BatteryStats.Uid.PROCESS_STATE_FOREGROUND, 1000);
+
+ batteryStats.updateWifiState(new WifiActivityEnergyInfo(2000,
+ WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 1000, 2000, 3000, 4000),
+ 1_000_000, 2000, 2000,
+ mNetworkStatsManager);
+
+ uid.setProcessStateForTest(
+ BatteryStats.Uid.PROCESS_STATE_BACKGROUND, 3000);
+
+ mStatsRule.setNetworkStats(buildNetworkStats(4000, 5000, 200, 7000, 80));
+
+ batteryStats.updateWifiState(new WifiActivityEnergyInfo(4000,
+ WifiActivityEnergyInfo.STACK_STATE_STATE_ACTIVE, 5000, 6000, 7000, 8000),
+ 5_000_000, 4000, 4000,
+ mNetworkStatsManager);
+
+ WifiPowerCalculator calculator = new WifiPowerCalculator(mStatsRule.getPowerProfile());
+ mStatsRule.apply(new BatteryUsageStatsQuery.Builder()
+ .includePowerModels()
+ .includeProcessStateData()
+ .build(), calculator);
+
+ UidBatteryConsumer uidConsumer = mStatsRule.getUidBatteryConsumer(APP_UID);
+ assertThat(uidConsumer.getUsageDurationMillis(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isEqualTo(12423);
+ assertThat(uidConsumer.getConsumedPower(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isWithin(PRECISION).of(1.0325211);
+ assertThat(uidConsumer.getPowerModel(BatteryConsumer.POWER_COMPONENT_WIFI))
+ .isEqualTo(BatteryConsumer.POWER_MODEL_MEASURED_ENERGY);
+
+ final BatteryConsumer.Key foreground = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_WIFI,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND);
+ final BatteryConsumer.Key background = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_WIFI,
+ BatteryConsumer.PROCESS_STATE_BACKGROUND);
+ final BatteryConsumer.Key fgs = uidConsumer.getKey(
+ BatteryConsumer.POWER_COMPONENT_WIFI,
+ BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE);
+
+ assertThat(uidConsumer.getConsumedPower(foreground)).isWithin(PRECISION).of(0.5517519);
+ assertThat(uidConsumer.getConsumedPower(background)).isWithin(PRECISION).of(0.4807691);
+ assertThat(uidConsumer.getConsumedPower(fgs)).isWithin(PRECISION).of(0);
+ }
+
/** Sets up batterystats object with prepopulated network & timer data for Timer-model tests. */
private BatteryStatsImpl setupTimerBasedModelTestNumbers() {
final BatteryStatsImpl batteryStats = setupTestNetworkNumbers();
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index e6ff187..43cb5ee 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -16,8 +16,12 @@
package android.graphics;
+import android.annotation.IntDef;
import android.annotation.NonNull;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Shader used to draw a bitmap as a texture. The bitmap can be repeated or
* mirrored by setting the tiling mode.
@@ -31,6 +35,47 @@
private int mTileX;
private int mTileY;
+ /** @hide */
+ @IntDef(prefix = {"FILTER_MODE"}, value = {
+ FILTER_MODE_DEFAULT,
+ FILTER_MODE_NEAREST,
+ FILTER_MODE_LINEAR
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface FilterMode {}
+
+ /**
+ * This FilterMode value will respect the value of the Paint#isFilterBitmap flag while the
+ * shader is attached to the Paint.
+ *
+ * <p>The exception to this rule is when a Shader is attached as input to a RuntimeShader. In
+ * that case this mode will default to FILTER_MODE_NEAREST.</p>
+ *
+ * @see #setFilterMode(int)
+ */
+ public static final int FILTER_MODE_DEFAULT = 0;
+ /**
+ * This FilterMode value will cause the shader to sample from the nearest pixel to the requested
+ * sample point.
+ *
+ * <p>This value will override the effect of Paint#isFilterBitmap.</p>
+ *
+ * @see #setFilterMode(int)
+ */
+ public static final int FILTER_MODE_NEAREST = 1;
+ /**
+ * This FilterMode value will cause the shader to interpolate the output of the shader from a
+ * 2x2 grid of pixels nearest to the sample point (i.e. bilinear interpolation).
+ *
+ * <p>This value will override the effect of Paint#isFilterBitmap.</p>
+ *
+ * @see #setFilterMode(int)
+ */
+ public static final int FILTER_MODE_LINEAR = 2;
+
+ @FilterMode
+ private int mFilterMode;
+
/*
* This is cache of the last value from the Paint of bitmap-filtering.
* In the future, BitmapShaders will carry their own (expanded) data for this
@@ -49,6 +94,15 @@
private boolean mFilterFromPaint;
/**
+ * Stores whether or not the contents of this shader's bitmap will be sampled
+ * without modification or if the bitmap's properties, like colorspace and
+ * premultiplied alpha, will be respected when sampling from the bitmap's buffer.
+ */
+ private boolean mIsDirectSampled;
+
+ private boolean mRequestDirectSampling;
+
+ /**
* Call this to create a new shader that will draw with a bitmap.
*
* @param bitmap The bitmap to use inside the shader
@@ -66,24 +120,60 @@
mBitmap = bitmap;
mTileX = tileX;
mTileY = tileY;
+ mFilterMode = FILTER_MODE_DEFAULT;
mFilterFromPaint = false;
+ mIsDirectSampled = false;
+ mRequestDirectSampling = false;
+ }
+
+ /**
+ * Returns the filter mode used when sampling from this shader
+ */
+ @FilterMode
+ public int getFilterMode() {
+ return mFilterMode;
+ }
+
+ /**
+ * Set the filter mode to be used when sampling from this shader
+ */
+ public void setFilterMode(@FilterMode int mode) {
+ if (mode != mFilterMode) {
+ mFilterMode = mode;
+ discardNativeInstance();
+ }
+ }
+
+ /** @hide */
+ /* package */ synchronized long getNativeInstanceWithDirectSampling() {
+ mRequestDirectSampling = true;
+ return getNativeInstance();
}
/** @hide */
@Override
protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
- mFilterFromPaint = filterFromPaint;
+ boolean enableLinearFilter = mFilterMode == FILTER_MODE_LINEAR;
+ if (mFilterMode == FILTER_MODE_DEFAULT) {
+ mFilterFromPaint = filterFromPaint;
+ enableLinearFilter = mFilterFromPaint;
+ }
+
+ mIsDirectSampled = mRequestDirectSampling;
+ mRequestDirectSampling = false;
+
return nativeCreate(nativeMatrix, mBitmap.getNativeInstance(), mTileX, mTileY,
- mFilterFromPaint);
+ enableLinearFilter, mIsDirectSampled);
}
/** @hide */
@Override
protected boolean shouldDiscardNativeInstance(boolean filterFromPaint) {
- return mFilterFromPaint != filterFromPaint;
+ return mIsDirectSampled != mRequestDirectSampling
+ || (mFilterMode == FILTER_MODE_DEFAULT && mFilterFromPaint != filterFromPaint);
}
private static native long nativeCreate(long nativeMatrix, long bitmapHandle,
- int shaderTileModeX, int shaderTileModeY, boolean filter);
+ int shaderTileModeX, int shaderTileModeY, boolean filter, boolean isDirectSampled);
}
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index ef57f4a..57046f5 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -279,11 +279,11 @@
}
/**
- * Sets the uniform shader that is declares as input to this shader. If the shader does not
+ * Assigns the uniform shader to the provided shader parameter. If the shader program does not
* have a uniform shader with that name then an IllegalArgumentException is thrown.
*
- * @param shaderName name matching the uniform declared in the SKSL shader
- * @param shader shader passed into the SKSL shader for sampling
+ * @param shaderName name matching the uniform declared in the AGSL shader program
+ * @param shader shader passed into the AGSL shader program for sampling
*/
public void setInputShader(@NonNull String shaderName, @NonNull Shader shader) {
if (shaderName == null) {
@@ -297,6 +297,28 @@
discardNativeInstance();
}
+ /**
+ * Assigns the uniform shader to the provided shader parameter. If the shader program does not
+ * have a uniform shader with that name then an IllegalArgumentException is thrown.
+ *
+ * Unlike setInputShader this method returns samples directly from the bitmap's buffer. This
+ * means that there will be no transformation of the sampled pixels, such as colorspace
+ * conversion or alpha premultiplication.
+ */
+ public void setInputBuffer(@NonNull String shaderName, @NonNull BitmapShader shader) {
+ if (shaderName == null) {
+ throw new NullPointerException("The shaderName parameter must not be null");
+ }
+ if (shader == null) {
+ throw new NullPointerException("The shader parameter must not be null");
+ }
+
+ nativeUpdateShader(mNativeInstanceRuntimeShaderBuilder, shaderName,
+ shader.getNativeInstanceWithDirectSampling());
+ discardNativeInstance();
+ }
+
+
/** @hide */
@Override
protected long createNativeInstance(long nativeMatrix, boolean filterFromPaint) {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index 8e6fa5f..7e232ea 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -66,7 +66,7 @@
stringExtras: Map<String, String>
) {
super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras)
- wmHelper.waitFor("hasPipWindow") { it.wmState.hasPipWindow() }
+ wmHelper.waitPipShown()
}
private fun focusOnObject(selector: BySelector): Boolean {
@@ -88,7 +88,7 @@
clickObject(ENTER_PIP_BUTTON_ID)
// Wait on WMHelper or simply wait for 3 seconds
- wmHelper?.waitFor("hasPipWindow") { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000)
+ wmHelper?.waitPipShown() ?: SystemClock.sleep(3_000)
// when entering pip, the dismiss button is visible at the start. to ensure the pip
// animation is complete, wait until the pip dismiss button is no longer visible.
// b/176822698: dismiss-only state will be removed in the future
@@ -148,7 +148,7 @@
}
// Wait for animation to complete.
- wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
+ wmHelper.waitPipGone()
wmHelper.waitForHomeActivityVisible()
}
@@ -165,7 +165,7 @@
?: error("PIP window expand button not found")
val expandButtonBounds = expandPipObject.visibleBounds
uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY())
- wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
+ wmHelper.waitPipGone()
wmHelper.waitForAppTransitionIdle()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 2deff7b..db94de2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -181,13 +182,14 @@
}
/**
- * Checks the focus doesn't change during the animation
+ * Checks that the focus changes between the [pipApp] window and the launcher when
+ * closing the pip window
*/
- @FlakyTest
+ @Postsubmit
@Test
- fun focusDoesNotChange() {
+ fun focusChanges() {
testSpec.assertEventLog {
- this.focusDoesNotChange()
+ this.focusChanges(pipApp.`package`, "NexusLauncherActivity")
}
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 0e73463..dee13c1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -98,7 +98,7 @@
// Enter PiP, and assert that the PiP is within bounds now that the device is back
// in portrait
broadcastActionTrigger.doAction(ACTION_ENTER_PIP)
- wmHelper.waitFor { it.wmState.hasPipWindow() }
+ wmHelper.waitPipShown()
wmHelper.waitForAppTransitionIdle()
// during rotation the status bar becomes invisible and reappears at the end
wmHelper.waitForNavBarStatusBarVisible()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index 9a22007..173140d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -16,9 +16,9 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
-import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.dsl.FlickerBuilder
@@ -96,14 +96,13 @@
}
/**
- * Checks that the focus changes between the [pipApp] window and the launcher when
- * closing the pip window
+ * Checks that the focus doesn't change between windows during the transition
*/
- @FlakyTest(bugId = 151179149)
+ @Postsubmit
@Test
- open fun focusChanges() {
+ open fun focusDoesNotChange() {
testSpec.assertEventLog {
- this.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
+ this.focusDoesNotChange()
}
}
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index c036515..6524182 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -63,7 +63,7 @@
val pipCenterY = pipRegion.centerY()
val displayCenterX = device.displayWidth / 2
device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 10)
- wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
+ wmHelper.waitPipGone()
wmHelper.waitForWindowSurfaceDisappeared(pipApp.component)
wmHelper.waitForAppTransitionIdle()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index ef9ff4f..8d14f70 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -16,6 +16,7 @@
package com.android.wm.shell.flicker.pip
+import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -148,7 +149,7 @@
/**
* Checks that the focus doesn't change between windows during the transition
*/
- @FlakyTest
+ @Postsubmit
@Test
fun focusDoesNotChange() {
testSpec.assertEventLog {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index 93a4e1b..bb66f7b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -125,13 +125,13 @@
removeAllTasksButHome()
if (!eachRun) {
pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras)
- wmHelper.waitFor { it.wmState.hasPipWindow() }
+ wmHelper.waitPipShown()
}
}
eachRun {
if (eachRun) {
pipApp.launchViaIntent(wmHelper, stringExtras = stringExtras)
- wmHelper.waitFor { it.wmState.hasPipWindow() }
+ wmHelper.waitPipShown()
}
}
}
diff --git a/libs/hwui/jni/Shader.cpp b/libs/hwui/jni/Shader.cpp
index c4366f75..c505b53 100644
--- a/libs/hwui/jni/Shader.cpp
+++ b/libs/hwui/jni/Shader.cpp
@@ -64,7 +64,8 @@
///////////////////////////////////////////////////////////////////////////////////////////////
static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
- jint tileModeX, jint tileModeY, bool filter) {
+ jint tileModeX, jint tileModeY, bool filter,
+ bool isDirectSampled) {
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
sk_sp<SkImage> image;
if (bitmapHandle) {
@@ -79,8 +80,12 @@
}
SkSamplingOptions sampling(filter ? SkFilterMode::kLinear : SkFilterMode::kNearest,
SkMipmapMode::kNone);
- sk_sp<SkShader> shader = image->makeShader(
- (SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
+ sk_sp<SkShader> shader;
+ if (isDirectSampled) {
+ shader = image->makeRawShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
+ } else {
+ shader = image->makeShader((SkTileMode)tileModeX, (SkTileMode)tileModeY, sampling);
+ }
ThrowIAE_IfNull(env, shader.get());
if (matrix) {
@@ -393,7 +398,7 @@
};
static const JNINativeMethod gBitmapShaderMethods[] = {
- { "nativeCreate", "(JJIIZ)J", (void*)BitmapShader_constructor },
+ {"nativeCreate", "(JJIIZZ)J", (void*)BitmapShader_constructor},
};
static const JNINativeMethod gLinearGradientMethods[] = {
diff --git a/media/java/Android.bp b/media/java/Android.bp
index eeaf6e9..c7c1d54 100644
--- a/media/java/Android.bp
+++ b/media/java/Android.bp
@@ -8,7 +8,7 @@
}
filegroup {
- name: "framework-media-sources",
+ name: "framework-media-non-updatable-sources",
srcs: [
"**/*.java",
"**/*.aidl",
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
index f3f8bbe..030d212 100644
--- a/media/java/android/media/Spatializer.java
+++ b/media/java/android/media/Spatializer.java
@@ -215,6 +215,29 @@
public static final int HEAD_TRACKING_MODE_RELATIVE_DEVICE = 2;
/**
+ * @hide
+ * Head tracking mode to string conversion
+ * @param mode a valid head tracking mode
+ * @return a string containing the matching constant name
+ */
+ public static final String headtrackingModeToString(int mode) {
+ switch(mode) {
+ case HEAD_TRACKING_MODE_UNSUPPORTED:
+ return "HEAD_TRACKING_MODE_UNSUPPORTED";
+ case HEAD_TRACKING_MODE_DISABLED:
+ return "HEAD_TRACKING_MODE_DISABLED";
+ case HEAD_TRACKING_MODE_OTHER:
+ return "HEAD_TRACKING_MODE_OTHER";
+ case HEAD_TRACKING_MODE_RELATIVE_WORLD:
+ return "HEAD_TRACKING_MODE_RELATIVE_WORLD";
+ case HEAD_TRACKING_MODE_RELATIVE_DEVICE:
+ return "HEAD_TRACKING_MODE_RELATIVE_DEVICE";
+ default:
+ return "head tracking mode unknown " + mode;
+ }
+ }
+
+ /**
* Return the level of support for the spatialization feature on this device.
* This level of support is independent of whether the {@code Spatializer} is currently
* enabled or available and will not change over time.
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java
new file mode 100644
index 0000000..fd66d3b
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/BtProfileConnectionInfoTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mediaframeworktest.unit;
+
+import static org.junit.Assert.assertEquals;
+
+import android.bluetooth.BluetoothProfile;
+import android.media.BtProfileConnectionInfo;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class BtProfileConnectionInfoTest {
+
+ @Test
+ public void testCoverageA2dp() {
+ final boolean supprNoisy = false;
+ final int volume = 42;
+ final BtProfileConnectionInfo info = BtProfileConnectionInfo.a2dpInfo(supprNoisy, volume);
+ assertEquals(info.getProfile(), BluetoothProfile.A2DP);
+ assertEquals(info.getSuppressNoisyIntent(), supprNoisy);
+ assertEquals(info.getVolume(), volume);
+ }
+
+ @Test
+ public void testCoverageA2dpSink() {
+ final int volume = 42;
+ final BtProfileConnectionInfo info = BtProfileConnectionInfo.a2dpSinkInfo(volume);
+ assertEquals(info.getProfile(), BluetoothProfile.A2DP_SINK);
+ assertEquals(info.getVolume(), volume);
+ }
+
+ @Test
+ public void testCoveragehearingAid() {
+ final boolean supprNoisy = true;
+ final BtProfileConnectionInfo info = BtProfileConnectionInfo.hearingAidInfo(supprNoisy);
+ assertEquals(info.getProfile(), BluetoothProfile.HEARING_AID);
+ assertEquals(info.getSuppressNoisyIntent(), supprNoisy);
+ }
+
+ @Test
+ public void testCoverageLeAudio() {
+ final boolean supprNoisy = false;
+ final boolean isLeOutput = true;
+ final BtProfileConnectionInfo info = BtProfileConnectionInfo.leAudio(supprNoisy,
+ isLeOutput);
+ assertEquals(info.getProfile(), BluetoothProfile.LE_AUDIO);
+ assertEquals(info.getSuppressNoisyIntent(), supprNoisy);
+ assertEquals(info.getIsLeOutput(), isLeOutput);
+ }
+}
+
diff --git a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
index d8feb88..1af32bf 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -27,8 +28,8 @@
import android.content.Context;
import android.media.MediaPlayer;
import android.os.Build;
+import android.os.IBinder;
import android.os.RemoteException;
-import android.os.ServiceManager;
import com.android.server.NetworkManagementSocketTagger;
@@ -36,6 +37,8 @@
import java.io.FileDescriptor;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.net.DatagramSocket;
import java.net.Socket;
import java.net.SocketException;
@@ -53,6 +56,7 @@
* use {@link NetworkStatsManager} instead.
*/
public class TrafficStats {
+ private static final String TAG = TrafficStats.class.getSimpleName();
/**
* The return value to indicate that the device does not support the statistic.
*/
@@ -173,12 +177,25 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private synchronized static INetworkStatsService getStatsService() {
if (sStatsService == null) {
- sStatsService = INetworkStatsService.Stub.asInterface(
- ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ sStatsService = getStatsBinder();
}
return sStatsService;
}
+ @Nullable
+ private static INetworkStatsService getStatsBinder() {
+ try {
+ final Method getServiceMethod = Class.forName("android.os.ServiceManager")
+ .getDeclaredMethod("getService", new Class[]{String.class});
+ final IBinder binder = (IBinder) getServiceMethod.invoke(
+ null, Context.NETWORK_STATS_SERVICE);
+ return INetworkStatsService.Stub.asInterface(binder);
+ } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException
+ | InvocationTargetException e) {
+ throw new NullPointerException("Cannot get INetworkStatsService: " + e);
+ }
+ }
+
/**
* Snapshot of {@link NetworkStats} when the currently active profiling
* session started, or {@code null} if no session active.
@@ -265,6 +282,18 @@
}
/**
+ * Set active tag to use when accounting {@link Socket} traffic originating
+ * from the current thread. The tag used internally is well-defined to
+ * distinguish all download provider traffic.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static void setThreadStatsTagDownload() {
+ setThreadStatsTag(TAG_SYSTEM_DOWNLOAD);
+ }
+
+ /**
* Get the active tag used when accounting {@link Socket} traffic originating
* from the current thread. Only one active tag per thread is supported.
* {@link #tagSocket(Socket)}.
diff --git a/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java b/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java
index e35f6a6..1eb52fb 100644
--- a/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java
+++ b/packages/ConnectivityT/framework-t/src/com/android/server/NetworkManagementSocketTagger.java
@@ -26,6 +26,7 @@
/**
* Assigns tags to sockets for traffic stats.
+ * @hide
*/
public final class NetworkManagementSocketTagger extends SocketTagger {
private static final String TAG = "NetworkManagementSocketTagger";
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
index 7539f99..851ea65 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginManagerImpl.java
@@ -137,7 +137,8 @@
filter.addAction(PLUGIN_CHANGED);
filter.addAction(DISABLE_PLUGIN);
filter.addDataScheme("package");
- mContext.registerReceiver(this, filter, PluginActionManager.PLUGIN_PERMISSION, null);
+ mContext.registerReceiver(this, filter, PluginActionManager.PLUGIN_PERMISSION, null,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiver(this, filter);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
index 26c227d..8bcb7c9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardEsimArea.java
@@ -91,7 +91,8 @@
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_DISABLE_ESIM),
- PERMISSION_SELF, null /* scheduler */);
+ PERMISSION_SELF, null /* scheduler */,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
}
public static boolean isEsimLocked(Context context, int subId) {
diff --git a/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java b/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
index d7da63b..1f2de4c 100644
--- a/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/SliceBroadcastRelayHandler.java
@@ -112,7 +112,8 @@
public void register(Context context, ComponentName receiver, IntentFilter filter) {
mReceivers.add(receiver);
- context.registerReceiver(this, filter);
+ context.registerReceiver(this, filter,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
}
public void unregister(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 1ac9016..2b12f67 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -518,7 +518,7 @@
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(mBroadcastReceiver, filter);
+ context.registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_EXPORTED_UNAUDITED);
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index d208441..6581490 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -539,7 +539,8 @@
final IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(mBroadcastReceiver, filter);
+ context.registerReceiver(mBroadcastReceiver, filter,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
udfpsHapticsSimulator.setUdfpsController(this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
index 89623f4..f3b721c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/FeatureFlagsDebug.java
@@ -88,7 +88,8 @@
filter.addAction(ACTION_GET_FLAGS);
flagManager.setRestartAction(this::restartSystemUI);
flagManager.setClearCacheAction(this::removeFromCache);
- context.registerReceiver(mReceiver, filter, null, null);
+ context.registerReceiver(mReceiver, filter, null, null,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
dumpManager.registerDumpable(TAG, this);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 5ca2539..fdd6f65 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -894,7 +894,8 @@
delayedActionFilter.addAction(DELAYED_KEYGUARD_ACTION);
delayedActionFilter.addAction(DELAYED_LOCK_PROFILE_ACTION);
mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
- SYSTEMUI_PERMISSION, null /* scheduler */);
+ SYSTEMUI_PERMISSION, null /* scheduler */,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 4e039279..83d581f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -539,7 +539,8 @@
}
boolean isVolumeControlEnabled(@NonNull MediaDevice device) {
- return !device.getFeatures().contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK)
+ // TODO(b/202500642): Also enable volume control for remote non-group sessions.
+ return !isActiveRemoteDevice(device)
|| mVolumeAdjustmentForRemoteGroupSessions;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 9dc823b..d785059 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -293,7 +293,8 @@
IntentFilter internalFilter = new IntentFilter();
internalFilter.addAction(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION);
- mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
+ mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
mCurrentUserId = ActivityManager.getCurrentUser(); // in case we reg'd receiver too late
updateCurrentProfilesCache();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 137c519..649aa42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1003,7 +1003,7 @@
internalFilter.addAction(BANNER_ACTION_CANCEL);
internalFilter.addAction(BANNER_ACTION_SETUP);
mContext.registerReceiver(mBannerActionBroadcastReceiver, internalFilter, PERMISSION_SELF,
- null);
+ null, Context.RECEIVER_EXPORTED_UNAUDITED);
if (mWallpaperSupported) {
IWallpaperManager wallpaperManager = IWallpaperManager.Stub.asInterface(
@@ -1332,7 +1332,8 @@
demoFilter.addAction(ACTION_FAKE_ARTWORK);
}
mContext.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
- android.Manifest.permission.DUMP, null);
+ android.Manifest.permission.DUMP, null,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
// listen for USER_SETUP_COMPLETE setting (per-user)
mDeviceProvisionedController.addCallback(mUserSetupObserver);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index c1f63b8..05a586b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -128,7 +128,7 @@
update(true /* updateAlways */);
}
}
- }, filter, null, null);
+ }, filter, null, null, Context.RECEIVER_EXPORTED_UNAUDITED);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
index f42e388..29285f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoControllerImpl.java
@@ -74,7 +74,7 @@
profileFilter.addAction(ContactsContract.Intents.ACTION_PROFILE_CHANGED);
profileFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
mContext.registerReceiverAsUser(mProfileReceiver, UserHandle.ALL, profileFilter,
- null, null);
+ null, null, Context.RECEIVER_EXPORTED_UNAUDITED);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 79ee746..9f20bc5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -229,7 +229,8 @@
filter = new IntentFilter();
mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter,
- PERMISSION_SELF, null /* scheduler */);
+ PERMISSION_SELF, null /* scheduler */,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
mSettingsObserver = new ContentObserver(mHandler) {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 90c7f1f..cf361ec 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -167,9 +167,11 @@
mStorageManager.registerListener(mListener);
mContext.registerReceiver(mSnoozeReceiver, new IntentFilter(ACTION_SNOOZE_VOLUME),
- android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
+ android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
mContext.registerReceiver(mFinishReceiver, new IntentFilter(ACTION_FINISH_WIZARD),
- android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null);
+ android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS, null,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
// Kick current state into place
final List<DiskInfo> disks = mStorageManager.getDisks();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
index a40cf4f..5b188b2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/SafetyWarningDialog.java
@@ -63,7 +63,8 @@
setOnDismissListener(this);
final IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- context.registerReceiver(mReceiver, filter);
+ context.registerReceiver(mReceiver, filter,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
}
abstract protected void cleanUp();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
index 7d55623..7c121e1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SliceBroadcastRelayHandlerTest.java
@@ -15,6 +15,7 @@
package com.android.systemui;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -79,7 +80,7 @@
intent.putExtra(SliceBroadcastRelay.EXTRA_URI, testUri);
mRelayHandler.handleIntent(intent);
- verify(mSpyContext).registerReceiver(any(), eq(value));
+ verify(mSpyContext).registerReceiver(any(), eq(value), anyInt());
}
@Test
@@ -99,7 +100,7 @@
mRelayHandler.handleIntent(intent);
ArgumentCaptor<BroadcastReceiver> relay = ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mSpyContext).registerReceiver(relay.capture(), eq(value));
+ verify(mSpyContext).registerReceiver(relay.capture(), eq(value), anyInt());
intent = new Intent(SliceBroadcastRelay.ACTION_UNREGISTER);
intent.putExtra(SliceBroadcastRelay.EXTRA_URI, ContentProvider.maybeAddUserId(testUri, 0));
@@ -138,7 +139,7 @@
mRelayHandler.handleIntent(intent);
ArgumentCaptor<BroadcastReceiver> relay = ArgumentCaptor.forClass(BroadcastReceiver.class);
- verify(mSpyContext).registerReceiver(relay.capture(), eq(value));
+ verify(mSpyContext).registerReceiver(relay.capture(), eq(value), anyInt());
relay.getValue().onReceive(mSpyContext, new Intent(TEST_ACTION));
verify(Receiver.sReceiver, timeout(2000)).onReceive(any(), any());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
index 3d679de..0674ea8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestableContext.java
@@ -83,6 +83,16 @@
}
@Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, int flags) {
+ if (receiver != null) {
+ synchronized (mRegisteredReceivers) {
+ mRegisteredReceivers.add(receiver);
+ }
+ }
+ return super.registerReceiver(receiver, filter, flags);
+ }
+
+ @Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
if (receiver != null) {
@@ -94,6 +104,17 @@
}
@Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
+ String broadcastPermission, Handler scheduler, int flags) {
+ if (receiver != null) {
+ synchronized (mRegisteredReceivers) {
+ mRegisteredReceivers.add(receiver);
+ }
+ }
+ return super.registerReceiver(receiver, filter, broadcastPermission, scheduler, flags);
+ }
+
+ @Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
IntentFilter filter, String broadcastPermission, Handler scheduler) {
if (receiver != null) {
@@ -105,6 +126,18 @@
}
@Override
+ public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+ IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
+ if (receiver != null) {
+ synchronized (mRegisteredReceivers) {
+ mRegisteredReceivers.add(receiver);
+ }
+ }
+ return super.registerReceiverAsUser(receiver, user, filter, broadcastPermission, scheduler,
+ flags);
+ }
+
+ @Override
public void unregisterReceiver(BroadcastReceiver receiver) {
if (receiver != null) {
synchronized (mRegisteredReceivers) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
index cb16bec..87bc732 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/flags/FeatureFlagsDebugTest.kt
@@ -76,7 +76,8 @@
)
verify(mFlagManager).restartAction = any()
mBroadcastReceiver = withArgCaptor {
- verify(mMockContext).registerReceiver(capture(), any(), nullable(), nullable())
+ verify(mMockContext).registerReceiver(capture(), any(), nullable(), nullable(),
+ any())
}
mClearCacheAction = withArgCaptor {
verify(mFlagManager).clearCacheAction = capture()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index ba7bbfe..20a3fda 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -102,7 +102,8 @@
mReceiver = new BlockingQueueIntentReceiver();
mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION), null,
- Handler.createAsync(Dependency.get(Dependency.BG_LOOPER)));
+ Handler.createAsync(Dependency.get(Dependency.BG_LOOPER)),
+ Context.RECEIVER_EXPORTED_UNAUDITED);
// Avoid SecurityException RemoteInputView#sendRemoteInput().
mContext.addMockSystemService(ShortcutManager.class, mShortcutManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
index 32aee2b..0e25d24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyViewTest.java
@@ -30,6 +30,7 @@
import android.app.Notification;
import android.app.PendingIntent;
import android.app.RemoteInput;
+import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
@@ -119,7 +120,8 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mReceiver = new BlockingQueueIntentReceiver();
- mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION));
+ mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION),
+ Context.RECEIVER_EXPORTED_UNAUDITED);
mKeyguardDismissUtil.setDismissHandler((action, unused, afterKgGone) -> action.onDismiss());
mDependency.injectMockDependency(KeyguardUpdateMonitor.class);
mDependency.injectMockDependency(ShadeController.class);
diff --git a/services/Android.bp b/services/Android.bp
index 74d7f65..f33c8c0 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -77,6 +77,7 @@
":services.appwidget-sources",
":services.autofill-sources",
":services.backup-sources",
+ ":services.bluetooth-sources", // TODO(b/214988855) : Remove once apex/service-bluetooth jar is ready
":backuplib-sources",
":services.companion-sources",
":services.contentcapture-sources",
diff --git a/services/companion/java/com/android/server/companion/AssociationStoreImpl.java b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
index 5b318d3..dbcdd0f 100644
--- a/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
+++ b/services/companion/java/com/android/server/companion/AssociationStoreImpl.java
@@ -37,6 +37,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.StringJoiner;
/**
* Implementation of the {@link AssociationStore}, with addition of the methods for modification.
@@ -58,33 +59,15 @@
private final Object mLock = new Object();
@GuardedBy("mLock")
- private final Map<Integer, AssociationInfo> mIdMap;
+ private final Map<Integer, AssociationInfo> mIdMap = new HashMap<>();
@GuardedBy("mLock")
- private final Map<MacAddress, Set<Integer>> mAddressMap;
+ private final Map<MacAddress, Set<Integer>> mAddressMap = new HashMap<>();
@GuardedBy("mLock")
private final SparseArray<List<AssociationInfo>> mCachedPerUser = new SparseArray<>();
@GuardedBy("mListeners")
private final Set<OnChangeListener> mListeners = new LinkedHashSet<>();
- AssociationStoreImpl(Collection<AssociationInfo> associations) {
- synchronized (mLock) {
- final int size = associations.size();
- mIdMap = new HashMap<>(size);
- mAddressMap = new HashMap<>(size);
-
- for (AssociationInfo association : associations) {
- final int id = association.getId();
- mIdMap.put(id, association);
-
- final MacAddress address = association.getDeviceMacAddress();
- if (address != null) {
- mAddressMap.computeIfAbsent(address, it -> new HashSet<>()).add(id);
- }
- }
- }
- }
-
void addAssociation(@NonNull AssociationInfo association) {
final int id = association.getId();
@@ -301,4 +284,38 @@
}
}
}
+
+ void setAssociations(Collection<AssociationInfo> allAssociations) {
+ if (DEBUG) {
+ Log.i(TAG, "setAssociations() n=" + allAssociations.size());
+ final StringJoiner stringJoiner = new StringJoiner(", ");
+ allAssociations.forEach(assoc -> stringJoiner.add(assoc.toShortString()));
+ Log.v(TAG, " associations=" + stringJoiner);
+ }
+ synchronized (mLock) {
+ setAssociationsLocked(allAssociations);
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void setAssociationsLocked(Collection<AssociationInfo> associations) {
+ clearLocked();
+
+ for (AssociationInfo association : associations) {
+ final int id = association.getId();
+ mIdMap.put(id, association);
+
+ final MacAddress address = association.getDeviceMacAddress();
+ if (address != null) {
+ mAddressMap.computeIfAbsent(address, it -> new HashSet<>()).add(id);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void clearLocked() {
+ mIdMap.clear();
+ mAddressMap.clear();
+ mCachedPerUser.clear();
+ }
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 1c98347..1e50c80 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -159,7 +159,7 @@
// Persistent data store for all Associations.
private PersistentDataStore mPersistentStore;
- private AssociationStoreImpl mAssociationStore;
+ private final AssociationStoreImpl mAssociationStore = new AssociationStoreImpl();
private AssociationRequestsProcessor mAssociationRequestsProcessor;
private PowerWhitelistManager mPowerWhitelistManager;
@@ -219,16 +219,8 @@
@Override
public void onStart() {
mPersistentStore = new PersistentDataStore();
- final Set<AssociationInfo> allAssociations = new ArraySet<>();
- synchronized (mPreviouslyUsedIds) {
- // The data is stored in DE directories, so we can read the data for all users now
- // (which would not be possible if the data was stored to CE directories).
- mPersistentStore.readStateForUsers(
- mUserManager.getAliveUsers(), allAssociations, mPreviouslyUsedIds);
- }
-
- mAssociationStore = new AssociationStoreImpl(allAssociations);
+ loadAssociationsFromDisk();
mAssociationStore.registerListener(this);
mCompanionDevicePresenceController = new CompanionDevicePresenceController(this);
@@ -239,6 +231,18 @@
publishBinderService(Context.COMPANION_DEVICE_SERVICE, impl);
}
+ void loadAssociationsFromDisk() {
+ final Set<AssociationInfo> allAssociations = new ArraySet<>();
+ synchronized (mPreviouslyUsedIds) {
+ // The data is stored in DE directories, so we can read the data for all users now
+ // (which would not be possible if the data was stored to CE directories).
+ mPersistentStore.readStateForUsers(
+ mUserManager.getAliveUsers(), allAssociations, mPreviouslyUsedIds);
+ }
+
+ mAssociationStore.setAssociations(allAssociations);
+ }
+
@Override
public void onBootPhase(int phase) {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 5c0571d..5f46d5c 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -82,7 +82,10 @@
mService.onDeviceDisconnected(getNextArgRequired());
}
break;
-
+ case "clear-association-memory-cache": {
+ mService.loadAssociationsFromDisk();
+ }
+ break;
default:
return handleDefaultCommands(cmd);
}
@@ -110,5 +113,8 @@
pw.println(" Create a new Association.");
pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS");
pw.println(" Remove an existing Association.");
+ pw.println(" clear-association-memory-cache");
+ pw.println(" Clear the in-memory association cache and reload all association "
+ + "information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY.");
}
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 95ec9e9..094ed37 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -103,6 +103,7 @@
":android.hardware.biometrics.face-V2-java-source",
":statslog-art-java-gen",
":statslog-contexthub-java-gen",
+ ":services.bluetooth-sources", // TODO(b/214988855) : Remove once apex is ready
":services.core-sources",
":services.core.protologsrc",
":dumpstate_aidl",
diff --git a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java b/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
deleted file mode 100644
index 380b1f3..0000000
--- a/services/core/java/com/android/server/BluetoothAirplaneModeListener.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.annotation.RequiresPermission;
-import android.content.Context;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * The BluetoothAirplaneModeListener handles system airplane mode change callback and checks
- * whether we need to inform BluetoothManagerService on this change.
- *
- * The information of airplane mode turns on would not be passed to the BluetoothManagerService
- * when Bluetooth is on and Bluetooth is in one of the following situations:
- * 1. Bluetooth A2DP is connected.
- * 2. Bluetooth Hearing Aid profile is connected.
- * 3. Bluetooth LE Audio is connected
- */
-class BluetoothAirplaneModeListener {
- private static final String TAG = "BluetoothAirplaneModeListener";
- @VisibleForTesting static final String TOAST_COUNT = "bluetooth_airplane_toast_count";
-
- private static final int MSG_AIRPLANE_MODE_CHANGED = 0;
-
- @VisibleForTesting static final int MAX_TOAST_COUNT = 10; // 10 times
-
- private final BluetoothManagerService mBluetoothManager;
- private final BluetoothAirplaneModeHandler mHandler;
- private BluetoothModeChangeHelper mAirplaneHelper;
-
- @VisibleForTesting int mToastCount = 0;
-
- BluetoothAirplaneModeListener(BluetoothManagerService service, Looper looper, Context context) {
- mBluetoothManager = service;
-
- mHandler = new BluetoothAirplaneModeHandler(looper);
- context.getContentResolver().registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
- mAirplaneModeObserver);
- }
-
- private final ContentObserver mAirplaneModeObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean unused) {
- // Post from system main thread to android_io thread.
- Message msg = mHandler.obtainMessage(MSG_AIRPLANE_MODE_CHANGED);
- mHandler.sendMessage(msg);
- }
- };
-
- private class BluetoothAirplaneModeHandler extends Handler {
- BluetoothAirplaneModeHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_AIRPLANE_MODE_CHANGED:
- handleAirplaneModeChange();
- break;
- default:
- Log.e(TAG, "Invalid message: " + msg.what);
- break;
- }
- }
- }
-
- /**
- * Call after boot complete
- */
- @VisibleForTesting
- void start(BluetoothModeChangeHelper helper) {
- Log.i(TAG, "start");
- mAirplaneHelper = helper;
- mToastCount = mAirplaneHelper.getSettingsInt(TOAST_COUNT);
- }
-
- @VisibleForTesting
- boolean shouldPopToast() {
- if (mToastCount >= MAX_TOAST_COUNT) {
- return false;
- }
- mToastCount++;
- mAirplaneHelper.setSettingsInt(TOAST_COUNT, mToastCount);
- return true;
- }
-
- @VisibleForTesting
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- void handleAirplaneModeChange() {
- if (shouldSkipAirplaneModeChange()) {
- Log.i(TAG, "Ignore airplane mode change");
- // Airplane mode enabled when Bluetooth is being used for audio/headering aid.
- // Bluetooth is not disabled in such case, only state is changed to
- // BLUETOOTH_ON_AIRPLANE mode.
- mAirplaneHelper.setSettingsInt(Settings.Global.BLUETOOTH_ON,
- BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
- if (shouldPopToast()) {
- mAirplaneHelper.showToastMessage();
- }
- return;
- }
- if (mAirplaneHelper != null) {
- mAirplaneHelper.onAirplaneModeChanged(mBluetoothManager);
- }
- }
-
- @VisibleForTesting
- boolean shouldSkipAirplaneModeChange() {
- if (mAirplaneHelper == null) {
- return false;
- }
- if (!mAirplaneHelper.isBluetoothOn() || !mAirplaneHelper.isAirplaneModeOn()
- || !mAirplaneHelper.isMediaProfileConnected()) {
- return false;
- }
- return true;
- }
-}
diff --git a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java b/services/core/java/com/android/server/BluetoothDeviceConfigListener.java
deleted file mode 100644
index 611a37d..0000000
--- a/services/core/java/com/android/server/BluetoothDeviceConfigListener.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.provider.DeviceConfig;
-import android.util.Slog;
-
-import java.util.ArrayList;
-
-/**
- * The BluetoothDeviceConfigListener handles system device config change callback and checks
- * whether we need to inform BluetoothManagerService on this change.
- *
- * The information of device config change would not be passed to the BluetoothManagerService
- * when Bluetooth is on and Bluetooth is in one of the following situations:
- * 1. Bluetooth A2DP is connected.
- * 2. Bluetooth Hearing Aid profile is connected.
- */
-class BluetoothDeviceConfigListener {
- private static final String TAG = "BluetoothDeviceConfigListener";
-
- private final BluetoothManagerService mService;
- private final boolean mLogDebug;
-
- BluetoothDeviceConfigListener(BluetoothManagerService service, boolean logDebug) {
- mService = service;
- mLogDebug = logDebug;
- DeviceConfig.addOnPropertiesChangedListener(
- DeviceConfig.NAMESPACE_BLUETOOTH,
- (Runnable r) -> r.run(),
- mDeviceConfigChangedListener);
- }
-
- private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener =
- new DeviceConfig.OnPropertiesChangedListener() {
- @Override
- public void onPropertiesChanged(DeviceConfig.Properties properties) {
- if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) {
- return;
- }
- if (mLogDebug) {
- ArrayList<String> flags = new ArrayList<>();
- for (String name : properties.getKeyset()) {
- flags.add(name + "='" + properties.getString(name, "") + "'");
- }
- Slog.d(TAG, "onPropertiesChanged: " + String.join(",", flags));
- }
- boolean foundInit = false;
- for (String name : properties.getKeyset()) {
- if (name.startsWith("INIT_")) {
- foundInit = true;
- break;
- }
- }
- if (!foundInit) {
- return;
- }
- mService.onInitFlagsChanged();
- }
- };
-
-}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
deleted file mode 100644
index 262933d..0000000
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ /dev/null
@@ -1,2962 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static android.Manifest.permission.BLUETOOTH_CONNECT;
-import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
-import static android.os.UserHandle.USER_SYSTEM;
-import static android.permission.PermissionCheckerManager.PERMISSION_HARD_DENIED;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.AppGlobals;
-import android.app.AppOpsManager;
-import android.app.BroadcastOptions;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProtoEnums;
-import android.bluetooth.IBluetooth;
-import android.bluetooth.IBluetoothCallback;
-import android.bluetooth.IBluetoothGatt;
-import android.bluetooth.IBluetoothHeadset;
-import android.bluetooth.IBluetoothManager;
-import android.bluetooth.IBluetoothManagerCallback;
-import android.bluetooth.IBluetoothProfileServiceConnection;
-import android.bluetooth.IBluetoothStateChangeCallback;
-import android.bluetooth.IBluetoothLeCallControl;
-import android.content.ActivityNotFoundException;
-import android.content.AttributionSource;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.UserInfo;
-import android.database.ContentObserver;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerExemptionManager;
-import android.os.Process;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.permission.PermissionManager;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.text.TextUtils;
-import android.util.FeatureFlagUtils;
-import android.util.Log;
-import android.util.Slog;
-import android.util.proto.ProtoOutputStream;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FrameworkStatsLog;
-import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
-import com.android.server.pm.UserRestrictionsUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.Locale;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-class BluetoothManagerService extends IBluetoothManager.Stub {
- private static final String TAG = "BluetoothManagerService";
- private static final boolean DBG = true;
-
- private static final String BLUETOOTH_PRIVILEGED =
- android.Manifest.permission.BLUETOOTH_PRIVILEGED;
-
- private static final int ACTIVE_LOG_MAX_SIZE = 20;
- private static final int CRASH_LOG_MAX_SIZE = 100;
-
- private static final int TIMEOUT_BIND_MS = 3000; //Maximum msec to wait for a bind
- //Maximum msec to wait for service restart
- private static final int SERVICE_RESTART_TIME_MS = 400;
- //Maximum msec to wait for restart due to error
- private static final int ERROR_RESTART_TIME_MS = 3000;
- //Maximum msec to delay MESSAGE_USER_SWITCHED
- private static final int USER_SWITCHED_TIME_MS = 200;
- // Delay for the addProxy function in msec
- private static final int ADD_PROXY_DELAY_MS = 100;
- // Delay for retrying enable and disable in msec
- private static final int ENABLE_DISABLE_DELAY_MS = 300;
- private static final int DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS = 300;
- private static final int DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS = 86400;
-
- private static final int MESSAGE_ENABLE = 1;
- private static final int MESSAGE_DISABLE = 2;
- private static final int MESSAGE_HANDLE_ENABLE_DELAYED = 3;
- private static final int MESSAGE_HANDLE_DISABLE_DELAYED = 4;
- private static final int MESSAGE_REGISTER_STATE_CHANGE_CALLBACK = 30;
- private static final int MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK = 31;
- private static final int MESSAGE_BLUETOOTH_SERVICE_CONNECTED = 40;
- private static final int MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED = 41;
- private static final int MESSAGE_RESTART_BLUETOOTH_SERVICE = 42;
- private static final int MESSAGE_BLUETOOTH_STATE_CHANGE = 60;
- private static final int MESSAGE_TIMEOUT_BIND = 100;
- private static final int MESSAGE_TIMEOUT_UNBIND = 101;
- private static final int MESSAGE_GET_NAME_AND_ADDRESS = 200;
- private static final int MESSAGE_USER_SWITCHED = 300;
- private static final int MESSAGE_USER_UNLOCKED = 301;
- private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
- private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
- private static final int MESSAGE_RESTORE_USER_SETTING = 500;
- private static final int MESSAGE_INIT_FLAGS_CHANGED = 600;
-
- private static final int RESTORE_SETTING_TO_ON = 1;
- private static final int RESTORE_SETTING_TO_OFF = 0;
-
- private static final int MAX_ERROR_RESTART_RETRIES = 6;
- private static final int MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES = 10;
-
- // Bluetooth persisted setting is off
- private static final int BLUETOOTH_OFF = 0;
- // Bluetooth persisted setting is on
- // and Airplane mode won't affect Bluetooth state at start up
- private static final int BLUETOOTH_ON_BLUETOOTH = 1;
- // Bluetooth persisted setting is on
- // but Airplane mode will affect Bluetooth state at start up
- // and Airplane mode will have higher priority.
- @VisibleForTesting
- static final int BLUETOOTH_ON_AIRPLANE = 2;
-
- private static final int SERVICE_IBLUETOOTH = 1;
- private static final int SERVICE_IBLUETOOTHGATT = 2;
-
- private final Context mContext;
-
- // Locks are not provided for mName and mAddress.
- // They are accessed in handler or broadcast receiver, same thread context.
- private String mAddress;
- private String mName;
- private final ContentResolver mContentResolver;
- private final int mUserId;
- private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks;
- private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks;
- private IBinder mBluetoothBinder;
- private IBluetooth mBluetooth;
- private IBluetoothGatt mBluetoothGatt;
- private final ReentrantReadWriteLock mBluetoothLock = new ReentrantReadWriteLock();
- private boolean mBinding;
- private boolean mUnbinding;
-
- private BluetoothModeChangeHelper mBluetoothModeChangeHelper;
-
- private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
-
- private BluetoothDeviceConfigListener mBluetoothDeviceConfigListener;
-
- // used inside handler thread
- private boolean mQuietEnable = false;
- private boolean mEnable;
-
- private static CharSequence timeToLog(long timestamp) {
- return android.text.format.DateFormat.format("MM-dd HH:mm:ss", timestamp);
- }
-
- /**
- * Used for tracking apps that enabled / disabled Bluetooth.
- */
- private class ActiveLog {
- private int mReason;
- private String mPackageName;
- private boolean mEnable;
- private long mTimestamp;
-
- ActiveLog(int reason, String packageName, boolean enable, long timestamp) {
- mReason = reason;
- mPackageName = packageName;
- mEnable = enable;
- mTimestamp = timestamp;
- }
-
- public String toString() {
- return timeToLog(mTimestamp) + (mEnable ? " Enabled " : " Disabled ")
- + " due to " + getEnableDisableReasonString(mReason) + " by " + mPackageName;
- }
-
- void dump(ProtoOutputStream proto) {
- proto.write(BluetoothManagerServiceDumpProto.ActiveLog.TIMESTAMP_MS, mTimestamp);
- proto.write(BluetoothManagerServiceDumpProto.ActiveLog.ENABLE, mEnable);
- proto.write(BluetoothManagerServiceDumpProto.ActiveLog.PACKAGE_NAME, mPackageName);
- proto.write(BluetoothManagerServiceDumpProto.ActiveLog.REASON, mReason);
- }
- }
-
- private final LinkedList<ActiveLog> mActiveLogs = new LinkedList<>();
- private final LinkedList<Long> mCrashTimestamps = new LinkedList<>();
- private int mCrashes;
- private long mLastEnabledTime;
-
- // configuration from external IBinder call which is used to
- // synchronize with broadcast receiver.
- private boolean mQuietEnableExternal;
- private boolean mEnableExternal;
-
- // Map of apps registered to keep BLE scanning on.
- private Map<IBinder, ClientDeathRecipient> mBleApps =
- new ConcurrentHashMap<IBinder, ClientDeathRecipient>();
-
- private int mState;
- private final BluetoothHandler mHandler;
- private int mErrorRecoveryRetryCounter;
- private final int mSystemUiUid;
-
- private boolean mIsHearingAidProfileSupported;
-
- private AppOpsManager mAppOps;
-
- // Save a ProfileServiceConnections object for each of the bound
- // bluetooth profile services
- private final Map<Integer, ProfileServiceConnections> mProfileServices = new HashMap<>();
-
- private final boolean mWirelessConsentRequired;
-
- private final IBluetoothCallback mBluetoothCallback = new IBluetoothCallback.Stub() {
- @Override
- public void onBluetoothStateChange(int prevState, int newState) throws RemoteException {
- Message msg =
- mHandler.obtainMessage(MESSAGE_BLUETOOTH_STATE_CHANGE, prevState, newState);
- mHandler.sendMessage(msg);
- }
- };
-
- private final UserRestrictionsListener mUserRestrictionsListener =
- new UserRestrictionsListener() {
- @Override
- public void onUserRestrictionsChanged(int userId, Bundle newRestrictions,
- Bundle prevRestrictions) {
-
- if (UserRestrictionsUtils.restrictionsChanged(prevRestrictions, newRestrictions,
- UserManager.DISALLOW_BLUETOOTH_SHARING)) {
- updateOppLauncherComponentState(userId,
- newRestrictions.getBoolean(UserManager.DISALLOW_BLUETOOTH_SHARING));
- }
-
- // DISALLOW_BLUETOOTH can only be set by DO or PO on the system user.
- if (userId == USER_SYSTEM
- && UserRestrictionsUtils.restrictionsChanged(prevRestrictions,
- newRestrictions, UserManager.DISALLOW_BLUETOOTH)) {
- if (userId == USER_SYSTEM && newRestrictions.getBoolean(
- UserManager.DISALLOW_BLUETOOTH)) {
- updateOppLauncherComponentState(userId, true); // Sharing disallowed
- sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED,
- mContext.getPackageName());
- } else {
- updateOppLauncherComponentState(userId, newRestrictions.getBoolean(
- UserManager.DISALLOW_BLUETOOTH_SHARING));
- }
- }
- }
- };
-
- @VisibleForTesting
- public void onInitFlagsChanged() {
- mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_INIT_FLAGS_CHANGED,
- DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS);
- }
-
- public boolean onFactoryReset(AttributionSource attributionSource) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
- "Need BLUETOOTH_PRIVILEGED permission");
-
- // Wait for stable state if bluetooth is temporary state.
- int state = getState();
- if (state == BluetoothAdapter.STATE_BLE_TURNING_ON
- || state == BluetoothAdapter.STATE_TURNING_ON
- || state == BluetoothAdapter.STATE_TURNING_OFF) {
- if (!waitForState(Set.of(BluetoothAdapter.STATE_BLE_ON, BluetoothAdapter.STATE_ON))) {
- return false;
- }
- }
-
- // Clear registered LE apps to force shut-off Bluetooth
- clearBleApps();
- state = getState();
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth == null) {
- return false;
- }
- if (state == BluetoothAdapter.STATE_BLE_ON) {
- addActiveLog(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
- mContext.getPackageName(), false);
- mBluetooth.onBrEdrDown(attributionSource);
- return true;
- } else if (state == BluetoothAdapter.STATE_ON) {
- addActiveLog(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET,
- mContext.getPackageName(), false);
- mBluetooth.disable(attributionSource);
- return true;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to shutdown Bluetooth", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- return false;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void onAirplaneModeChanged() {
- synchronized (this) {
- if (isBluetoothPersistedStateOn()) {
- if (isAirplaneModeOn()) {
- persistBluetoothSetting(BLUETOOTH_ON_AIRPLANE);
- } else {
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- }
- }
-
- int st = BluetoothAdapter.STATE_OFF;
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- st = mBluetooth.getState();
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call getState", e);
- return;
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- Slog.d(TAG,
- "Airplane Mode change - current state: " + BluetoothAdapter.nameForState(
- st) + ", isAirplaneModeOn()=" + isAirplaneModeOn());
-
- if (isAirplaneModeOn()) {
- // Clear registered LE apps to force shut-off
- clearBleApps();
-
- // If state is BLE_ON make sure we trigger disableBLE
- if (st == BluetoothAdapter.STATE_BLE_ON) {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- addActiveLog(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
- mContext.getPackageName(), false);
- mBluetooth.onBrEdrDown(mContext.getAttributionSource());
- mEnable = false;
- mEnableExternal = false;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBrEdrDown", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- } else if (st == BluetoothAdapter.STATE_ON) {
- sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
- mContext.getPackageName());
- }
- } else if (mEnableExternal) {
- sendEnableMsg(mQuietEnableExternal,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE,
- mContext.getPackageName());
- }
- }
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED.equals(action)) {
- String newName = intent.getStringExtra(BluetoothAdapter.EXTRA_LOCAL_NAME);
- if (DBG) {
- Slog.d(TAG, "Bluetooth Adapter name changed to " + newName + " by "
- + mContext.getPackageName());
- }
- if (newName != null) {
- storeNameAndAddress(newName, null);
- }
- } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) {
- String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS);
- if (newAddress != null) {
- if (DBG) {
- Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress);
- }
- storeNameAndAddress(null, newAddress);
- } else {
- if (DBG) {
- Slog.e(TAG, "No Bluetooth Adapter address parameter found");
- }
- }
- } else if (Intent.ACTION_SETTING_RESTORED.equals(action)) {
- final String name = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
- if (Settings.Global.BLUETOOTH_ON.equals(name)) {
- // The Bluetooth On state may be changed during system restore.
- final String prevValue =
- intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
- final String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
-
- if (DBG) {
- Slog.d(TAG,
- "ACTION_SETTING_RESTORED with BLUETOOTH_ON, prevValue=" + prevValue
- + ", newValue=" + newValue);
- }
-
- if ((newValue != null) && (prevValue != null) && !prevValue.equals(newValue)) {
- Message msg = mHandler.obtainMessage(MESSAGE_RESTORE_USER_SETTING,
- newValue.equals("0") ? RESTORE_SETTING_TO_OFF
- : RESTORE_SETTING_TO_ON, 0);
- mHandler.sendMessage(msg);
- }
- }
- } else if (BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED.equals(action)
- || BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED.equals(action)
- || BluetoothLeAudio.ACTION_LE_AUDIO_CONNECTION_STATE_CHANGED.equals(action)) {
- final int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
- BluetoothProfile.STATE_CONNECTED);
- if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)
- && state == BluetoothProfile.STATE_DISCONNECTED
- && !mBluetoothModeChangeHelper.isMediaProfileConnected()) {
- Slog.i(TAG, "Device disconnected, reactivating pending flag changes");
- onInitFlagsChanged();
- }
- }
- }
- };
-
- BluetoothManagerService(Context context) {
- mHandler = new BluetoothHandler(IoThread.get().getLooper());
-
- mContext = context;
-
- mWirelessConsentRequired = context.getResources()
- .getBoolean(com.android.internal.R.bool.config_wirelessConsentRequired);
-
- mCrashes = 0;
- mBluetooth = null;
- mBluetoothBinder = null;
- mBluetoothGatt = null;
- mBinding = false;
- mUnbinding = false;
- mEnable = false;
- mState = BluetoothAdapter.STATE_OFF;
- mQuietEnableExternal = false;
- mEnableExternal = false;
- mAddress = null;
- mName = null;
- mErrorRecoveryRetryCounter = 0;
- mContentResolver = context.getContentResolver();
- mUserId = mContentResolver.getUserId();
- // Observe BLE scan only mode settings change.
- registerForBleScanModeChange();
- mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
- mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();
-
- mIsHearingAidProfileSupported = context.getResources()
- .getBoolean(com.android.internal.R.bool.config_hearing_aid_profile_supported);
-
- // TODO: We need a more generic way to initialize the persist keys of FeatureFlagUtils
- String value = SystemProperties.get(FeatureFlagUtils.PERSIST_PREFIX + FeatureFlagUtils.HEARING_AID_SETTINGS);
- if (!TextUtils.isEmpty(value)) {
- boolean isHearingAidEnabled = Boolean.parseBoolean(value);
- Log.v(TAG, "set feature flag HEARING_AID_SETTINGS to " + isHearingAidEnabled);
- FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.HEARING_AID_SETTINGS, isHearingAidEnabled);
- if (isHearingAidEnabled && !mIsHearingAidProfileSupported) {
- // Overwrite to enable support by FeatureFlag
- mIsHearingAidProfileSupported = true;
- }
- }
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
- filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
- filter.addAction(Intent.ACTION_SETTING_RESTORED);
- filter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
- filter.addAction(BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
- filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- mContext.registerReceiver(mReceiver, filter);
-
- loadStoredNameAndAddress();
- if (isBluetoothPersistedStateOn()) {
- if (DBG) {
- Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
- }
- mEnableExternal = true;
- }
-
- String airplaneModeRadios =
- Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);
- if (airplaneModeRadios == null || airplaneModeRadios.contains(
- Settings.Global.RADIO_BLUETOOTH)) {
- mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
- this, IoThread.get().getLooper(), context);
- }
-
- int systemUiUid = -1;
- // Check if device is configured with no home screen, which implies no SystemUI.
- boolean noHome = mContext.getResources().getBoolean(R.bool.config_noHomeScreen);
- if (!noHome) {
- PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
- systemUiUid = pm.getPackageUid(pm.getSystemUiServiceComponent().getPackageName(),
- MATCH_SYSTEM_ONLY, USER_SYSTEM);
- }
- if (systemUiUid >= 0) {
- Slog.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid));
- } else {
- // Some platforms, such as wearables do not have a system ui.
- Slog.w(TAG, "Unable to resolve SystemUI's UID.");
- }
- mSystemUiUid = systemUiUid;
- }
-
- /**
- * Returns true if airplane mode is currently on
- */
- private boolean isAirplaneModeOn() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
- }
-
- private boolean supportBluetoothPersistedState() {
- return mContext.getResources().getBoolean(R.bool.config_supportBluetoothPersistedState);
- }
-
- /**
- * Returns true if the Bluetooth saved state is "on"
- */
- private boolean isBluetoothPersistedStateOn() {
- if (!supportBluetoothPersistedState()) {
- return false;
- }
- int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1);
- if (DBG) {
- Slog.d(TAG, "Bluetooth persisted state: " + state);
- }
- return state != BLUETOOTH_OFF;
- }
-
- private boolean isBluetoothPersistedStateOnAirplane() {
- if (!supportBluetoothPersistedState()) {
- return false;
- }
- int state = Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON, -1);
- if (DBG) {
- Slog.d(TAG, "Bluetooth persisted state: " + state);
- }
- return state == BLUETOOTH_ON_AIRPLANE;
- }
-
- /**
- * Returns true if the Bluetooth saved state is BLUETOOTH_ON_BLUETOOTH
- */
- private boolean isBluetoothPersistedStateOnBluetooth() {
- if (!supportBluetoothPersistedState()) {
- return false;
- }
- return Settings.Global.getInt(mContentResolver, Settings.Global.BLUETOOTH_ON,
- BLUETOOTH_ON_BLUETOOTH) == BLUETOOTH_ON_BLUETOOTH;
- }
-
- /**
- * Save the Bluetooth on/off state
- */
- private void persistBluetoothSetting(int value) {
- if (DBG) {
- Slog.d(TAG, "Persisting Bluetooth Setting: " + value);
- }
- // waive WRITE_SECURE_SETTINGS permission check
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- Settings.Global.putInt(mContext.getContentResolver(),
- Settings.Global.BLUETOOTH_ON, value);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
-
- /**
- * Returns true if the Bluetooth Adapter's name and address is
- * locally cached
- * @return
- */
- private boolean isNameAndAddressSet() {
- return mName != null && mAddress != null && mName.length() > 0 && mAddress.length() > 0;
- }
-
- /**
- * Retrieve the Bluetooth Adapter's name and address and save it in
- * in the local cache
- */
- private void loadStoredNameAndAddress() {
- if (DBG) {
- Slog.d(TAG, "Loading stored name and address");
- }
- if (mContext.getResources()
- .getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation)
- && Settings.Secure.getIntForUser(mContentResolver,
- Settings.Secure.BLUETOOTH_NAME, 0, mUserId)
- == 0) {
- // if the valid flag is not set, don't load the address and name
- if (DBG) {
- Slog.d(TAG, "invalid bluetooth name and address stored");
- }
- return;
- }
- mName = Settings.Secure.getStringForUser(
- mContentResolver, Settings.Secure.BLUETOOTH_NAME, mUserId);
- mAddress = Settings.Secure.getStringForUser(
- mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS, mUserId);
- if (DBG) {
- Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
- }
- }
-
- /**
- * Save the Bluetooth name and address in the persistent store.
- * Only non-null values will be saved.
- * @param name
- * @param address
- */
- private void storeNameAndAddress(String name, String address) {
- if (name != null) {
- Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_NAME, name,
- mUserId);
- mName = name;
- if (DBG) {
- Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser(
- mContentResolver, Settings.Secure.BLUETOOTH_NAME,
- mUserId));
- }
- }
-
- if (address != null) {
- Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
- address, mUserId);
- mAddress = address;
- if (DBG) {
- Slog.d(TAG,
- "Stored Bluetoothaddress: " + Settings.Secure.getStringForUser(
- mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
- mUserId));
- }
- }
-
- if ((name != null) && (address != null)) {
- Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDR_VALID, 1,
- mUserId);
- }
- }
-
- public IBluetooth registerAdapter(IBluetoothManagerCallback callback) {
- if (callback == null) {
- Slog.w(TAG, "Callback is null in registerAdapter");
- return null;
- }
- synchronized (mCallbacks) {
- mCallbacks.register(callback);
- }
- return mBluetooth;
- }
-
- public void unregisterAdapter(IBluetoothManagerCallback callback) {
- if (callback == null) {
- Slog.w(TAG, "Callback is null in unregisterAdapter");
- return;
- }
- synchronized (mCallbacks) {
- mCallbacks.unregister(callback);
- }
- }
-
- public void registerStateChangeCallback(IBluetoothStateChangeCallback callback) {
- if (callback == null) {
- Slog.w(TAG, "registerStateChangeCallback: Callback is null!");
- return;
- }
- Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_STATE_CHANGE_CALLBACK);
- msg.obj = callback;
- mHandler.sendMessage(msg);
- }
-
- public void unregisterStateChangeCallback(IBluetoothStateChangeCallback callback) {
- if (callback == null) {
- Slog.w(TAG, "unregisterStateChangeCallback: Callback is null!");
- return;
- }
- Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK);
- msg.obj = callback;
- mHandler.sendMessage(msg);
- }
-
- public boolean isEnabled() {
- return getState() == BluetoothAdapter.STATE_ON;
- }
-
- public int getState() {
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG, "getState(): report OFF for non-active and non system user");
- return BluetoothAdapter.STATE_OFF;
- }
-
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- return mBluetooth.getState();
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "getState()", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- return BluetoothAdapter.STATE_OFF;
- }
-
- class ClientDeathRecipient implements IBinder.DeathRecipient {
- private String mPackageName;
-
- ClientDeathRecipient(String packageName) {
- mPackageName = packageName;
- }
-
- public void binderDied() {
- if (DBG) {
- Slog.d(TAG, "Binder is dead - unregister " + mPackageName);
- }
-
- for (Map.Entry<IBinder, ClientDeathRecipient> entry : mBleApps.entrySet()) {
- IBinder token = entry.getKey();
- ClientDeathRecipient deathRec = entry.getValue();
- if (deathRec.equals(this)) {
- updateBleAppCount(token, false, mPackageName);
- break;
- }
- }
- }
-
- public String getPackageName() {
- return mPackageName;
- }
- }
-
- @Override
- public boolean isBleScanAlwaysAvailable() {
- if (isAirplaneModeOn() && !mEnable) {
- return false;
- }
- try {
- return Settings.Global.getInt(mContentResolver,
- Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE) != 0;
- } catch (SettingNotFoundException e) {
- }
- return false;
- }
-
- @Override
- public boolean isHearingAidProfileSupported() {
- return mIsHearingAidProfileSupported;
- }
-
- private boolean isDeviceProvisioned() {
- return Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED,
- 0) != 0;
- }
-
- // Monitor change of BLE scan only mode settings.
- private void registerForProvisioningStateChange() {
- ContentObserver contentObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- if (!isDeviceProvisioned()) {
- if (DBG) {
- Slog.d(TAG, "DEVICE_PROVISIONED setting changed, but device is not "
- + "provisioned");
- }
- return;
- }
- if (mHandler.hasMessages(MESSAGE_INIT_FLAGS_CHANGED)) {
- Slog.i(TAG, "Device provisioned, reactivating pending flag changes");
- onInitFlagsChanged();
- }
- }
- };
-
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), false,
- contentObserver);
- }
-
- // Monitor change of BLE scan only mode settings.
- private void registerForBleScanModeChange() {
- ContentObserver contentObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- if (isBleScanAlwaysAvailable()) {
- // Nothing to do
- return;
- }
- // BLE scan is not available.
- disableBleScanMode();
- clearBleApps();
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
- mContext.getPackageName(), false);
- mBluetooth.onBrEdrDown(mContext.getAttributionSource());
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "error when disabling bluetooth", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- }
- };
-
- mContentResolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE), false,
- contentObserver);
- }
-
- // Disable ble scan only mode.
- private void disableBleScanMode() {
- try {
- mBluetoothLock.writeLock().lock();
- if (mBluetooth != null && (mBluetooth.getState() != BluetoothAdapter.STATE_ON)) {
- if (DBG) {
- Slog.d(TAG, "Reseting the mEnable flag for clean disable");
- }
- mEnable = false;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "getState()", e);
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
- }
-
- private int updateBleAppCount(IBinder token, boolean enable, String packageName) {
- ClientDeathRecipient r = mBleApps.get(token);
- if (r == null && enable) {
- ClientDeathRecipient deathRec = new ClientDeathRecipient(packageName);
- try {
- token.linkToDeath(deathRec, 0);
- } catch (RemoteException ex) {
- throw new IllegalArgumentException("BLE app (" + packageName + ") already dead!");
- }
- mBleApps.put(token, deathRec);
- if (DBG) {
- Slog.d(TAG, "Registered for death of " + packageName);
- }
- } else if (!enable && r != null) {
- // Unregister death recipient as the app goes away.
- token.unlinkToDeath(r, 0);
- mBleApps.remove(token);
- if (DBG) {
- Slog.d(TAG, "Unregistered for death of " + packageName);
- }
- }
- int appCount = mBleApps.size();
- if (DBG) {
- Slog.d(TAG, appCount + " registered Ble Apps");
- }
- return appCount;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private boolean checkBluetoothPermissions(AttributionSource attributionSource, String message,
- boolean requireForeground) {
- if (isBluetoothDisallowed()) {
- if (DBG) {
- Slog.d(TAG, "checkBluetoothPermissions: bluetooth disallowed");
- }
- return false;
- }
- // Check if packageName belongs to callingUid
- final int callingUid = Binder.getCallingUid();
- final boolean isCallerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
- if (!isCallerSystem) {
- checkPackage(callingUid, attributionSource.getPackageName());
-
- if (requireForeground && !checkIfCallerIsForegroundUser()) {
- Slog.w(TAG, "Not allowed for non-active and non system user");
- return false;
- }
-
- if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, message)) {
- return false;
- }
- }
- return true;
- }
-
- public boolean enableBle(AttributionSource attributionSource, IBinder token)
- throws RemoteException {
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "enableBle", false)) {
- if (DBG) {
- Slog.d(TAG, "enableBle(): bluetooth disallowed");
- }
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "enableBle(" + packageName + "): mBluetooth =" + mBluetooth
- + " mBinding = " + mBinding + " mState = "
- + BluetoothAdapter.nameForState(mState));
- }
- updateBleAppCount(token, true, packageName);
-
- if (mState == BluetoothAdapter.STATE_ON
- || mState == BluetoothAdapter.STATE_BLE_ON
- || mState == BluetoothAdapter.STATE_TURNING_ON
- || mState == BluetoothAdapter.STATE_TURNING_OFF
- || mState == BluetoothAdapter.STATE_BLE_TURNING_ON) {
- Log.d(TAG, "enableBLE(): Bluetooth is already enabled or is turning on");
- return true;
- }
- synchronized (mReceiver) {
- // waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false, BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
- packageName, true);
- }
- return true;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean disableBle(AttributionSource attributionSource, IBinder token)
- throws RemoteException {
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "disableBle", false)) {
- if (DBG) {
- Slog.d(TAG, "disableBLE(): bluetooth disallowed");
- }
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "disableBle(" + packageName + "): mBluetooth =" + mBluetooth
- + " mBinding = " + mBinding + " mState = "
- + BluetoothAdapter.nameForState(mState));
- }
-
- if (mState == BluetoothAdapter.STATE_OFF) {
- Slog.d(TAG, "disableBLE(): Already disabled");
- return false;
- }
- updateBleAppCount(token, false, packageName);
-
- if (mState == BluetoothAdapter.STATE_BLE_ON && !isBleAppPresent()) {
- if (mEnable) {
- disableBleScanMode();
- }
- if (!mEnableExternal) {
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
- packageName, false);
- sendBrEdrDownCallback(attributionSource);
- }
- }
- return true;
- }
-
- // Clear all apps using BLE scan only mode.
- private void clearBleApps() {
- mBleApps.clear();
- }
-
- /** @hide */
- public boolean isBleAppPresent() {
- if (DBG) {
- Slog.d(TAG, "isBleAppPresent() count: " + mBleApps.size());
- }
- return mBleApps.size() > 0;
- }
-
- /**
- * Call IBluetooth.onLeServiceUp() to continue if Bluetooth should be on,
- * call IBluetooth.onBrEdrDown() to disable if Bluetooth should be off.
- */
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- private void continueFromBleOnState() {
- if (DBG) {
- Slog.d(TAG, "continueFromBleOnState()");
- }
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth == null) {
- Slog.e(TAG, "onBluetoothServiceUp: mBluetooth is null!");
- return;
- }
- if (!mEnableExternal && !isBleAppPresent()) {
- Slog.i(TAG, "Bluetooth was disabled while enabling BLE, disable BLE now");
- mEnable = false;
- mBluetooth.onBrEdrDown(mContext.getAttributionSource());
- return;
- }
- if (isBluetoothPersistedStateOnBluetooth() || !isBleAppPresent()) {
- // This triggers transition to STATE_ON
- mBluetooth.onLeServiceUp(mContext.getAttributionSource());
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onServiceUp", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- }
-
- /**
- * Inform BluetoothAdapter instances that BREDR part is down
- * and turn off all service and stack if no LE app needs it
- */
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- private void sendBrEdrDownCallback(AttributionSource attributionSource) {
- if (DBG) {
- Slog.d(TAG, "Calling sendBrEdrDownCallback callbacks");
- }
-
- if (mBluetooth == null) {
- Slog.w(TAG, "Bluetooth handle is null");
- return;
- }
-
- if (isBleAppPresent()) {
- // Need to stay at BLE ON. Disconnect all Gatt connections
- try {
- mBluetoothGatt.unregAll(attributionSource);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to disconnect all apps.", e);
- }
- } else {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- mBluetooth.onBrEdrDown(attributionSource);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Call to onBrEdrDown() failed.", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- }
-
- }
-
- public boolean enableNoAutoConnect(AttributionSource attributionSource) {
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "enableNoAutoConnect", false)) {
- if (DBG) {
- Slog.d(TAG, "enableNoAutoConnect(): not enabling - bluetooth disallowed");
- }
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "enableNoAutoConnect(): mBluetooth =" + mBluetooth + " mBinding = "
- + mBinding);
- }
-
- int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
- if (callingAppId != Process.NFC_UID) {
- throw new SecurityException("no permission to enable Bluetooth quietly");
- }
-
- synchronized (mReceiver) {
- mQuietEnableExternal = true;
- mEnableExternal = true;
- sendEnableMsg(true,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
- }
- return true;
- }
-
- public boolean enable(AttributionSource attributionSource) throws RemoteException {
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "enable", true)) {
- if (DBG) {
- Slog.d(TAG, "enable(): not enabling - bluetooth disallowed");
- }
- return false;
- }
-
- final int callingUid = Binder.getCallingUid();
- final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
- if (!callerSystem && !isEnabled() && mWirelessConsentRequired
- && startConsentUiIfNeeded(packageName,
- callingUid, BluetoothAdapter.ACTION_REQUEST_ENABLE)) {
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "enable(" + packageName + "): mBluetooth =" + mBluetooth + " mBinding = "
- + mBinding + " mState = " + BluetoothAdapter.nameForState(mState));
- }
-
- synchronized (mReceiver) {
- mQuietEnableExternal = false;
- mEnableExternal = true;
- // waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST, packageName);
- }
- if (DBG) {
- Slog.d(TAG, "enable returning");
- }
- return true;
- }
-
- public boolean disable(AttributionSource attributionSource, boolean persist)
- throws RemoteException {
- if (!persist) {
- mContext.enforceCallingOrSelfPermission(BLUETOOTH_PRIVILEGED,
- "Need BLUETOOTH_PRIVILEGED permission");
- }
-
- final String packageName = attributionSource.getPackageName();
- if (!checkBluetoothPermissions(attributionSource, "disable", true)) {
- if (DBG) {
- Slog.d(TAG, "disable(): not disabling - bluetooth disallowed");
- }
- return false;
- }
-
- final int callingUid = Binder.getCallingUid();
- final boolean callerSystem = UserHandle.getAppId(callingUid) == Process.SYSTEM_UID;
- if (!callerSystem && isEnabled() && mWirelessConsentRequired
- && startConsentUiIfNeeded(packageName,
- callingUid, BluetoothAdapter.ACTION_REQUEST_DISABLE)) {
- return false;
- }
-
- if (DBG) {
- Slog.d(TAG, "disable(): mBluetooth = " + mBluetooth + " mBinding = " + mBinding);
- }
-
- synchronized (mReceiver) {
- if (!isBluetoothPersistedStateOnAirplane()) {
- if (persist) {
- persistBluetoothSetting(BLUETOOTH_OFF);
- }
- mEnableExternal = false;
- }
- sendDisableMsg(BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST,
- packageName);
- }
- return true;
- }
-
- private boolean startConsentUiIfNeeded(String packageName,
- int callingUid, String intentAction) throws RemoteException {
- if (checkBluetoothPermissionWhenWirelessConsentRequired()) {
- return false;
- }
- try {
- // Validate the package only if we are going to use it
- ApplicationInfo applicationInfo = mContext.getPackageManager()
- .getApplicationInfoAsUser(packageName,
- PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
- UserHandle.getUserId(callingUid));
- if (applicationInfo.uid != callingUid) {
- throw new SecurityException("Package " + packageName
- + " not in uid " + callingUid);
- }
-
- Intent intent = new Intent(intentAction);
- intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
- intent.setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- try {
- mContext.startActivity(intent);
- } catch (ActivityNotFoundException e) {
- // Shouldn't happen
- Slog.e(TAG, "Intent to handle action " + intentAction + " missing");
- return false;
- }
- return true;
- } catch (PackageManager.NameNotFoundException e) {
- throw new RemoteException(e.getMessage());
- }
- }
-
- /**
- * Check if AppOpsManager is available and the packageName belongs to uid
- *
- * A null package belongs to any uid
- */
- private void checkPackage(int uid, String packageName) {
- if (mAppOps == null) {
- Slog.w(TAG, "checkPackage(): called before system boot up, uid "
- + uid + ", packageName " + packageName);
- throw new IllegalStateException("System has not boot yet");
- }
- if (packageName == null) {
- Slog.w(TAG, "checkPackage(): called with null packageName from " + uid);
- return;
- }
- try {
- mAppOps.checkPackage(uid, packageName);
- } catch (SecurityException e) {
- Slog.w(TAG, "checkPackage(): " + packageName + " does not belong to uid " + uid);
- throw new SecurityException(e.getMessage());
- }
- }
-
- /**
- * Check if the caller must still pass permission check or if the caller is exempted
- * from the consent UI via the MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED check.
- *
- * Commands from some callers may be exempted from triggering the consent UI when
- * enabling bluetooth. This exemption is checked via the
- * MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED and allows calls to skip
- * the consent UI where it may otherwise be required.
- *
- * @hide
- */
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private boolean checkBluetoothPermissionWhenWirelessConsentRequired() {
- int result = mContext.checkCallingPermission(
- android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_WIRELESS_CONSENT_REQUIRED);
- return result == PackageManager.PERMISSION_GRANTED;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void unbindAndFinish() {
- if (DBG) {
- Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding
- + " mUnbinding = " + mUnbinding);
- }
-
- try {
- mBluetoothLock.writeLock().lock();
- if (mUnbinding) {
- return;
- }
- mUnbinding = true;
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE);
- if (mBluetooth != null) {
- //Unregister callback object
- try {
- mBluetooth.unregisterCallback(mBluetoothCallback,
- mContext.getAttributionSource());
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to unregister BluetoothCallback", re);
- }
- mBluetoothBinder = null;
- mBluetooth = null;
- mContext.unbindService(mConnection);
- mUnbinding = false;
- mBinding = false;
- } else {
- mUnbinding = false;
- }
- mBluetoothGatt = null;
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
- }
-
- public IBluetoothGatt getBluetoothGatt() {
- // sync protection
- return mBluetoothGatt;
- }
-
- @Override
- public boolean bindBluetoothProfileService(int bluetoothProfile,
- IBluetoothProfileServiceConnection proxy) {
- if (mState != BluetoothAdapter.STATE_ON) {
- if (DBG) {
- Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile
- + ", while Bluetooth was disabled");
- }
- return false;
- }
- synchronized (mProfileServices) {
- ProfileServiceConnections psc = mProfileServices.get(new Integer(bluetoothProfile));
- if (psc == null) {
- if (DBG) {
- Slog.d(TAG, "Creating new ProfileServiceConnections object for" + " profile: "
- + bluetoothProfile);
- }
-
- Intent intent;
- if (bluetoothProfile == BluetoothProfile.HEADSET) {
- intent = new Intent(IBluetoothHeadset.class.getName());
- } else if (bluetoothProfile== BluetoothProfile.LE_CALL_CONTROL) {
- intent = new Intent(IBluetoothLeCallControl.class.getName());
- } else {
- return false;
- }
-
- psc = new ProfileServiceConnections(intent);
- if (!psc.bindService()) {
- return false;
- }
-
- mProfileServices.put(new Integer(bluetoothProfile), psc);
- }
- }
-
- // Introducing a delay to give the client app time to prepare
- Message addProxyMsg = mHandler.obtainMessage(MESSAGE_ADD_PROXY_DELAYED);
- addProxyMsg.arg1 = bluetoothProfile;
- addProxyMsg.obj = proxy;
- mHandler.sendMessageDelayed(addProxyMsg, ADD_PROXY_DELAY_MS);
- return true;
- }
-
- @Override
- public void unbindBluetoothProfileService(int bluetoothProfile,
- IBluetoothProfileServiceConnection proxy) {
- synchronized (mProfileServices) {
- Integer profile = new Integer(bluetoothProfile);
- ProfileServiceConnections psc = mProfileServices.get(profile);
- if (psc == null) {
- return;
- }
- psc.removeProxy(proxy);
- if (psc.isEmpty()) {
- // All prxoies are disconnected, unbind with the service.
- try {
- mContext.unbindService(psc);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
- }
- mProfileServices.remove(profile);
- }
- }
- }
-
- private void unbindAllBluetoothProfileServices() {
- synchronized (mProfileServices) {
- for (Integer i : mProfileServices.keySet()) {
- ProfileServiceConnections psc = mProfileServices.get(i);
- try {
- mContext.unbindService(psc);
- } catch (IllegalArgumentException e) {
- Slog.e(TAG, "Unable to unbind service with intent: " + psc.mIntent, e);
- }
- psc.removeAllProxies();
- }
- mProfileServices.clear();
- }
- }
-
- /**
- * Send enable message and set adapter name and address. Called when the boot phase becomes
- * PHASE_SYSTEM_SERVICES_READY.
- */
- public void handleOnBootPhase() {
- if (DBG) {
- Slog.d(TAG, "Bluetooth boot completed");
- }
- mAppOps = mContext.getSystemService(AppOpsManager.class);
- UserManagerInternal userManagerInternal =
- LocalServices.getService(UserManagerInternal.class);
- userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
- final boolean isBluetoothDisallowed = isBluetoothDisallowed();
- if (isBluetoothDisallowed) {
- return;
- }
- final boolean isSafeMode = mContext.getPackageManager().isSafeMode();
- if (mEnableExternal && isBluetoothPersistedStateOnBluetooth() && !isSafeMode) {
- if (DBG) {
- Slog.d(TAG, "Auto-enabling Bluetooth.");
- }
- sendEnableMsg(mQuietEnableExternal,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT,
- mContext.getPackageName());
- } else if (!isNameAndAddressSet()) {
- if (DBG) {
- Slog.d(TAG, "Getting adapter name and address");
- }
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- }
-
- mBluetoothModeChangeHelper = new BluetoothModeChangeHelper(mContext);
- if (mBluetoothAirplaneModeListener != null) {
- mBluetoothAirplaneModeListener.start(mBluetoothModeChangeHelper);
- }
- registerForProvisioningStateChange();
- mBluetoothDeviceConfigListener = new BluetoothDeviceConfigListener(this, DBG);
- }
-
- /**
- * Called when switching to a different foreground user.
- */
- public void handleOnSwitchUser(int userHandle) {
- if (DBG) {
- Slog.d(TAG, "User " + userHandle + " switched");
- }
- mHandler.obtainMessage(MESSAGE_USER_SWITCHED, userHandle, 0).sendToTarget();
- }
-
- /**
- * Called when user is unlocked.
- */
- public void handleOnUnlockUser(int userHandle) {
- if (DBG) {
- Slog.d(TAG, "User " + userHandle + " unlocked");
- }
- mHandler.obtainMessage(MESSAGE_USER_UNLOCKED, userHandle, 0).sendToTarget();
- }
-
- /**
- * This class manages the clients connected to a given ProfileService
- * and maintains the connection with that service.
- */
- private final class ProfileServiceConnections
- implements ServiceConnection, IBinder.DeathRecipient {
- final RemoteCallbackList<IBluetoothProfileServiceConnection> mProxies =
- new RemoteCallbackList<IBluetoothProfileServiceConnection>();
- IBinder mService;
- ComponentName mClassName;
- Intent mIntent;
- boolean mInvokingProxyCallbacks = false;
-
- ProfileServiceConnections(Intent intent) {
- mService = null;
- mClassName = null;
- mIntent = intent;
- }
-
- private boolean bindService() {
- int state = BluetoothAdapter.STATE_OFF;
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- state = mBluetooth.getState();
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call getState", e);
- return false;
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- if (state != BluetoothAdapter.STATE_ON) {
- if (DBG) {
- Slog.d(TAG, "Unable to bindService while Bluetooth is disabled");
- }
- return false;
- }
-
- if (mIntent != null && mService == null && doBind(mIntent, this, 0,
- UserHandle.CURRENT_OR_SELF)) {
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
- return true;
- }
- Slog.w(TAG, "Unable to bind with intent: " + mIntent);
- return false;
- }
-
- private void addProxy(IBluetoothProfileServiceConnection proxy) {
- mProxies.register(proxy);
- if (mService != null) {
- try {
- proxy.onServiceConnected(mClassName, mService);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to connect to proxy", e);
- }
- } else {
- if (!mHandler.hasMessages(MESSAGE_BIND_PROFILE_SERVICE, this)) {
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessage(msg);
- }
- }
- }
-
- private void removeProxy(IBluetoothProfileServiceConnection proxy) {
- if (proxy != null) {
- if (mProxies.unregister(proxy)) {
- try {
- proxy.onServiceDisconnected(mClassName);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to disconnect proxy", e);
- }
- }
- } else {
- Slog.w(TAG, "Trying to remove a null proxy");
- }
- }
-
- private void removeAllProxies() {
- onServiceDisconnected(mClassName);
- mProxies.kill();
- }
-
- private boolean isEmpty() {
- return mProxies.getRegisteredCallbackCount() == 0;
- }
-
- @Override
- public void onServiceConnected(ComponentName className, IBinder service) {
- // remove timeout message
- mHandler.removeMessages(MESSAGE_BIND_PROFILE_SERVICE, this);
- mService = service;
- mClassName = className;
- try {
- mService.linkToDeath(this, 0);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to linkToDeath", e);
- }
-
- if (mInvokingProxyCallbacks) {
- Slog.e(TAG, "Proxy callbacks already in progress.");
- return;
- }
- mInvokingProxyCallbacks = true;
-
- final int n = mProxies.beginBroadcast();
- try {
- for (int i = 0; i < n; i++) {
- try {
- mProxies.getBroadcastItem(i).onServiceConnected(className, service);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to connect to proxy", e);
- }
- }
- } finally {
- mProxies.finishBroadcast();
- mInvokingProxyCallbacks = false;
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName className) {
- if (mService == null) {
- return;
- }
- try {
- mService.unlinkToDeath(this, 0);
- } catch (NoSuchElementException e) {
- Log.e(TAG, "error unlinking to death", e);
- }
- mService = null;
- mClassName = null;
-
- if (mInvokingProxyCallbacks) {
- Slog.e(TAG, "Proxy callbacks already in progress.");
- return;
- }
- mInvokingProxyCallbacks = true;
-
- final int n = mProxies.beginBroadcast();
- try {
- for (int i = 0; i < n; i++) {
- try {
- mProxies.getBroadcastItem(i).onServiceDisconnected(className);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to disconnect from proxy", e);
- }
- }
- } finally {
- mProxies.finishBroadcast();
- mInvokingProxyCallbacks = false;
- }
- }
-
- @Override
- public void binderDied() {
- if (DBG) {
- Slog.w(TAG, "Profile service for profile: " + mClassName + " died.");
- }
- onServiceDisconnected(mClassName);
- // Trigger rebind
- Message msg = mHandler.obtainMessage(MESSAGE_BIND_PROFILE_SERVICE);
- msg.obj = this;
- mHandler.sendMessageDelayed(msg, TIMEOUT_BIND_MS);
- }
- }
-
- private void sendBluetoothStateCallback(boolean isUp) {
- try {
- int n = mStateChangeCallbacks.beginBroadcast();
- if (DBG) {
- Slog.d(TAG, "Broadcasting onBluetoothStateChange(" + isUp + ") to " + n
- + " receivers.");
- }
- for (int i = 0; i < n; i++) {
- try {
- mStateChangeCallbacks.getBroadcastItem(i).onBluetoothStateChange(isUp);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e);
- }
- }
- } finally {
- mStateChangeCallbacks.finishBroadcast();
- }
- }
-
- /**
- * Inform BluetoothAdapter instances that Adapter service is up
- */
- private void sendBluetoothServiceUpCallback() {
- synchronized (mCallbacks) {
- try {
- int n = mCallbacks.beginBroadcast();
- Slog.d(TAG, "Broadcasting onBluetoothServiceUp() to " + n + " receivers.");
- for (int i = 0; i < n; i++) {
- try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceUp(mBluetooth);
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBluetoothServiceUp() on callback #" + i, e);
- }
- }
- } finally {
- mCallbacks.finishBroadcast();
- }
- }
- }
-
- /**
- * Inform BluetoothAdapter instances that Adapter service is down
- */
- private void sendBluetoothServiceDownCallback() {
- synchronized (mCallbacks) {
- try {
- int n = mCallbacks.beginBroadcast();
- Slog.d(TAG, "Broadcasting onBluetoothServiceDown() to " + n + " receivers.");
- for (int i = 0; i < n; i++) {
- try {
- mCallbacks.getBroadcastItem(i).onBluetoothServiceDown();
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call onBluetoothServiceDown() on callback #" + i, e);
- }
- }
- } finally {
- mCallbacks.finishBroadcast();
- }
- }
- }
-
- public String getAddress(AttributionSource attributionSource) {
- if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getAddress")) {
- return null;
- }
-
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG, "getAddress(): not allowed for non-active and non system user");
- return null;
- }
-
- if (mContext.checkCallingOrSelfPermission(Manifest.permission.LOCAL_MAC_ADDRESS)
- != PackageManager.PERMISSION_GRANTED) {
- return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
- }
-
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- return mBluetooth.getAddressWithAttribution(attributionSource);
- }
- } catch (RemoteException e) {
- Slog.e(TAG,
- "getAddress(): Unable to retrieve address remotely. Returning cached address",
- e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- // mAddress is accessed from outside.
- // It is alright without a lock. Here, bluetooth is off, no other thread is
- // changing mAddress
- return mAddress;
- }
-
- public String getName(AttributionSource attributionSource) {
- if (!checkConnectPermissionForDataDelivery(mContext, attributionSource, "getName")) {
- return null;
- }
-
- if ((Binder.getCallingUid() != Process.SYSTEM_UID) && (!checkIfCallerIsForegroundUser())) {
- Slog.w(TAG, "getName(): not allowed for non-active and non system user");
- return null;
- }
-
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- return mBluetooth.getName(attributionSource);
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "getName(): Unable to retrieve name remotely. Returning cached name", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- // mName is accessed from outside.
- // It alright without a lock. Here, bluetooth is off, no other thread is
- // changing mName
- return mName;
- }
-
- private class BluetoothServiceConnection implements ServiceConnection {
- public void onServiceConnected(ComponentName componentName, IBinder service) {
- String name = componentName.getClassName();
- if (DBG) {
- Slog.d(TAG, "BluetoothServiceConnection: " + name);
- }
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
- if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
- msg.arg1 = SERVICE_IBLUETOOTH;
- } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
- msg.arg1 = SERVICE_IBLUETOOTHGATT;
- } else {
- Slog.e(TAG, "Unknown service connected: " + name);
- return;
- }
- msg.obj = service;
- mHandler.sendMessage(msg);
- }
-
- public void onServiceDisconnected(ComponentName componentName) {
- // Called if we unexpectedly disconnect.
- String name = componentName.getClassName();
- if (DBG) {
- Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);
- }
- Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
- if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
- msg.arg1 = SERVICE_IBLUETOOTH;
- } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
- msg.arg1 = SERVICE_IBLUETOOTHGATT;
- } else {
- Slog.e(TAG, "Unknown service disconnected: " + name);
- return;
- }
- mHandler.sendMessage(msg);
- }
- }
-
- private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
-
- private class BluetoothHandler extends Handler {
- boolean mGetNameAddressOnly = false;
- private int mWaitForEnableRetry;
- private int mWaitForDisableRetry;
-
- BluetoothHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MESSAGE_GET_NAME_AND_ADDRESS:
- if (DBG) {
- Slog.d(TAG, "MESSAGE_GET_NAME_AND_ADDRESS");
- }
- try {
- mBluetoothLock.writeLock().lock();
- if ((mBluetooth == null) && (!mBinding)) {
- if (DBG) {
- Slog.d(TAG, "Binding to service to get name and address");
- }
- mGetNameAddressOnly = true;
- Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
- mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
- Intent i = new Intent(IBluetooth.class.getName());
- if (!doBind(i, mConnection,
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.CURRENT)) {
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
- } else {
- mBinding = true;
- }
- } else if (mBluetooth != null) {
- try {
- storeNameAndAddress(
- mBluetooth.getName(mContext.getAttributionSource()),
- mBluetooth.getAddressWithAttribution(
- mContext.getAttributionSource()));
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to grab names", re);
- }
- if (mGetNameAddressOnly && !mEnable) {
- unbindAndFinish();
- }
- mGetNameAddressOnly = false;
- }
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
- break;
-
- case MESSAGE_ENABLE:
- int quietEnable = msg.arg1;
- int isBle = msg.arg2;
- if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED)
- || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
- // We are handling enable or disable right now, wait for it.
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ENABLE,
- quietEnable, isBle), ENABLE_DISABLE_DELAY_MS);
- break;
- }
-
- if (DBG) {
- Slog.d(TAG, "MESSAGE_ENABLE(" + quietEnable + "): mBluetooth = "
- + mBluetooth);
- }
- mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mEnable = true;
-
- if (isBle == 0) {
- persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
- }
-
- // Use service interface to get the exact state
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- boolean isHandled = true;
- int state = mBluetooth.getState();
- switch (state) {
- case BluetoothAdapter.STATE_BLE_ON:
- if (isBle == 1) {
- Slog.i(TAG, "Already at BLE_ON State");
- } else {
- Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
- mBluetooth.onLeServiceUp(mContext.getAttributionSource());
- }
- break;
- case BluetoothAdapter.STATE_BLE_TURNING_ON:
- case BluetoothAdapter.STATE_TURNING_ON:
- case BluetoothAdapter.STATE_ON:
- Slog.i(TAG, "MESSAGE_ENABLE: already enabled");
- break;
- default:
- isHandled = false;
- break;
- }
- if (isHandled) break;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- mQuietEnable = (quietEnable == 1);
- if (mBluetooth == null) {
- handleEnable(mQuietEnable);
- } else {
- //
- // We need to wait until transitioned to STATE_OFF and
- // the previous Bluetooth process has exited. The
- // waiting period has three components:
- // (a) Wait until the local state is STATE_OFF. This
- // is accomplished by sending delay a message
- // MESSAGE_HANDLE_ENABLE_DELAYED
- // (b) Wait until the STATE_OFF state is updated to
- // all components.
- // (c) Wait until the Bluetooth process exits, and
- // ActivityManager detects it.
- // The waiting for (b) and (c) is accomplished by
- // delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE
- // message. The delay time is backed off if Bluetooth
- // continuously failed to turn on itself.
- //
- mWaitForEnableRetry = 0;
- Message enableDelayedMsg =
- mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
- mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
- }
- break;
-
- case MESSAGE_DISABLE:
- if (mHandler.hasMessages(MESSAGE_HANDLE_DISABLE_DELAYED) || mBinding
- || mHandler.hasMessages(MESSAGE_HANDLE_ENABLE_DELAYED)) {
- // We are handling enable or disable right now, wait for it.
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_DISABLE),
- ENABLE_DISABLE_DELAY_MS);
- break;
- }
-
- if (DBG) {
- Slog.d(TAG, "MESSAGE_DISABLE: mBluetooth = " + mBluetooth
- + ", mBinding = " + mBinding);
- }
- mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
-
- if (mEnable && mBluetooth != null) {
- mWaitForDisableRetry = 0;
- Message disableDelayedMsg =
- mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
- mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
- } else {
- mEnable = false;
- handleDisable();
- }
- break;
-
- case MESSAGE_HANDLE_ENABLE_DELAYED: {
- // The Bluetooth is turning off, wait for STATE_OFF
- if (mState != BluetoothAdapter.STATE_OFF) {
- if (mWaitForEnableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
- mWaitForEnableRetry++;
- Message enableDelayedMsg =
- mHandler.obtainMessage(MESSAGE_HANDLE_ENABLE_DELAYED);
- mHandler.sendMessageDelayed(enableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
- break;
- } else {
- Slog.e(TAG, "Wait for STATE_OFF timeout");
- }
- }
- // Either state is changed to STATE_OFF or reaches the maximum retry, we
- // should move forward to the next step.
- mWaitForEnableRetry = 0;
- Message restartMsg =
- mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
- Slog.d(TAG, "Handle enable is finished");
- break;
- }
-
- case MESSAGE_HANDLE_DISABLE_DELAYED: {
- boolean disabling = (msg.arg1 == 1);
- Slog.d(TAG, "MESSAGE_HANDLE_DISABLE_DELAYED: disabling:" + disabling);
- if (!disabling) {
- // The Bluetooth is turning on, wait for STATE_ON
- if (mState != BluetoothAdapter.STATE_ON) {
- if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
- mWaitForDisableRetry++;
- Message disableDelayedMsg = mHandler.obtainMessage(
- MESSAGE_HANDLE_DISABLE_DELAYED, 0, 0);
- mHandler.sendMessageDelayed(disableDelayedMsg,
- ENABLE_DISABLE_DELAY_MS);
- break;
- } else {
- Slog.e(TAG, "Wait for STATE_ON timeout");
- }
- }
- // Either state is changed to STATE_ON or reaches the maximum retry, we
- // should move forward to the next step.
- mWaitForDisableRetry = 0;
- mEnable = false;
- handleDisable();
- // Wait for state exiting STATE_ON
- Message disableDelayedMsg =
- mHandler.obtainMessage(MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
- mHandler.sendMessageDelayed(disableDelayedMsg, ENABLE_DISABLE_DELAY_MS);
- } else {
- // The Bluetooth is turning off, wait for exiting STATE_ON
- if (mState == BluetoothAdapter.STATE_ON) {
- if (mWaitForDisableRetry < MAX_WAIT_FOR_ENABLE_DISABLE_RETRIES) {
- mWaitForDisableRetry++;
- Message disableDelayedMsg = mHandler.obtainMessage(
- MESSAGE_HANDLE_DISABLE_DELAYED, 1, 0);
- mHandler.sendMessageDelayed(disableDelayedMsg,
- ENABLE_DISABLE_DELAY_MS);
- break;
- } else {
- Slog.e(TAG, "Wait for exiting STATE_ON timeout");
- }
- }
- // Either state is exited from STATE_ON or reaches the maximum retry, we
- // should move forward to the next step.
- Slog.d(TAG, "Handle disable is finished");
- }
- break;
- }
-
- case MESSAGE_RESTORE_USER_SETTING:
- if ((msg.arg1 == RESTORE_SETTING_TO_OFF) && mEnable) {
- if (DBG) {
- Slog.d(TAG, "Restore Bluetooth state to disabled");
- }
- persistBluetoothSetting(BLUETOOTH_OFF);
- mEnableExternal = false;
- sendDisableMsg(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING,
- mContext.getPackageName());
- } else if ((msg.arg1 == RESTORE_SETTING_TO_ON) && !mEnable) {
- if (DBG) {
- Slog.d(TAG, "Restore Bluetooth state to enabled");
- }
- mQuietEnableExternal = false;
- mEnableExternal = true;
- // waive WRITE_SECURE_SETTINGS permission check
- sendEnableMsg(false,
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING,
- mContext.getPackageName());
- }
- break;
- case MESSAGE_REGISTER_STATE_CHANGE_CALLBACK: {
- IBluetoothStateChangeCallback callback =
- (IBluetoothStateChangeCallback) msg.obj;
- mStateChangeCallbacks.register(callback);
- break;
- }
- case MESSAGE_UNREGISTER_STATE_CHANGE_CALLBACK: {
- IBluetoothStateChangeCallback callback =
- (IBluetoothStateChangeCallback) msg.obj;
- mStateChangeCallbacks.unregister(callback);
- break;
- }
- case MESSAGE_ADD_PROXY_DELAYED: {
- ProfileServiceConnections psc = mProfileServices.get(msg.arg1);
- if (psc == null) {
- break;
- }
- IBluetoothProfileServiceConnection proxy =
- (IBluetoothProfileServiceConnection) msg.obj;
- psc.addProxy(proxy);
- break;
- }
- case MESSAGE_BIND_PROFILE_SERVICE: {
- ProfileServiceConnections psc = (ProfileServiceConnections) msg.obj;
- removeMessages(MESSAGE_BIND_PROFILE_SERVICE, msg.obj);
- if (psc == null) {
- break;
- }
- psc.bindService();
- break;
- }
- case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
- if (DBG) {
- Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
- }
-
- IBinder service = (IBinder) msg.obj;
- try {
- mBluetoothLock.writeLock().lock();
- if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt =
- IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
- continueFromBleOnState();
- break;
- } // else must be SERVICE_IBLUETOOTH
-
- //Remove timeout
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
-
- mBinding = false;
- mBluetoothBinder = service;
- mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));
-
- if (!isNameAndAddressSet()) {
- Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
- mHandler.sendMessage(getMsg);
- if (mGetNameAddressOnly) {
- return;
- }
- }
-
- //Register callback object
- try {
- mBluetooth.registerCallback(mBluetoothCallback,
- mContext.getAttributionSource());
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to register BluetoothCallback", re);
- }
- //Inform BluetoothAdapter instances that service is up
- sendBluetoothServiceUpCallback();
-
- //Do enable request
- try {
- if (!mBluetooth.enable(mQuietEnable, mContext.getAttributionSource())) {
- Slog.e(TAG, "IBluetooth.enable() returned false");
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call enable()", e);
- }
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
- if (!mEnable) {
- waitForState(Set.of(BluetoothAdapter.STATE_ON));
- handleDisable();
- waitForState(Set.of(BluetoothAdapter.STATE_OFF,
- BluetoothAdapter.STATE_TURNING_ON,
- BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_BLE_TURNING_ON,
- BluetoothAdapter.STATE_BLE_ON,
- BluetoothAdapter.STATE_BLE_TURNING_OFF));
- }
- break;
- }
- case MESSAGE_BLUETOOTH_STATE_CHANGE: {
- int prevState = msg.arg1;
- int newState = msg.arg2;
- if (DBG) {
- Slog.d(TAG,
- "MESSAGE_BLUETOOTH_STATE_CHANGE: " + BluetoothAdapter.nameForState(
- prevState) + " > " + BluetoothAdapter.nameForState(
- newState));
- }
- mState = newState;
- bluetoothStateChangeHandler(prevState, newState);
- // handle error state transition case from TURNING_ON to OFF
- // unbind and rebind bluetooth service and enable bluetooth
- if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_ON) && (newState
- == BluetoothAdapter.STATE_OFF) && (mBluetooth != null) && mEnable) {
- recoverBluetoothServiceFromError(false);
- }
- if ((prevState == BluetoothAdapter.STATE_TURNING_ON) && (newState
- == BluetoothAdapter.STATE_BLE_ON) && (mBluetooth != null) && mEnable) {
- recoverBluetoothServiceFromError(true);
- }
- // If we tried to enable BT while BT was in the process of shutting down,
- // wait for the BT process to fully tear down and then force a restart
- // here. This is a bit of a hack (b/29363429).
- if ((prevState == BluetoothAdapter.STATE_BLE_TURNING_OFF) && (newState
- == BluetoothAdapter.STATE_OFF)) {
- if (mEnable) {
- Slog.d(TAG, "Entering STATE_OFF but mEnabled is true; restarting.");
- waitForState(Set.of(BluetoothAdapter.STATE_OFF));
- Message restartMsg =
- mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
- }
- }
- if (newState == BluetoothAdapter.STATE_ON
- || newState == BluetoothAdapter.STATE_BLE_ON) {
- // bluetooth is working, reset the counter
- if (mErrorRecoveryRetryCounter != 0) {
- Slog.w(TAG, "bluetooth is recovered from error");
- mErrorRecoveryRetryCounter = 0;
- }
- }
- break;
- }
- case MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED: {
- Slog.e(TAG, "MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED(" + msg.arg1 + ")");
- try {
- mBluetoothLock.writeLock().lock();
- if (msg.arg1 == SERVICE_IBLUETOOTH) {
- // if service is unbinded already, do nothing and return
- if (mBluetooth == null) {
- break;
- }
- mBluetooth = null;
- } else if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
- mBluetoothGatt = null;
- break;
- } else {
- Slog.e(TAG, "Unknown argument for service disconnect!");
- break;
- }
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
- // log the unexpected crash
- addCrashLog();
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH,
- mContext.getPackageName(), false);
- if (mEnable) {
- mEnable = false;
- // Send a Bluetooth Restart message
- Message restartMsg =
- mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, getServiceRestartMs());
- }
-
- sendBluetoothServiceDownCallback();
-
- // Send BT state broadcast to update
- // the BT icon correctly
- if ((mState == BluetoothAdapter.STATE_TURNING_ON) || (mState
- == BluetoothAdapter.STATE_ON)) {
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
- mState = BluetoothAdapter.STATE_TURNING_OFF;
- }
- if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
- break;
- }
- case MESSAGE_RESTART_BLUETOOTH_SERVICE: {
- mErrorRecoveryRetryCounter++;
- Slog.d(TAG, "MESSAGE_RESTART_BLUETOOTH_SERVICE: retry count="
- + mErrorRecoveryRetryCounter);
- if (mErrorRecoveryRetryCounter < MAX_ERROR_RESTART_RETRIES) {
- /* Enable without persisting the setting as
- it doesnt change when IBluetooth
- service restarts */
- mEnable = true;
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED,
- mContext.getPackageName(), true);
- handleEnable(mQuietEnable);
- } else {
- Slog.e(TAG, "Reach maximum retry to restart Bluetooth!");
- }
- break;
- }
- case MESSAGE_TIMEOUT_BIND: {
- Slog.e(TAG, "MESSAGE_TIMEOUT_BIND");
- mBluetoothLock.writeLock().lock();
- mBinding = false;
- mBluetoothLock.writeLock().unlock();
- break;
- }
- case MESSAGE_TIMEOUT_UNBIND: {
- Slog.e(TAG, "MESSAGE_TIMEOUT_UNBIND");
- mBluetoothLock.writeLock().lock();
- mUnbinding = false;
- mBluetoothLock.writeLock().unlock();
- break;
- }
-
- case MESSAGE_USER_SWITCHED: {
- if (DBG) {
- Slog.d(TAG, "MESSAGE_USER_SWITCHED");
- }
- mHandler.removeMessages(MESSAGE_USER_SWITCHED);
-
- /* disable and enable BT when detect a user switch */
- if (mBluetooth != null && isEnabled()) {
- restartForReason(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH);
- } else if (mBinding || mBluetooth != null) {
- Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
- userMsg.arg2 = 1 + msg.arg2;
- // if user is switched when service is binding retry after a delay
- mHandler.sendMessageDelayed(userMsg, USER_SWITCHED_TIME_MS);
- if (DBG) {
- Slog.d(TAG, "Retry MESSAGE_USER_SWITCHED " + userMsg.arg2);
- }
- }
- break;
- }
- case MESSAGE_USER_UNLOCKED: {
- if (DBG) {
- Slog.d(TAG, "MESSAGE_USER_UNLOCKED");
- }
- mHandler.removeMessages(MESSAGE_USER_SWITCHED);
-
- if (mEnable && !mBinding && (mBluetooth == null)) {
- // We should be connected, but we gave up for some
- // reason; maybe the Bluetooth service wasn't encryption
- // aware, so try binding again.
- if (DBG) {
- Slog.d(TAG, "Enabled but not bound; retrying after unlock");
- }
- handleEnable(mQuietEnable);
- }
- break;
- }
- case MESSAGE_INIT_FLAGS_CHANGED: {
- if (DBG) {
- Slog.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED");
- }
- mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
- if (mBluetoothModeChangeHelper.isMediaProfileConnected()) {
- Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
- + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
- + " ms due to existing connections");
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_INIT_FLAGS_CHANGED,
- DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS);
- break;
- }
- if (!isDeviceProvisioned()) {
- Slog.i(TAG, "Delaying MESSAGE_INIT_FLAGS_CHANGED by "
- + DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS
- + "ms because device is not provisioned");
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_INIT_FLAGS_CHANGED,
- DELAY_FOR_RETRY_INIT_FLAG_CHECK_MS);
- break;
- }
- if (mBluetooth != null && isEnabled()) {
- Slog.i(TAG, "Restarting Bluetooth due to init flag change");
- restartForReason(
- BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED);
- }
- break;
- }
- }
- }
-
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED
- })
- private void restartForReason(int reason) {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- mBluetooth.unregisterCallback(mBluetoothCallback,
- mContext.getAttributionSource());
- }
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to unregister", re);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
- // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
- mState = BluetoothAdapter.STATE_OFF;
- }
- if (mState == BluetoothAdapter.STATE_OFF) {
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
- mState = BluetoothAdapter.STATE_TURNING_ON;
- }
-
- waitForState(Set.of(BluetoothAdapter.STATE_ON));
-
- if (mState == BluetoothAdapter.STATE_TURNING_ON) {
- bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
- }
-
- unbindAllBluetoothProfileServices();
- // disable
- addActiveLog(reason, mContext.getPackageName(), false);
- handleDisable();
- // Pbap service need receive STATE_TURNING_OFF intent to close
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
- BluetoothAdapter.STATE_TURNING_OFF);
-
- boolean didDisableTimeout =
- !waitForState(Set.of(BluetoothAdapter.STATE_OFF));
-
- bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
- BluetoothAdapter.STATE_OFF);
- sendBluetoothServiceDownCallback();
-
- try {
- mBluetoothLock.writeLock().lock();
- if (mBluetooth != null) {
- mBluetooth = null;
- // Unbind
- mContext.unbindService(mConnection);
- }
- mBluetoothGatt = null;
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
- //
- // If disabling Bluetooth times out, wait for an
- // additional amount of time to ensure the process is
- // shut down completely before attempting to restart.
- //
- if (didDisableTimeout) {
- SystemClock.sleep(3000);
- } else {
- SystemClock.sleep(100);
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
- // enable
- addActiveLog(reason, mContext.getPackageName(), true);
- // mEnable flag could have been reset on disableBLE. Reenable it.
- mEnable = true;
- handleEnable(mQuietEnable);
- }
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private void handleEnable(boolean quietMode) {
- mQuietEnable = quietMode;
-
- try {
- mBluetoothLock.writeLock().lock();
- if ((mBluetooth == null) && (!mBinding)) {
- Slog.d(TAG, "binding Bluetooth service");
- //Start bind timeout and bind
- Message timeoutMsg = mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
- mHandler.sendMessageDelayed(timeoutMsg, TIMEOUT_BIND_MS);
- Intent i = new Intent(IBluetooth.class.getName());
- if (!doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.CURRENT)) {
- mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
- } else {
- mBinding = true;
- }
- } else if (mBluetooth != null) {
- //Enable bluetooth
- try {
- if (!mBluetooth.enable(mQuietEnable, mContext.getAttributionSource())) {
- Slog.e(TAG, "IBluetooth.enable() returned false");
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call enable()", e);
- }
- }
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
- }
-
- boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
- ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
- intent.setComponent(comp);
- if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
- Slog.e(TAG, "Fail to bind to: " + intent);
- return false;
- }
- return true;
- }
-
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- private void handleDisable() {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- if (DBG) {
- Slog.d(TAG, "Sending off request.");
- }
- if (!mBluetooth.disable(mContext.getAttributionSource())) {
- Slog.e(TAG, "IBluetooth.disable() returned false");
- }
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "Unable to call disable()", e);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- }
-
- private boolean checkIfCallerIsForegroundUser() {
- int foregroundUser;
- int callingUser = UserHandle.getCallingUserId();
- int callingUid = Binder.getCallingUid();
- final long callingIdentity = Binder.clearCallingIdentity();
- UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- UserInfo ui = um.getProfileParent(callingUser);
- int parentUser = (ui != null) ? ui.id : UserHandle.USER_NULL;
- int callingAppId = UserHandle.getAppId(callingUid);
- boolean valid = false;
- try {
- foregroundUser = ActivityManager.getCurrentUser();
- valid = (callingUser == foregroundUser) || parentUser == foregroundUser
- || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid
- || callingAppId == Process.SHELL_UID;
- if (DBG && !valid) {
- Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser="
- + callingUser + " parentUser=" + parentUser + " foregroundUser="
- + foregroundUser);
- }
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- return valid;
- }
-
- private void sendBleStateChanged(int prevState, int newState) {
- if (DBG) {
- Slog.d(TAG,
- "Sending BLE State Change: " + BluetoothAdapter.nameForState(prevState) + " > "
- + BluetoothAdapter.nameForState(newState));
- }
- // Send broadcast message to everyone else
- Intent intent = new Intent(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
- intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
- intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null, getTempAllowlistBroadcastOptions());
- }
-
- private boolean isBleState(int state) {
- switch (state) {
- case BluetoothAdapter.STATE_BLE_ON:
- case BluetoothAdapter.STATE_BLE_TURNING_ON:
- case BluetoothAdapter.STATE_BLE_TURNING_OFF:
- return true;
- }
- return false;
- }
-
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- private void bluetoothStateChangeHandler(int prevState, int newState) {
- boolean isStandardBroadcast = true;
- if (prevState == newState) { // No change. Nothing to do.
- return;
- }
- // Notify all proxy objects first of adapter state change
- if (newState == BluetoothAdapter.STATE_BLE_ON || newState == BluetoothAdapter.STATE_OFF) {
- boolean intermediate_off = (prevState == BluetoothAdapter.STATE_TURNING_OFF
- && newState == BluetoothAdapter.STATE_BLE_ON);
-
- if (newState == BluetoothAdapter.STATE_OFF) {
- // If Bluetooth is off, send service down event to proxy objects, and unbind
- if (DBG) {
- Slog.d(TAG, "Bluetooth is complete send Service Down");
- }
- sendBluetoothServiceDownCallback();
- unbindAndFinish();
- sendBleStateChanged(prevState, newState);
-
- /* Currently, the OFF intent is broadcasted externally only when we transition
- * from TURNING_OFF to BLE_ON state. So if the previous state is a BLE state,
- * we are guaranteed that the OFF intent has been broadcasted earlier and we
- * can safely skip it.
- * Conversely, if the previous state is not a BLE state, it indicates that some
- * sort of crash has occurred, moving us directly to STATE_OFF without ever
- * passing through BLE_ON. We should broadcast the OFF intent in this case. */
- isStandardBroadcast = !isBleState(prevState);
-
- } else if (!intermediate_off) {
- // connect to GattService
- if (DBG) {
- Slog.d(TAG, "Bluetooth is in LE only mode");
- }
- if (mBluetoothGatt != null || !mContext.getPackageManager()
- .hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
- continueFromBleOnState();
- } else {
- if (DBG) {
- Slog.d(TAG, "Binding Bluetooth GATT service");
- }
- Intent i = new Intent(IBluetoothGatt.class.getName());
- doBind(i, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
- UserHandle.CURRENT);
- }
- sendBleStateChanged(prevState, newState);
- //Don't broadcase this as std intent
- isStandardBroadcast = false;
-
- } else if (intermediate_off) {
- if (DBG) {
- Slog.d(TAG, "Intermediate off, back to LE only mode");
- }
- // For LE only mode, broadcast as is
- sendBleStateChanged(prevState, newState);
- sendBluetoothStateCallback(false); // BT is OFF for general users
- // Broadcast as STATE_OFF
- newState = BluetoothAdapter.STATE_OFF;
- sendBrEdrDownCallback(mContext.getAttributionSource());
- }
- } else if (newState == BluetoothAdapter.STATE_ON) {
- boolean isUp = (newState == BluetoothAdapter.STATE_ON);
- sendBluetoothStateCallback(isUp);
- sendBleStateChanged(prevState, newState);
-
- } else if (newState == BluetoothAdapter.STATE_BLE_TURNING_ON
- || newState == BluetoothAdapter.STATE_BLE_TURNING_OFF) {
- sendBleStateChanged(prevState, newState);
- isStandardBroadcast = false;
-
- } else if (newState == BluetoothAdapter.STATE_TURNING_ON
- || newState == BluetoothAdapter.STATE_TURNING_OFF) {
- sendBleStateChanged(prevState, newState);
- }
-
- if (isStandardBroadcast) {
- if (prevState == BluetoothAdapter.STATE_BLE_ON) {
- // Show prevState of BLE_ON as OFF to standard users
- prevState = BluetoothAdapter.STATE_OFF;
- }
- if (DBG) {
- Slog.d(TAG,
- "Sending State Change: " + BluetoothAdapter.nameForState(prevState) + " > "
- + BluetoothAdapter.nameForState(newState));
- }
- Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
- intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, prevState);
- intent.putExtra(BluetoothAdapter.EXTRA_STATE, newState);
- intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL, null,
- getTempAllowlistBroadcastOptions());
- }
- }
-
- private boolean waitForState(Set<Integer> states) {
- int i = 0;
- while (i < 10) {
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth == null) {
- break;
- }
- if (states.contains(mBluetooth.getState())) {
- return true;
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "getState()", e);
- break;
- } finally {
- mBluetoothLock.readLock().unlock();
- }
- SystemClock.sleep(300);
- i++;
- }
- Slog.e(TAG, "waitForState " + states + " time out");
- return false;
- }
-
- private void sendDisableMsg(int reason, String packageName) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_DISABLE));
- addActiveLog(reason, packageName, false);
- }
-
- private void sendEnableMsg(boolean quietMode, int reason, String packageName) {
- sendEnableMsg(quietMode, reason, packageName, false);
- }
-
- private void sendEnableMsg(boolean quietMode, int reason, String packageName, boolean isBle) {
- mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0,
- isBle ? 1 : 0));
- addActiveLog(reason, packageName, true);
- mLastEnabledTime = SystemClock.elapsedRealtime();
- }
-
- private void addActiveLog(int reason, String packageName, boolean enable) {
- synchronized (mActiveLogs) {
- if (mActiveLogs.size() > ACTIVE_LOG_MAX_SIZE) {
- mActiveLogs.remove();
- }
- mActiveLogs.add(
- new ActiveLog(reason, packageName, enable, System.currentTimeMillis()));
- }
-
- int state = enable ? FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED :
- FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED;
- FrameworkStatsLog.write_non_chained(FrameworkStatsLog.BLUETOOTH_ENABLED_STATE_CHANGED,
- Binder.getCallingUid(), null, state, reason, packageName);
- }
-
- private void addCrashLog() {
- synchronized (mCrashTimestamps) {
- if (mCrashTimestamps.size() == CRASH_LOG_MAX_SIZE) {
- mCrashTimestamps.removeFirst();
- }
- mCrashTimestamps.add(System.currentTimeMillis());
- mCrashes++;
- }
- }
-
- @RequiresPermission(allOf = {
- android.Manifest.permission.BLUETOOTH_CONNECT,
- android.Manifest.permission.BLUETOOTH_PRIVILEGED,
- })
- private void recoverBluetoothServiceFromError(boolean clearBle) {
- Slog.e(TAG, "recoverBluetoothServiceFromError");
- try {
- mBluetoothLock.readLock().lock();
- if (mBluetooth != null) {
- //Unregister callback object
- mBluetooth.unregisterCallback(mBluetoothCallback, mContext.getAttributionSource());
- }
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to unregister", re);
- } finally {
- mBluetoothLock.readLock().unlock();
- }
-
- SystemClock.sleep(500);
-
- // disable
- addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR,
- mContext.getPackageName(), false);
- handleDisable();
-
- waitForState(Set.of(BluetoothAdapter.STATE_OFF));
-
- sendBluetoothServiceDownCallback();
-
- try {
- mBluetoothLock.writeLock().lock();
- if (mBluetooth != null) {
- mBluetooth = null;
- // Unbind
- mContext.unbindService(mConnection);
- }
- mBluetoothGatt = null;
- } finally {
- mBluetoothLock.writeLock().unlock();
- }
-
- mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
- mState = BluetoothAdapter.STATE_OFF;
-
- if (clearBle) {
- clearBleApps();
- }
-
- mEnable = false;
-
- // Send a Bluetooth Restart message to reenable bluetooth
- Message restartMsg = mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
- mHandler.sendMessageDelayed(restartMsg, ERROR_RESTART_TIME_MS);
- }
-
- private boolean isBluetoothDisallowed() {
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- return mContext.getSystemService(UserManager.class)
- .hasUserRestriction(UserManager.DISALLOW_BLUETOOTH, UserHandle.SYSTEM);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
-
- /**
- * Disables BluetoothOppLauncherActivity component, so the Bluetooth sharing option is not
- * offered to the user if Bluetooth or sharing is disallowed. Puts the component to its default
- * state if Bluetooth is not disallowed.
- *
- * @param userId user to disable bluetooth sharing for.
- * @param bluetoothSharingDisallowed whether bluetooth sharing is disallowed.
- */
- private void updateOppLauncherComponentState(int userId, boolean bluetoothSharingDisallowed) {
- final ComponentName oppLauncherComponent = new ComponentName("com.android.bluetooth",
- "com.android.bluetooth.opp.BluetoothOppLauncherActivity");
- final int newState =
- bluetoothSharingDisallowed ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
- try {
- final IPackageManager imp = AppGlobals.getPackageManager();
- imp.setComponentEnabledSetting(oppLauncherComponent, newState,
- PackageManager.DONT_KILL_APP, userId);
- } catch (Exception e) {
- // The component was not found, do nothing.
- }
- }
-
- private int getServiceRestartMs() {
- return (mErrorRecoveryRetryCounter + 1) * SERVICE_RESTART_TIME_MS;
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) {
- return;
- }
- if ((args.length > 0) && args[0].startsWith("--proto")) {
- dumpProto(fd);
- return;
- }
- String errorMsg = null;
-
- writer.println("Bluetooth Status");
- writer.println(" enabled: " + isEnabled());
- writer.println(" state: " + BluetoothAdapter.nameForState(mState));
- writer.println(" address: " + mAddress);
- writer.println(" name: " + mName);
- if (mEnable) {
- long onDuration = SystemClock.elapsedRealtime() - mLastEnabledTime;
- String onDurationString = String.format(Locale.US, "%02d:%02d:%02d.%03d",
- (int) (onDuration / (1000 * 60 * 60)),
- (int) ((onDuration / (1000 * 60)) % 60), (int) ((onDuration / 1000) % 60),
- (int) (onDuration % 1000));
- writer.println(" time since enabled: " + onDurationString);
- }
-
- if (mActiveLogs.size() == 0) {
- writer.println("\nBluetooth never enabled!");
- } else {
- writer.println("\nEnable log:");
- for (ActiveLog log : mActiveLogs) {
- writer.println(" " + log);
- }
- }
-
- writer.println(
- "\nBluetooth crashed " + mCrashes + " time" + (mCrashes == 1 ? "" : "s"));
- if (mCrashes == CRASH_LOG_MAX_SIZE) {
- writer.println("(last " + CRASH_LOG_MAX_SIZE + ")");
- }
- for (Long time : mCrashTimestamps) {
- writer.println(" " + timeToLog(time));
- }
-
- writer.println("\n" + mBleApps.size() + " BLE app" + (mBleApps.size() == 1 ? "" : "s")
- + " registered");
- for (ClientDeathRecipient app : mBleApps.values()) {
- writer.println(" " + app.getPackageName());
- }
-
- writer.println("\nBluetoothManagerService:");
- writer.println(" mEnable:" + mEnable);
- writer.println(" mQuietEnable:" + mQuietEnable);
- writer.println(" mEnableExternal:" + mEnableExternal);
- writer.println(" mQuietEnableExternal:" + mQuietEnableExternal);
-
- writer.println("");
- writer.flush();
- if (args.length == 0) {
- // Add arg to produce output
- args = new String[1];
- args[0] = "--print";
- }
-
- if (mBluetoothBinder == null) {
- errorMsg = "Bluetooth Service not connected";
- } else {
- try {
- mBluetoothBinder.dump(fd, args);
- } catch (RemoteException re) {
- errorMsg = "RemoteException while dumping Bluetooth Service";
- }
- }
- if (errorMsg != null) {
- writer.println(errorMsg);
- }
- }
-
- private void dumpProto(FileDescriptor fd) {
- final ProtoOutputStream proto = new ProtoOutputStream(fd);
- proto.write(BluetoothManagerServiceDumpProto.ENABLED, isEnabled());
- proto.write(BluetoothManagerServiceDumpProto.STATE, mState);
- proto.write(BluetoothManagerServiceDumpProto.STATE_NAME,
- BluetoothAdapter.nameForState(mState));
- proto.write(BluetoothManagerServiceDumpProto.ADDRESS, mAddress);
- proto.write(BluetoothManagerServiceDumpProto.NAME, mName);
- if (mEnable) {
- proto.write(BluetoothManagerServiceDumpProto.LAST_ENABLED_TIME_MS, mLastEnabledTime);
- }
- proto.write(BluetoothManagerServiceDumpProto.CURR_TIMESTAMP_MS,
- SystemClock.elapsedRealtime());
- for (ActiveLog log : mActiveLogs) {
- long token = proto.start(BluetoothManagerServiceDumpProto.ACTIVE_LOGS);
- log.dump(proto);
- proto.end(token);
- }
- proto.write(BluetoothManagerServiceDumpProto.NUM_CRASHES, mCrashes);
- proto.write(BluetoothManagerServiceDumpProto.CRASH_LOG_MAXED,
- mCrashes == CRASH_LOG_MAX_SIZE);
- for (Long time : mCrashTimestamps) {
- proto.write(BluetoothManagerServiceDumpProto.CRASH_TIMESTAMPS_MS, time);
- }
- proto.write(BluetoothManagerServiceDumpProto.NUM_BLE_APPS, mBleApps.size());
- for (ClientDeathRecipient app : mBleApps.values()) {
- proto.write(BluetoothManagerServiceDumpProto.BLE_APP_PACKAGE_NAMES,
- app.getPackageName());
- }
- proto.flush();
- }
-
- private static String getEnableDisableReasonString(int reason) {
- switch (reason) {
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_APPLICATION_REQUEST:
- return "APPLICATION_REQUEST";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_AIRPLANE_MODE:
- return "AIRPLANE_MODE";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_DISALLOWED:
- return "DISALLOWED";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTARTED:
- return "RESTARTED";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_START_ERROR:
- return "START_ERROR";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT:
- return "SYSTEM_BOOT";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_CRASH:
- return "CRASH";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH:
- return "USER_SWITCH";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_RESTORE_USER_SETTING:
- return "RESTORE_USER_SETTING";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET:
- return "FACTORY_RESET";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED:
- return "INIT_FLAGS_CHANGED";
- case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED:
- default: return "UNKNOWN[" + reason + "]";
- }
- }
-
- @SuppressLint("AndroidFrameworkRequiresPermission")
- private static boolean checkPermissionForDataDelivery(Context context, String permission,
- AttributionSource attributionSource, String message) {
- PermissionManager pm = context.getSystemService(PermissionManager.class);
- if (pm == null) {
- return false;
- }
- AttributionSource currentAttribution = new AttributionSource
- .Builder(context.getAttributionSource())
- .setNext(attributionSource)
- .build();
- final int result = pm.checkPermissionForDataDeliveryFromDataSource(permission,
- currentAttribution, message);
- if (result == PERMISSION_GRANTED) {
- return true;
- }
-
- final String msg = "Need " + permission + " permission for " + attributionSource + ": "
- + message;
- if (result == PERMISSION_HARD_DENIED) {
- throw new SecurityException(msg);
- } else {
- Log.w(TAG, msg);
- return false;
- }
- }
-
- /**
- * Returns true if the BLUETOOTH_CONNECT permission is granted for the calling app. Returns
- * false if the result is a soft denial. Throws SecurityException if the result is a hard
- * denial.
- *
- * <p>Should be used in situations where the app op should not be noted.
- */
- @SuppressLint("AndroidFrameworkRequiresPermission")
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_CONNECT)
- public static boolean checkConnectPermissionForDataDelivery(
- Context context, AttributionSource attributionSource, String message) {
- return checkPermissionForDataDelivery(context, BLUETOOTH_CONNECT,
- attributionSource, message);
- }
-
- static @NonNull Bundle getTempAllowlistBroadcastOptions() {
- final long duration = 10_000;
- final BroadcastOptions bOptions = BroadcastOptions.makeBasic();
- bOptions.setTemporaryAppAllowlist(duration,
- TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
- PowerExemptionManager.REASON_BLUETOOTH_BROADCAST, "");
- return bOptions.toBundle();
- }
-}
diff --git a/services/core/java/com/android/server/BluetoothModeChangeHelper.java b/services/core/java/com/android/server/BluetoothModeChangeHelper.java
deleted file mode 100644
index e5854c9..0000000
--- a/services/core/java/com/android/server/BluetoothModeChangeHelper.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.annotation.RequiresPermission;
-import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothHearingAid;
-import android.bluetooth.BluetoothLeAudio;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProfile.ServiceListener;
-import android.content.Context;
-import android.content.res.Resources;
-import android.provider.Settings;
-import android.widget.Toast;
-
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-
-/**
- * Helper class that handles callout and callback methods without
- * complex logic.
- */
-public class BluetoothModeChangeHelper {
- private volatile BluetoothA2dp mA2dp;
- private volatile BluetoothHearingAid mHearingAid;
- private volatile BluetoothLeAudio mLeAudio;
- private final BluetoothAdapter mAdapter;
- private final Context mContext;
-
- BluetoothModeChangeHelper(Context context) {
- mAdapter = BluetoothAdapter.getDefaultAdapter();
- mContext = context;
-
- mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.A2DP);
- mAdapter.getProfileProxy(mContext, mProfileServiceListener,
- BluetoothProfile.HEARING_AID);
- mAdapter.getProfileProxy(mContext, mProfileServiceListener, BluetoothProfile.LE_AUDIO);
- }
-
- private final ServiceListener mProfileServiceListener = new ServiceListener() {
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- // Setup Bluetooth profile proxies
- switch (profile) {
- case BluetoothProfile.A2DP:
- mA2dp = (BluetoothA2dp) proxy;
- break;
- case BluetoothProfile.HEARING_AID:
- mHearingAid = (BluetoothHearingAid) proxy;
- break;
- case BluetoothProfile.LE_AUDIO:
- mLeAudio = (BluetoothLeAudio) proxy;
- break;
- default:
- break;
- }
- }
-
- @Override
- public void onServiceDisconnected(int profile) {
- // Clear Bluetooth profile proxies
- switch (profile) {
- case BluetoothProfile.A2DP:
- mA2dp = null;
- break;
- case BluetoothProfile.HEARING_AID:
- mHearingAid = null;
- break;
- case BluetoothProfile.LE_AUDIO:
- mLeAudio = null;
- break;
- default:
- break;
- }
- }
- };
-
- @VisibleForTesting
- public boolean isMediaProfileConnected() {
- return isA2dpConnected() || isHearingAidConnected() || isLeAudioConnected();
- }
-
- @VisibleForTesting
- public boolean isBluetoothOn() {
- final BluetoothAdapter adapter = mAdapter;
- if (adapter == null) {
- return false;
- }
- return adapter.getLeState() == BluetoothAdapter.STATE_ON;
- }
-
- @VisibleForTesting
- public boolean isAirplaneModeOn() {
- return Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
- }
-
- @VisibleForTesting
- @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public void onAirplaneModeChanged(BluetoothManagerService managerService) {
- managerService.onAirplaneModeChanged();
- }
-
- @VisibleForTesting
- public int getSettingsInt(String name) {
- return Settings.Global.getInt(mContext.getContentResolver(),
- name, 0);
- }
-
- @VisibleForTesting
- public void setSettingsInt(String name, int value) {
- Settings.Global.putInt(mContext.getContentResolver(),
- name, value);
- }
-
- @VisibleForTesting
- public void showToastMessage() {
- Resources r = mContext.getResources();
- final CharSequence text = r.getString(
- R.string.bluetooth_airplane_mode_toast, 0);
- Toast.makeText(mContext, text, Toast.LENGTH_LONG).show();
- }
-
- private boolean isA2dpConnected() {
- final BluetoothA2dp a2dp = mA2dp;
- if (a2dp == null) {
- return false;
- }
- return a2dp.getConnectedDevices().size() > 0;
- }
-
- private boolean isHearingAidConnected() {
- final BluetoothHearingAid hearingAid = mHearingAid;
- if (hearingAid == null) {
- return false;
- }
- return hearingAid.getConnectedDevices().size() > 0;
- }
-
- private boolean isLeAudioConnected() {
- final BluetoothLeAudio leAudio = mLeAudio;
- if (leAudio == null) {
- return false;
- }
- return leAudio.getConnectedDevices().size() > 0;
- }
-}
diff --git a/services/core/java/com/android/server/BluetoothService.java b/services/core/java/com/android/server/BluetoothService.java
deleted file mode 100644
index 1a1eecd..0000000
--- a/services/core/java/com/android/server/BluetoothService.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.os.UserManager;
-
-import com.android.server.SystemService.TargetUser;
-
-class BluetoothService extends SystemService {
- private BluetoothManagerService mBluetoothManagerService;
- private boolean mInitialized = false;
-
- public BluetoothService(Context context) {
- super(context);
- mBluetoothManagerService = new BluetoothManagerService(context);
- }
-
- private void initialize() {
- if (!mInitialized) {
- mBluetoothManagerService.handleOnBootPhase();
- mInitialized = true;
- }
- }
-
- @Override
- public void onStart() {
- }
-
- @Override
- public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
- mBluetoothManagerService);
- } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY &&
- !UserManager.isHeadlessSystemUserMode()) {
- initialize();
- }
- }
-
- @Override
- public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
- if (!mInitialized) {
- initialize();
- } else {
- mBluetoothManagerService.handleOnSwitchUser(to.getUserIdentifier());
- }
- }
-
- @Override
- public void onUserUnlocking(@NonNull TargetUser user) {
- mBluetoothManagerService.handleOnUnlockUser(user.getUserIdentifier());
- }
-}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 70bd734..e933526 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -393,6 +393,7 @@
import com.android.server.job.JobSchedulerInternal;
import com.android.server.os.NativeTombstoneManager;
import com.android.server.pm.Installer;
+import com.android.server.pm.UserManagerInternal;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.uri.GrantUri;
@@ -13312,6 +13313,14 @@
}
switch (action) {
+ case Intent.ACTION_MEDIA_SCANNER_SCAN_FILE:
+ UserManagerInternal umInternal = LocalServices.getService(
+ UserManagerInternal.class);
+ UserInfo userInfo = umInternal.getUserInfo(userId);
+ if (userInfo != null && userInfo.isCloneProfile()) {
+ userId = umInternal.getProfileParentId(userId);
+ }
+ break;
case Intent.ACTION_UID_REMOVED:
case Intent.ACTION_PACKAGE_REMOVED:
case Intent.ACTION_PACKAGE_CHANGED:
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 2fcdd61..565e295 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -1219,6 +1219,7 @@
mDeviceInventory.onSetBtActiveDevice((BtDeviceInfo) msg.obj,
mAudioService.getBluetoothContextualVolumeStream());
}
+ break;
case MSG_BT_HEADSET_CNCT_FAILED:
synchronized (mSetModeLock) {
synchronized (mDeviceStateLock) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 346ae0f..57ae36ed 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -9408,6 +9408,7 @@
pw.println("mHasSpatializerEffect:" + mHasSpatializerEffect);
pw.println("isSpatializerEnabled:" + isSpatializerEnabled());
pw.println("isSpatialAudioEnabled:" + isSpatialAudioEnabled());
+ mSpatializerHelper.dump(pw);
mAudioSystem.dump(pw);
}
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
index b47ea4f..e6789d5 100644
--- a/services/core/java/com/android/server/audio/SpatializerHelper.java
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -39,6 +39,7 @@
import android.os.RemoteException;
import android.util.Log;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -84,7 +85,7 @@
private int mSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
private int mCapableSpatLevel = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
private int mActualHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
- private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_UNSUPPORTED;
+ private int mDesiredHeadTrackingMode = Spatializer.HEAD_TRACKING_MODE_RELATIVE_WORLD;
private int mSpatOutput = 0;
private @Nullable ISpatializer mSpat;
private @Nullable SpatializerCallback mSpatCallback;
@@ -681,12 +682,13 @@
return;
}
try {
- if (mode != mDesiredHeadTrackingMode) {
- mSpat.setDesiredHeadTrackingMode(spatializerIntToHeadTrackingModeType(mode));
+ if (mDesiredHeadTrackingMode != mode) {
mDesiredHeadTrackingMode = mode;
dispatchDesiredHeadTrackingMode(mode);
}
-
+ if (mode != headTrackingModeTypeToSpatializerInt(mSpat.getActualHeadTrackingMode())) {
+ mSpat.setDesiredHeadTrackingMode(spatializerIntToHeadTrackingModeType(mode));
+ }
} catch (RemoteException e) {
Log.e(TAG, "Error calling setDesiredHeadTrackingMode", e);
}
@@ -937,6 +939,7 @@
} catch (Exception e) {
Log.e(TAG, "Error calling setHeadSensor:" + headHandle, e);
}
+ setDesiredHeadTrackingMode(mDesiredHeadTrackingMode);
}
//------------------------------------------------------
@@ -983,4 +986,22 @@
throw(new IllegalArgumentException("Unexpected spatializer level:" + level));
}
}
+
+ void dump(PrintWriter pw) {
+ pw.println("SpatializerHelper:");
+ pw.println("\tmState:" + mState);
+ pw.println("\tmSpatLevel:" + mSpatLevel);
+ pw.println("\tmCapableSpatLevel:" + mCapableSpatLevel);
+ pw.println("\tmActualHeadTrackingMode:"
+ + Spatializer.headtrackingModeToString(mActualHeadTrackingMode));
+ pw.println("\tmDesiredHeadTrackingMode:"
+ + Spatializer.headtrackingModeToString(mDesiredHeadTrackingMode));
+ String modesString = "";
+ int[] modes = getSupportedHeadTrackingModes();
+ for (int mode : modes) {
+ modesString += Spatializer.headtrackingModeToString(mode) + " ";
+ }
+ pw.println("\tsupported head tracking modes:" + modesString);
+ pw.println("\tmSpatOutput:" + mSpatOutput);
+ }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
index 8c93891..6654c0c 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/ProgramInfoCache.java
@@ -189,7 +189,8 @@
removed.add(id);
}
}
- if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.isComplete()) {
+ if (modified.isEmpty() && removed.isEmpty() && mComplete == chunk.isComplete()
+ && !chunk.isPurge()) {
return null;
}
mComplete = chunk.isComplete();
@@ -239,9 +240,10 @@
}
// Determine number of chunks we need to send.
- int numChunks = 0;
+ int numChunks = purge ? 1 : 0;
if (modified != null) {
- numChunks = roundUpFraction(modified.size(), maxNumModifiedPerChunk);
+ numChunks = Math.max(numChunks,
+ roundUpFraction(modified.size(), maxNumModifiedPerChunk));
}
if (removed != null) {
numChunks = Math.max(numChunks, roundUpFraction(removed.size(), maxNumRemovedPerChunk));
diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
index cc9efbc..fce6737 100644
--- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
+++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java
@@ -199,6 +199,7 @@
private final NetworkTemplate mNetworkTemplate;
private final UsageCallback mUsageCallback;
private NetworkCapabilities mNetworkCapabilities;
+ private final NetworkStatsManager mStatsManager;
public MultipathTracker(Network network, NetworkCapabilities nc) {
this.network = network;
@@ -238,6 +239,13 @@
updateMultipathBudget();
}
};
+ mStatsManager = mContext.getSystemService(NetworkStatsManager.class);
+ // Query stats from NetworkStatsService will trigger a poll by default.
+ // But since MultipathPolicyTracker listens NPMS events that triggered by
+ // stats updated event, and will query stats
+ // after the event. A polling -> updated -> query -> polling loop will be introduced
+ // if polls on open. Hence, set flag to false to prevent a polling loop.
+ mStatsManager.setPollOnOpen(false);
updateMultipathBudget();
}
@@ -262,8 +270,7 @@
private long getNetworkTotalBytes(long start, long end) {
try {
final android.app.usage.NetworkStats.Bucket ret =
- mContext.getSystemService(NetworkStatsManager.class)
- .querySummaryForDevice(mNetworkTemplate, start, end);
+ mStatsManager.querySummaryForDevice(mNetworkTemplate, start, end);
return ret.getRxBytes() + ret.getTxBytes();
} catch (RuntimeException e) {
Log.w(TAG, "Failed to get data usage: " + e);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index ffed68e..f4c36c6 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -74,13 +74,6 @@
private static final int MSG_UPDATE_FOREGROUND_APP_SYNC = 5;
private static final int MSG_RUN_UPDATE = 6;
- // Length of the ambient light horizon used to calculate the long term estimate of ambient
- // light.
- private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
-
- // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
- private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
-
// Callbacks for requesting updates to the display's power state
private final Callbacks mCallbacks;
@@ -125,8 +118,10 @@
// and only then decide whether to change brightness.
private final boolean mResetAmbientLuxAfterWarmUpConfig;
- // Period of time in which to consider light samples in milliseconds.
- private final int mAmbientLightHorizon;
+ // Period of time in which to consider light samples for a short/long-term estimate of ambient
+ // light in milliseconds.
+ private final int mAmbientLightHorizonLong;
+ private final int mAmbientLightHorizonShort;
// The intercept used for the weighting calculation. This is used in order to keep all possible
// weighting values positive.
@@ -220,6 +215,7 @@
private Context mContext;
private int mState = AUTO_BRIGHTNESS_DISABLED;
+ private Clock mClock;
private final Injector mInjector;
AutomaticBrightnessController(Callbacks callbacks, Looper looper,
@@ -231,14 +227,16 @@
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
HysteresisLevels screenBrightnessThresholds, Context context,
HighBrightnessModeController hbmController,
- BrightnessMappingStrategy idleModeBrightnessMapper) {
+ BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
+ int ambientLightHorizonLong) {
this(new Injector(), callbacks, looper, sensorManager, lightSensor,
interactiveModeBrightnessMapper,
lightSensorWarmUpTime, brightnessMin, brightnessMax, dozeScaleFactor,
lightSensorRate, initialLightSensorRate, brighteningLightDebounceConfig,
darkeningLightDebounceConfig, resetAmbientLuxAfterWarmUpConfig,
ambientBrightnessThresholds, screenBrightnessThresholds, context,
- hbmController, idleModeBrightnessMapper
+ hbmController, idleModeBrightnessMapper, ambientLightHorizonShort,
+ ambientLightHorizonLong
);
}
@@ -252,8 +250,10 @@
boolean resetAmbientLuxAfterWarmUpConfig, HysteresisLevels ambientBrightnessThresholds,
HysteresisLevels screenBrightnessThresholds, Context context,
HighBrightnessModeController hbmController,
- BrightnessMappingStrategy idleModeBrightnessMapper) {
+ BrightnessMappingStrategy idleModeBrightnessMapper, int ambientLightHorizonShort,
+ int ambientLightHorizonLong) {
mInjector = injector;
+ mClock = injector.createClock();
mContext = context;
mCallbacks = callbacks;
mSensorManager = sensorManager;
@@ -268,15 +268,16 @@
mBrighteningLightDebounceConfig = brighteningLightDebounceConfig;
mDarkeningLightDebounceConfig = darkeningLightDebounceConfig;
mResetAmbientLuxAfterWarmUpConfig = resetAmbientLuxAfterWarmUpConfig;
- mAmbientLightHorizon = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
- mWeightingIntercept = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
+ mAmbientLightHorizonLong = ambientLightHorizonLong;
+ mAmbientLightHorizonShort = ambientLightHorizonShort;
+ mWeightingIntercept = ambientLightHorizonLong;
mAmbientBrightnessThresholds = ambientBrightnessThresholds;
mScreenBrightnessThresholds = screenBrightnessThresholds;
mShortTermModelValid = true;
mShortTermModelAnchor = -1;
mHandler = new AutomaticBrightnessHandler(looper);
mAmbientLightRingBuffer =
- new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
+ new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizonLong, mClock);
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
mLightSensor = lightSensor;
@@ -397,6 +398,11 @@
mHandler.sendEmptyMessage(MSG_RUN_UPDATE);
}
+ @VisibleForTesting
+ float getAmbientLux() {
+ return mAmbientLux;
+ }
+
private boolean setDisplayPolicy(int policy) {
if (mDisplayPolicy == policy) {
return false;
@@ -476,7 +482,8 @@
pw.println(" mBrighteningLightDebounceConfig=" + mBrighteningLightDebounceConfig);
pw.println(" mDarkeningLightDebounceConfig=" + mDarkeningLightDebounceConfig);
pw.println(" mResetAmbientLuxAfterWarmUpConfig=" + mResetAmbientLuxAfterWarmUpConfig);
- pw.println(" mAmbientLightHorizon=" + mAmbientLightHorizon);
+ pw.println(" mAmbientLightHorizonLong=" + mAmbientLightHorizonLong);
+ pw.println(" mAmbientLightHorizonShort=" + mAmbientLightHorizonShort);
pw.println(" mWeightingIntercept=" + mWeightingIntercept);
pw.println();
@@ -545,7 +552,7 @@
if (enable) {
if (!mLightSensorEnabled) {
mLightSensorEnabled = true;
- mLightSensorEnableTime = SystemClock.uptimeMillis();
+ mLightSensorEnableTime = mClock.uptimeMillis();
mCurrentLightSensorRate = mInitialLightSensorRate;
registerForegroundAppUpdater();
mSensorManager.registerListener(mLightSensorListener, mLightSensor,
@@ -580,7 +587,7 @@
private void applyLightSensorMeasurement(long time, float lux) {
mRecentLightSamples++;
- mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
+ mAmbientLightRingBuffer.prune(time - mAmbientLightHorizonLong);
mAmbientLightRingBuffer.push(time, lux);
// Remember this sample value.
@@ -721,8 +728,8 @@
}
private void updateAmbientLux() {
- long time = SystemClock.uptimeMillis();
- mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
+ long time = mClock.uptimeMillis();
+ mAmbientLightRingBuffer.prune(time - mAmbientLightHorizonLong);
updateAmbientLux(time);
}
@@ -742,7 +749,7 @@
timeWhenSensorWarmedUp);
return;
}
- setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS));
+ setAmbientLux(calculateAmbientLux(time, mAmbientLightHorizonShort));
mAmbientLuxValid = true;
if (mLoggingEnabled) {
Slog.d(TAG, "updateAmbientLux: Initializing: " +
@@ -762,8 +769,8 @@
// proposed ambient light value since the slow value might be sufficiently far enough away
// from the fast value to cause a recalculation while its actually just converging on
// the fast value still.
- float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS);
- float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS);
+ float slowAmbientLux = calculateAmbientLux(time, mAmbientLightHorizonLong);
+ float fastAmbientLux = calculateAmbientLux(time, mAmbientLightHorizonShort);
if ((slowAmbientLux >= mAmbientBrighteningThreshold
&& fastAmbientLux >= mAmbientBrighteningThreshold
@@ -1044,7 +1051,7 @@
@Override
public void onSensorChanged(SensorEvent event) {
if (mLightSensorEnabled) {
- final long time = SystemClock.uptimeMillis();
+ final long time = mClock.uptimeMillis();
final float lux = event.values[0];
handleLightSensorEvent(time, lux);
}
@@ -1070,6 +1077,15 @@
void updateBrightness();
}
+ /** Functional interface for providing time. */
+ @VisibleForTesting
+ interface Clock {
+ /**
+ * Returns current time in milliseconds since boot, not counting time spent in deep sleep.
+ */
+ long uptimeMillis();
+ }
+
/**
* A ring buffer of ambient light measurements sorted by time.
*
@@ -1089,14 +1105,16 @@
private int mStart;
private int mEnd;
private int mCount;
+ Clock mClock;
- public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon) {
+ public AmbientLightRingBuffer(long lightSensorRate, int ambientLightHorizon, Clock clock) {
if (lightSensorRate <= 0) {
throw new IllegalArgumentException("lightSensorRate must be above 0");
}
mCapacity = (int) Math.ceil(ambientLightHorizon * BUFFER_SLACK / lightSensorRate);
mRingLux = new float[mCapacity];
mRingTime = new long[mCapacity];
+ mClock = clock;
}
public float getLux(int index) {
@@ -1181,7 +1199,7 @@
StringBuilder buf = new StringBuilder();
buf.append('[');
for (int i = 0; i < mCount; i++) {
- final long next = i + 1 < mCount ? getTime(i + 1) : SystemClock.uptimeMillis();
+ final long next = i + 1 < mCount ? getTime(i + 1) : mClock.uptimeMillis();
if (i != 0) {
buf.append(", ");
}
@@ -1210,5 +1228,9 @@
public Handler getBackgroundThreadHandler() {
return BackgroundThread.getHandler();
}
+
+ Clock createClock() {
+ return SystemClock::uptimeMillis;
+ }
}
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index a9e1647..3df2422 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -52,6 +52,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
+import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -86,6 +87,13 @@
private static final float NITS_INVALID = -1;
+ // Length of the ambient light horizon used to calculate the long term estimate of ambient
+ // light.
+ private static final int AMBIENT_LIGHT_LONG_HORIZON_MILLIS = 10000;
+
+ // Length of the ambient light horizon used to calculate short-term estimate of ambient light.
+ private static final int AMBIENT_LIGHT_SHORT_HORIZON_MILLIS = 2000;
+
private final Context mContext;
// The details of the ambient light sensor associated with this display.
@@ -120,6 +128,8 @@
private float mBrightnessRampFastIncrease = Float.NaN;
private float mBrightnessRampSlowDecrease = Float.NaN;
private float mBrightnessRampSlowIncrease = Float.NaN;
+ private int mAmbientHorizonLong = AMBIENT_LIGHT_LONG_HORIZON_MILLIS;
+ private int mAmbientHorizonShort = AMBIENT_LIGHT_SHORT_HORIZON_MILLIS;
private Spline mBrightnessToBacklightSpline;
private Spline mBacklightToBrightnessSpline;
private Spline mBacklightToNitsSpline;
@@ -346,6 +356,14 @@
return mBrightnessRampSlowIncrease;
}
+ public int getAmbientHorizonLong() {
+ return mAmbientHorizonLong;
+ }
+
+ public int getAmbientHorizonShort() {
+ return mAmbientHorizonShort;
+ }
+
SensorData getAmbientLightSensor() {
return mAmbientLightSensor;
}
@@ -405,6 +423,8 @@
+ ", mBrightnessRampFastIncrease=" + mBrightnessRampFastIncrease
+ ", mBrightnessRampSlowDecrease=" + mBrightnessRampSlowDecrease
+ ", mBrightnessRampSlowIncrease=" + mBrightnessRampSlowIncrease
+ + ", mAmbientHorizonLong=" + mAmbientHorizonLong
+ + ", mAmbientHorizonShort=" + mAmbientHorizonShort
+ ", mAmbientLightSensor=" + mAmbientLightSensor
+ ", mProximitySensor=" + mProximitySensor
+ ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray())
@@ -461,6 +481,7 @@
loadBrightnessRamps(config);
loadAmbientLightSensorFromDdc(config);
loadProxSensorFromDdc(config);
+ loadAmbientHorizonFromDdc(config);
} else {
Slog.w(TAG, "DisplayDeviceConfig file is null");
}
@@ -869,6 +890,17 @@
}
}
+ private void loadAmbientHorizonFromDdc(DisplayConfiguration config) {
+ final BigInteger configLongHorizon = config.getAmbientLightHorizonLong();
+ if (configLongHorizon != null) {
+ mAmbientHorizonLong = configLongHorizon.intValue();
+ }
+ final BigInteger configShortHorizon = config.getAmbientLightHorizonShort();
+ if (configShortHorizon != null) {
+ mAmbientHorizonShort = configShortHorizon.intValue();
+ }
+ }
+
static class SensorData {
public String type;
public String name;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index faf0038..34f915e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -957,7 +957,9 @@
lightSensorRate, initialLightSensorRate, brighteningLightDebounce,
darkeningLightDebounce, autoBrightnessResetAmbientLuxAfterWarmUp,
ambientBrightnessThresholds, screenBrightnessThresholds, mContext,
- mHbmController, mIdleModeBrightnessMapper);
+ mHbmController, mIdleModeBrightnessMapper,
+ mDisplayDeviceConfig.getAmbientHorizonShort(),
+ mDisplayDeviceConfig.getAmbientHorizonLong());
} else {
mUseSoftwareAutoBrightnessConfig = false;
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 3af51f4..db13deb 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -18,8 +18,6 @@
import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static com.android.server.inputmethod.InputMethodManagerService.MSG_INITIALIZE_IME;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.PendingIntent;
@@ -311,11 +309,8 @@
if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
final InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
mSupportsStylusHw = info.supportsStylusHandwriting();
- // Dispatch display id for InputMethodService to update context display.
- mService.executeOrSendMessage(mCurMethod,
- mService.mCaller.obtainMessageIOOO(MSG_INITIALIZE_IME,
- info.getConfigChanges(), mCurMethod, mCurToken,
- mSupportsStylusHw));
+ mService.executeOrSendInitializeIme(mCurMethod, mCurToken,
+ info.getConfigChanges(), mSupportsStylusHw);
mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
mService.reRequestCurrentClientSessionLocked();
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index f1e8d0d..6c68011 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -219,38 +219,38 @@
int FAILURE = -1;
}
- static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
- static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
- static final int MSG_SHOW_IM_CONFIG = 3;
+ private static final int MSG_SHOW_IM_SUBTYPE_PICKER = 1;
+ private static final int MSG_SHOW_IM_SUBTYPE_ENABLER = 2;
+ private static final int MSG_SHOW_IM_CONFIG = 3;
- static final int MSG_UNBIND_INPUT = 1000;
- static final int MSG_BIND_INPUT = 1010;
- static final int MSG_SHOW_SOFT_INPUT = 1020;
- static final int MSG_HIDE_SOFT_INPUT = 1030;
- static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
- static final int MSG_INITIALIZE_IME = 1040;
- static final int MSG_CREATE_SESSION = 1050;
- static final int MSG_REMOVE_IME_SURFACE = 1060;
- static final int MSG_REMOVE_IME_SURFACE_FROM_WINDOW = 1061;
- static final int MSG_UPDATE_IME_WINDOW_STATUS = 1070;
- static final int MSG_START_HANDWRITING = 1100;
+ private static final int MSG_UNBIND_INPUT = 1000;
+ private static final int MSG_BIND_INPUT = 1010;
+ private static final int MSG_SHOW_SOFT_INPUT = 1020;
+ private static final int MSG_HIDE_SOFT_INPUT = 1030;
+ private static final int MSG_HIDE_CURRENT_INPUT_METHOD = 1035;
+ private static final int MSG_INITIALIZE_IME = 1040;
+ private static final int MSG_CREATE_SESSION = 1050;
+ private static final int MSG_REMOVE_IME_SURFACE = 1060;
+ private static final int MSG_REMOVE_IME_SURFACE_FROM_WINDOW = 1061;
+ private static final int MSG_UPDATE_IME_WINDOW_STATUS = 1070;
+ private static final int MSG_START_HANDWRITING = 1100;
- static final int MSG_START_INPUT = 2000;
+ private static final int MSG_START_INPUT = 2000;
- static final int MSG_UNBIND_CLIENT = 3000;
- static final int MSG_BIND_CLIENT = 3010;
- static final int MSG_SET_ACTIVE = 3020;
- static final int MSG_SET_INTERACTIVE = 3030;
- static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
+ private static final int MSG_UNBIND_CLIENT = 3000;
+ private static final int MSG_BIND_CLIENT = 3010;
+ private static final int MSG_SET_ACTIVE = 3020;
+ private static final int MSG_SET_INTERACTIVE = 3030;
+ private static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
- static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
+ private static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
- static final int MSG_SYSTEM_UNLOCK_USER = 5000;
- static final int MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED = 5010;
+ private static final int MSG_SYSTEM_UNLOCK_USER = 5000;
+ private static final int MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED = 5010;
- static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
+ private static final int MSG_INLINE_SUGGESTIONS_REQUEST = 6000;
- static final int MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE = 7000;
+ private static final int MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE = 7000;
private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
@@ -278,14 +278,14 @@
final Context mContext;
final Resources mRes;
- final Handler mHandler;
+ private final Handler mHandler;
final InputMethodSettings mSettings;
final SettingsObserver mSettingsObserver;
final IWindowManager mIWindowManager;
final WindowManagerInternal mWindowManagerInternal;
final PackageManagerInternal mPackageManagerInternal;
final InputManagerInternal mInputManagerInternal;
- final HandlerCaller mCaller;
+ private final HandlerCaller mCaller;
final boolean mHasFeature;
private final ArrayMap<String, List<InputMethodSubtype>> mAdditionalSubtypeMap =
new ArrayMap<>();
@@ -1806,10 +1806,10 @@
mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
com.android.internal.R.bool.show_ongoing_ime_switcher);
if (mShowOngoingImeSwitcherForPhones) {
- final InputMethodMenuController.HardKeyboardListener hardKeyboardListener =
- mMenuController.getHardKeyboardListener();
- mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
- hardKeyboardListener);
+ mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(available -> {
+ mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED, available ? 1 : 0)
+ .sendToTarget();
+ });
}
mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
@@ -2241,7 +2241,7 @@
}
}
- void executeOrSendMessage(IInterface target, Message msg) {
+ private void executeOrSendMessage(IInterface target, Message msg) {
if (target.asBinder() instanceof Binder) {
mCaller.sendMessage(msg);
} else {
@@ -2527,6 +2527,13 @@
}
@AnyThread
+ void executeOrSendInitializeIme(@NonNull IInputMethod inputMethod, @NonNull IBinder token,
+ @android.content.pm.ActivityInfo.Config int configChanges, boolean supportStylusHw) {
+ executeOrSendMessage(inputMethod, mCaller.obtainMessageIOOO(MSG_INITIALIZE_IME,
+ configChanges, inputMethod, token, supportStylusHw));
+ }
+
+ @AnyThread
void scheduleNotifyImeUidToAudioService(int uid) {
mCaller.removeMessages(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE);
mCaller.obtainMessageI(MSG_NOTIFY_IME_UID_TO_AUDIO_SERVICE, uid).sendToTarget();
@@ -4416,9 +4423,7 @@
// --------------------------------------------------------------
case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
- final InputMethodMenuController.HardKeyboardListener hardKeyboardListener =
- mMenuController.getHardKeyboardListener();
- hardKeyboardListener.handleHardKeyboardStatusChange(msg.arg1 == 1);
+ mMenuController.handleHardKeyboardStatusChange(msg.arg1 == 1);
return true;
case MSG_SYSTEM_UNLOCK_USER: {
final int userId = msg.arg1;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index 132be7d..fcb1be0 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -18,7 +18,6 @@
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.server.inputmethod.InputMethodManagerService.DEBUG;
-import static com.android.server.inputmethod.InputMethodManagerService.MSG_HARD_KEYBOARD_SWITCH_CHANGED;
import static com.android.server.inputmethod.InputMethodUtils.NOT_A_SUBTYPE_ID;
import android.app.ActivityThread;
@@ -28,7 +27,6 @@
import android.content.DialogInterface;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
-import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -62,10 +60,8 @@
private final InputMethodManagerService mService;
private final InputMethodUtils.InputMethodSettings mSettings;
private final InputMethodSubtypeSwitchingController mSwitchingController;
- private final Handler mHandler;
private final ArrayMap<String, InputMethodInfo> mMethodMap;
private final KeyguardManager mKeyguardManager;
- private final HardKeyboardListener mHardKeyboardListener;
private final WindowManagerInternal mWindowManagerInternal;
private Context mSettingsContext;
@@ -83,10 +79,8 @@
mService = service;
mSettings = mService.mSettings;
mSwitchingController = mService.mSwitchingController;
- mHandler = mService.mHandler;
mMethodMap = mService.mMethodMap;
mKeyguardManager = mService.mKeyguardManager;
- mHardKeyboardListener = new HardKeyboardListener();
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
}
@@ -271,10 +265,6 @@
}
}
- HardKeyboardListener getHardKeyboardListener() {
- return mHardKeyboardListener;
- }
-
AlertDialog getSwitchingDialogLocked() {
return mSwitchingDialog;
}
@@ -290,24 +280,16 @@
return mSwitchingDialog.isShowing();
}
- class HardKeyboardListener implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
- @Override
- public void onHardKeyboardStatusChange(boolean available) {
- mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
- available ? 1 : 0));
+ void handleHardKeyboardStatusChange(boolean available) {
+ if (DEBUG) {
+ Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
}
-
- public void handleHardKeyboardStatusChange(boolean available) {
- if (DEBUG) {
- Slog.w(TAG, "HardKeyboardStatusChanged: available=" + available);
- }
- synchronized (ImfLock.class) {
- if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
- && mSwitchingDialog.isShowing()) {
- mSwitchingDialogTitleView.findViewById(
- com.android.internal.R.id.hard_keyboard_section).setVisibility(
- available ? View.VISIBLE : View.GONE);
- }
+ synchronized (ImfLock.class) {
+ if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
+ && mSwitchingDialog.isShowing()) {
+ mSwitchingDialogTitleView.findViewById(
+ com.android.internal.R.id.hard_keyboard_section).setVisibility(
+ available ? View.VISIBLE : View.GONE);
}
}
}
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index a1c97a8..c285e27 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -413,11 +413,9 @@
throws PackageManagerException;
/**
- * Get a list of apex system services implemented in an apex.
- *
- * <p>The list is sorted by initOrder for consistency.
+ * Get a map of system services defined in an apex mapped to the jar files they reside in.
*/
- public abstract List<ApexSystemServiceInfo> getApexSystemServices();
+ public abstract Map<String, String> getApexSystemServices();
/**
* Dumps various state information to the provided {@link PrintWriter} object.
@@ -450,7 +448,7 @@
* Map of all apex system services to the jar files they are contained in.
*/
@GuardedBy("mLock")
- private List<ApexSystemServiceInfo> mApexSystemServices = new ArrayList<>();
+ private Map<String, String> mApexSystemServices = new ArrayMap<>();
/**
* Contains the list of {@code packageName}s of apks-in-apex for given
@@ -606,19 +604,14 @@
}
String name = service.getName();
- for (ApexSystemServiceInfo info : mApexSystemServices) {
- if (info.getName().equals(name)) {
- throw new IllegalStateException(String.format(
- "Duplicate apex-system-service %s from %s, %s",
- name, info.mJarPath, service.getJarPath()));
- }
+ if (mApexSystemServices.containsKey(name)) {
+ throw new IllegalStateException(String.format(
+ "Duplicate apex-system-service %s from %s, %s",
+ name, mApexSystemServices.get(name), service.getJarPath()));
}
- ApexSystemServiceInfo info = new ApexSystemServiceInfo(
- service.getName(), service.getJarPath(), service.getInitOrder());
- mApexSystemServices.add(info);
+ mApexSystemServices.put(name, service.getJarPath());
}
- Collections.sort(mApexSystemServices);
mPackageNameToApexModuleName.put(packageInfo.packageName, ai.moduleName);
if (ai.isActive) {
if (activePackagesSet.contains(packageInfo.packageName)) {
@@ -1139,7 +1132,7 @@
}
@Override
- public List<ApexSystemServiceInfo> getApexSystemServices() {
+ public Map<String, String> getApexSystemServices() {
synchronized (mLock) {
Preconditions.checkState(mApexSystemServices != null,
"APEX packages have not been scanned");
@@ -1425,10 +1418,10 @@
}
@Override
- public List<ApexSystemServiceInfo> getApexSystemServices() {
+ public Map<String, String> getApexSystemServices() {
// TODO(satayev): we can't really support flattened apex use case, and need to migrate
// the manifest entries into system's manifest asap.
- return Collections.emptyList();
+ return Collections.emptyMap();
}
@Override
diff --git a/services/core/java/com/android/server/pm/ApexSystemServiceInfo.java b/services/core/java/com/android/server/pm/ApexSystemServiceInfo.java
deleted file mode 100644
index f75ba6d..0000000
--- a/services/core/java/com/android/server/pm/ApexSystemServiceInfo.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import android.annotation.Nullable;
-
-/**
- * A helper class that contains information about apex-system-service to be used within system
- * server process.
- */
-public final class ApexSystemServiceInfo implements Comparable<ApexSystemServiceInfo> {
-
- final String mName;
- @Nullable
- final String mJarPath;
- final int mInitOrder;
-
- public ApexSystemServiceInfo(String name, String jarPath, int initOrder) {
- this.mName = name;
- this.mJarPath = jarPath;
- this.mInitOrder = initOrder;
- }
-
- public String getName() {
- return mName;
- }
-
- public String getJarPath() {
- return mJarPath;
- }
-
- public int getInitOrder() {
- return mInitOrder;
- }
-
- @Override
- public int compareTo(ApexSystemServiceInfo other) {
- if (mInitOrder == other.mInitOrder) {
- return mName.compareTo(other.mName);
- }
- // higher initOrder values take precedence
- return -Integer.compare(mInitOrder, other.mInitOrder);
- }
-}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4225f21..44818a8 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -399,10 +399,11 @@
if (recentsAnimationInputConsumer != null && focus != null) {
final RecentsAnimationController recentsAnimationController =
mService.getRecentsAnimationController();
+ // Apply recents input consumer when the focusing window is in recents animation.
final boolean shouldApplyRecentsInputConsumer = (recentsAnimationController != null
&& recentsAnimationController.shouldApplyInputConsumer(focus.mActivityRecord))
// Shell transitions doesn't use RecentsAnimationController
- || getWeak(mActiveRecentsActivity) != null;
+ || getWeak(mActiveRecentsActivity) != null && focus.inTransition();
if (shouldApplyRecentsInputConsumer) {
requestFocus(recentsAnimationInputConsumer.mWindowHandle.token,
recentsAnimationInputConsumer.mName);
diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd
index 2f4dd57..baf2ede 100644
--- a/services/core/xsd/display-device-config/display-device-config.xsd
+++ b/services/core/xsd/display-device-config/display-device-config.xsd
@@ -58,6 +58,15 @@
<xs:element type="sensorDetails" name="proxSensor">
<xs:annotation name="final"/>
</xs:element>
+
+ <!-- Length of the ambient light horizon used to calculate the long & short term
+ estimates of ambient light in milliseconds.-->
+ <xs:element type="xs:nonNegativeInteger" name="ambientLightHorizonLong">
+ <xs:annotation name="final"/>
+ </xs:element>
+ <xs:element type="xs:nonNegativeInteger" name="ambientLightHorizonShort">
+ <xs:annotation name="final"/>
+ </xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
diff --git a/services/core/xsd/display-device-config/schema/current.txt b/services/core/xsd/display-device-config/schema/current.txt
index 5b2b87c..6f97431 100644
--- a/services/core/xsd/display-device-config/schema/current.txt
+++ b/services/core/xsd/display-device-config/schema/current.txt
@@ -18,6 +18,8 @@
public class DisplayConfiguration {
ctor public DisplayConfiguration();
+ method public final java.math.BigInteger getAmbientLightHorizonLong();
+ method public final java.math.BigInteger getAmbientLightHorizonShort();
method @Nullable public final com.android.server.display.config.DensityMap getDensityMap();
method public com.android.server.display.config.HighBrightnessMode getHighBrightnessMode();
method public final com.android.server.display.config.SensorDetails getLightSensor();
@@ -29,6 +31,8 @@
method public final java.math.BigDecimal getScreenBrightnessRampFastIncrease();
method public final java.math.BigDecimal getScreenBrightnessRampSlowDecrease();
method public final java.math.BigDecimal getScreenBrightnessRampSlowIncrease();
+ method public final void setAmbientLightHorizonLong(java.math.BigInteger);
+ method public final void setAmbientLightHorizonShort(java.math.BigInteger);
method public final void setDensityMap(@Nullable com.android.server.display.config.DensityMap);
method public void setHighBrightnessMode(com.android.server.display.config.HighBrightnessMode);
method public final void setLightSensor(com.android.server.display.config.SensorDetails);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
index 55ab8c3..ebe9f93 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
@@ -17,16 +17,20 @@
import android.annotation.NonNull;
import android.annotation.UserIdInt;
+import android.app.admin.DevicePolicyDrawableResource;
import android.app.admin.DevicePolicySafetyChecker;
import android.app.admin.FullyManagedDeviceProvisioningParams;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.ManagedProfileProvisioningParams;
+import android.app.admin.ParcelableResource;
import android.content.ComponentName;
import android.os.UserHandle;
import android.util.Slog;
import com.android.server.SystemService;
+import java.util.List;
+
/**
* Defines the required interface for IDevicePolicyManager implemenation.
*
@@ -161,4 +165,16 @@
public boolean isKeyPairGrantedToWifiAuth(String callerPackage, String alias) {
return false;
}
+
+ @Override
+ public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables){}
+
+ @Override
+ public void resetDrawables(@NonNull int[] drawableIds){}
+
+ @Override
+ public ParcelableResource getDrawable(
+ int drawableId, int drawableStyle, int drawableSource) {
+ return null;
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
new file mode 100644
index 0000000..53422940
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceManagementResourcesProvider.java
@@ -0,0 +1,417 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import static android.app.admin.DevicePolicyResources.Drawable.Source.UPDATABLE_DRAWABLE_SOURCES;
+import static android.app.admin.DevicePolicyResources.Drawable.Style;
+import static android.app.admin.DevicePolicyResources.Drawable.Style.UPDATABLE_DRAWABLE_STYLES;
+import static android.app.admin.DevicePolicyResources.Drawable.UPDATABLE_DRAWABLE_IDS;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.admin.DevicePolicyDrawableResource;
+import android.app.admin.DevicePolicyResources;
+import android.app.admin.ParcelableResource;
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.TypedXmlPullParser;
+import android.util.TypedXmlSerializer;
+import android.util.Xml;
+
+import libcore.io.IoUtils;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * A helper class for {@link DevicePolicyManagerService} to store/retrieve updated device
+ * management resources.
+ */
+class DeviceManagementResourcesProvider {
+ private static final String TAG = "DevicePolicyManagerService";
+
+ private static final String UPDATED_RESOURCES_XML = "updated_resources.xml";
+ private static final String TAG_ROOT = "root";
+ private static final String TAG_DRAWABLE_STYLE_ENTRY = "drawable-style-entry";
+ private static final String TAG_DRAWABLE_SOURCE_ENTRY = "drawable-source-entry";
+ private static final String ATTR_DRAWABLE_STYLE_SIZE = "drawable-style-size";
+ private static final String ATTR_DRAWABLE_SOURCE_SIZE = "drawable-source-size";
+ private static final String ATTR_DRAWABLE_STYLE = "drawable-style";
+ private static final String ATTR_DRAWABLE_SOURCE = "drawable-source";
+ private static final String ATTR_DRAWABLE_ID = "drawable-id";
+
+
+ private final Map<Integer, Map<Integer, ParcelableResource>>
+ mUpdatedDrawablesForStyle = new HashMap<>();
+
+ private final Map<Integer, Map<Integer, ParcelableResource>>
+ mUpdatedDrawablesForSource = new HashMap<>();
+
+ private final Object mLock = new Object();
+ private final Injector mInjector;
+
+ DeviceManagementResourcesProvider() {
+ this(new Injector());
+ }
+
+ DeviceManagementResourcesProvider(Injector injector) {
+ mInjector = requireNonNull(injector);
+ }
+
+ /**
+ * Returns {@code false} if no resources were updated.
+ */
+ boolean updateDrawables(@NonNull List<DevicePolicyDrawableResource> drawables) {
+ boolean updated = false;
+ for (int i = 0; i < drawables.size(); i++) {
+ int drawableId = drawables.get(i).getDrawableId();
+ int drawableStyle = drawables.get(i).getDrawableStyle();
+ int drawableSource = drawables.get(i).getDrawableSource();
+ ParcelableResource resource = drawables.get(i).getResource();
+
+ Objects.requireNonNull(resource, "ParcelableResource must be provided.");
+
+ if (drawableSource == DevicePolicyResources.Drawable.Source.UNDEFINED) {
+ updated |= updateDrawable(drawableId, drawableStyle, resource);
+ } else {
+ updated |= updateDrawableForSource(drawableId, drawableSource, resource);
+ }
+ }
+ if (!updated) {
+ return false;
+ }
+ synchronized (mLock) {
+ write();
+ return true;
+ }
+ }
+
+ private boolean updateDrawable(
+ int drawableId, int drawableStyle, ParcelableResource updatableResource) {
+ if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
+ throw new IllegalArgumentException(
+ "Can't update drawable resource, invalid drawable " + "id " + drawableId);
+ }
+ if (!UPDATABLE_DRAWABLE_STYLES.contains(drawableStyle)) {
+ throw new IllegalArgumentException(
+ "Can't update drawable resource, invalid style id " + drawableStyle);
+ }
+ synchronized (mLock) {
+ if (!mUpdatedDrawablesForStyle.containsKey(drawableId)) {
+ mUpdatedDrawablesForStyle.put(drawableId, new HashMap<>());
+ }
+ ParcelableResource current = mUpdatedDrawablesForStyle.get(drawableId).get(
+ drawableStyle);
+ if (updatableResource.equals(current)) {
+ return false;
+ }
+ mUpdatedDrawablesForStyle.get(drawableId).put(drawableStyle, updatableResource);
+ return true;
+ }
+ }
+
+ // TODO(b/214576716): change this to respect style
+ private boolean updateDrawableForSource(
+ int drawableId, int drawableSource, ParcelableResource updatableResource) {
+ if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
+ throw new IllegalArgumentException("Can't update drawable resource, invalid drawable "
+ + "id " + drawableId);
+ }
+ if (!UPDATABLE_DRAWABLE_SOURCES.contains(drawableSource)) {
+ throw new IllegalArgumentException("Can't update drawable resource, invalid source id "
+ + drawableSource);
+ }
+ synchronized (mLock) {
+ if (!mUpdatedDrawablesForSource.containsKey(drawableId)) {
+ mUpdatedDrawablesForSource.put(drawableId, new HashMap<>());
+ }
+ ParcelableResource current = mUpdatedDrawablesForSource.get(drawableId).get(
+ drawableSource);
+ if (updatableResource.equals(current)) {
+ return false;
+ }
+ mUpdatedDrawablesForSource.get(drawableId).put(drawableSource, updatableResource);
+ return true;
+ }
+ }
+
+ /**
+ * Returns {@code false} if no resources were removed.
+ */
+ boolean removeDrawables(@NonNull int[] drawableIds) {
+ synchronized (mLock) {
+ boolean removed = false;
+ for (int i = 0; i < drawableIds.length; i++) {
+ int drawableId = drawableIds[i];
+ removed |= mUpdatedDrawablesForStyle.remove(drawableId) != null
+ || mUpdatedDrawablesForSource.remove(drawableId) != null;
+ }
+ if (!removed) {
+ return false;
+ }
+ write();
+ return true;
+ }
+ }
+
+ @Nullable
+ ParcelableResource getDrawable(
+ int drawableId, int drawableStyle, int drawableSource) {
+ if (!UPDATABLE_DRAWABLE_IDS.contains(drawableId)) {
+ Log.e(TAG, "Can't get updated drawable resource, invalid drawable id "
+ + drawableId);
+ return null;
+ }
+ if (!UPDATABLE_DRAWABLE_STYLES.contains(drawableStyle)) {
+ Log.e(TAG, "Can't get updated drawable resource, invalid style id "
+ + drawableStyle);
+ return null;
+ }
+ if (!UPDATABLE_DRAWABLE_SOURCES.contains(drawableSource)) {
+ Log.e(TAG, "Can't get updated drawable resource, invalid source id "
+ + drawableSource);
+ return null;
+ }
+ if (mUpdatedDrawablesForSource.containsKey(drawableId)
+ && mUpdatedDrawablesForSource.get(drawableId).containsKey(drawableSource)) {
+ return mUpdatedDrawablesForSource.get(drawableId).get(drawableSource);
+ }
+ if (!mUpdatedDrawablesForStyle.containsKey(drawableId)) {
+ Log.d(TAG, "No updated drawable found for drawable id " + drawableId);
+ return null;
+ }
+ if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(drawableStyle)) {
+ return mUpdatedDrawablesForStyle.get(drawableId).get(drawableStyle);
+ }
+
+ if (mUpdatedDrawablesForStyle.get(drawableId).containsKey(Style.DEFAULT)) {
+ return mUpdatedDrawablesForStyle.get(drawableId).get(Style.DEFAULT);
+ }
+ Log.d(TAG, "No updated drawable found for drawable id " + drawableId);
+ return null;
+ }
+
+ private void write() {
+ Log.d(TAG, "Writing updated resources to file.");
+ new ResourcesReaderWriter().writeToFileLocked();
+ }
+
+ void load() {
+ synchronized (mLock) {
+ new ResourcesReaderWriter().readFromFileLocked();
+ }
+ }
+
+ private File getResourcesFile() {
+ return new File(mInjector.environmentGetDataSystemDirectory(), UPDATED_RESOURCES_XML);
+ }
+
+ private class ResourcesReaderWriter {
+ private final File mFile;
+ private ResourcesReaderWriter() {
+ mFile = getResourcesFile();
+ }
+
+ void writeToFileLocked() {
+ Log.d(TAG, "Writing to " + mFile);
+
+ AtomicFile f = new AtomicFile(mFile);
+ FileOutputStream outputStream = null;
+ try {
+ outputStream = f.startWrite();
+ TypedXmlSerializer out = Xml.resolveSerializer(outputStream);
+
+ // Root tag
+ out.startDocument(null, true);
+ out.startTag(null, TAG_ROOT);
+
+ // Actual content
+ writeInner(out);
+
+ // Close root
+ out.endTag(null, TAG_ROOT);
+ out.endDocument();
+ out.flush();
+
+ // Commit the content.
+ f.finishWrite(outputStream);
+ outputStream = null;
+
+ } catch (IOException e) {
+ Log.e(TAG, "Exception when writing", e);
+ if (outputStream != null) {
+ f.failWrite(outputStream);
+ }
+ }
+ }
+
+ void readFromFileLocked() {
+ if (!mFile.exists()) {
+ Log.d(TAG, "" + mFile + " doesn't exist");
+ return;
+ }
+
+ Log.d(TAG, "Reading from " + mFile);
+ AtomicFile f = new AtomicFile(mFile);
+ InputStream input = null;
+ try {
+ input = f.openRead();
+ TypedXmlPullParser parser = Xml.resolvePullParser(input);
+
+ int type;
+ int depth = 0;
+ while ((type = parser.next()) != TypedXmlPullParser.END_DOCUMENT) {
+ switch (type) {
+ case TypedXmlPullParser.START_TAG:
+ depth++;
+ break;
+ case TypedXmlPullParser.END_TAG:
+ depth--;
+ // fallthrough
+ default:
+ continue;
+ }
+ // Check the root tag
+ String tag = parser.getName();
+ if (depth == 1) {
+ if (!TAG_ROOT.equals(tag)) {
+ Log.e(TAG, "Invalid root tag: " + tag);
+ return;
+ }
+ continue;
+ }
+ // readInner() will only see START_TAG at depth >= 2.
+ if (!readInner(parser, depth, tag)) {
+ return; // Error
+ }
+ }
+ } catch (XmlPullParserException | IOException e) {
+ Log.e(TAG, "Error parsing resources file", e);
+ } finally {
+ IoUtils.closeQuietly(input);
+ }
+ }
+
+ void writeInner(TypedXmlSerializer out) throws IOException {
+ if (mUpdatedDrawablesForStyle != null && !mUpdatedDrawablesForStyle.isEmpty()) {
+ for (Map.Entry<Integer, Map<Integer, ParcelableResource>> drawableEntry
+ : mUpdatedDrawablesForStyle.entrySet()) {
+ out.startTag(/* namespace= */ null, TAG_DRAWABLE_STYLE_ENTRY);
+ out.attributeInt(
+ /* namespace= */ null, ATTR_DRAWABLE_ID, drawableEntry.getKey());
+ out.attributeInt(
+ /* namespace= */ null,
+ ATTR_DRAWABLE_STYLE_SIZE,
+ drawableEntry.getValue().size());
+ int counter = 0;
+ for (Map.Entry<Integer, ParcelableResource> styleEntry
+ : drawableEntry.getValue().entrySet()) {
+ out.attributeInt(
+ /* namespace= */ null,
+ ATTR_DRAWABLE_STYLE + (counter++),
+ styleEntry.getKey());
+ styleEntry.getValue().writeToXmlFile(out);
+ }
+ out.endTag(/* namespace= */ null, TAG_DRAWABLE_STYLE_ENTRY);
+ }
+ }
+ if (mUpdatedDrawablesForSource != null && !mUpdatedDrawablesForSource.isEmpty()) {
+ for (Map.Entry<Integer, Map<Integer, ParcelableResource>> drawableEntry
+ : mUpdatedDrawablesForSource.entrySet()) {
+ out.startTag(/* namespace= */ null, TAG_DRAWABLE_SOURCE_ENTRY);
+ out.attributeInt(
+ /* namespace= */ null, ATTR_DRAWABLE_ID, drawableEntry.getKey());
+ out.attributeInt(
+ /* namespace= */ null,
+ ATTR_DRAWABLE_SOURCE_SIZE,
+ drawableEntry.getValue().size());
+ int counter = 0;
+ for (Map.Entry<Integer, ParcelableResource> sourceEntry
+ : drawableEntry.getValue().entrySet()) {
+ out.attributeInt(
+ /* namespace= */ null,
+ ATTR_DRAWABLE_SOURCE + (counter++),
+ sourceEntry.getKey());
+ sourceEntry.getValue().writeToXmlFile(out);
+ }
+ out.endTag(/* namespace= */ null, TAG_DRAWABLE_SOURCE_ENTRY);
+ }
+ }
+ }
+
+ private boolean readInner(
+ TypedXmlPullParser parser, int depth, String tag)
+ throws XmlPullParserException, IOException {
+ if (depth > 2) {
+ return true; // Ignore
+ }
+ switch (tag) {
+ case TAG_DRAWABLE_STYLE_ENTRY:
+ int drawableId = parser.getAttributeInt(
+ /* namespace= */ null, ATTR_DRAWABLE_ID);
+ mUpdatedDrawablesForStyle.put(
+ drawableId,
+ new HashMap<>());
+ int size = parser.getAttributeInt(
+ /* namespace= */ null, ATTR_DRAWABLE_STYLE_SIZE);
+ for (int i = 0; i < size; i++) {
+ int style = parser.getAttributeInt(
+ /* namespace= */ null, ATTR_DRAWABLE_STYLE + i);
+ mUpdatedDrawablesForStyle.get(drawableId).put(
+ style,
+ ParcelableResource.createFromXml(parser));
+ }
+ break;
+ case TAG_DRAWABLE_SOURCE_ENTRY:
+ drawableId = parser.getAttributeInt(
+ /* namespace= */ null, ATTR_DRAWABLE_ID);
+ mUpdatedDrawablesForSource.put(drawableId, new HashMap<>());
+ size = parser.getAttributeInt(
+ /* namespace= */ null, ATTR_DRAWABLE_SOURCE_SIZE);
+ for (int i = 0; i < size; i++) {
+ int source = parser.getAttributeInt(
+ /* namespace= */ null, ATTR_DRAWABLE_SOURCE + i);
+ mUpdatedDrawablesForSource.get(drawableId).put(
+ source,
+ ParcelableResource.createFromXml(parser));
+ }
+ break;
+ default:
+ Log.e(TAG, "Unexpected tag: " + tag);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ public static class Injector {
+ File environmentGetDataSystemDirectory() {
+ return Environment.getDataSystemDirectory();
+ }
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 6caf731..0595b73 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -26,6 +26,7 @@
import static android.app.admin.DeviceAdminReceiver.ACTION_COMPLIANCE_ACKNOWLEDGEMENT_REQUIRED;
import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.ACTION_CHECK_POLICY_COMPLIANCE;
+import static android.app.admin.DevicePolicyManager.ACTION_DEVICE_POLICY_RESOURCE_UPDATED;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER;
@@ -56,6 +57,8 @@
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
import static android.app.admin.DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_PER_USER;
+import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_ID;
+import static android.app.admin.DevicePolicyManager.EXTRA_RESOURCE_TYPE_DRAWABLE;
import static android.app.admin.DevicePolicyManager.ID_TYPE_BASE_INFO;
import static android.app.admin.DevicePolicyManager.ID_TYPE_IMEI;
import static android.app.admin.DevicePolicyManager.ID_TYPE_INDIVIDUAL_ATTESTATION;
@@ -161,6 +164,7 @@
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DeviceAdminReceiver;
import android.app.admin.DevicePolicyCache;
+import android.app.admin.DevicePolicyDrawableResource;
import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManager.DeviceOwnerType;
@@ -177,6 +181,7 @@
import android.app.admin.ManagedProfileProvisioningParams;
import android.app.admin.NetworkEvent;
import android.app.admin.ParcelableGranteeMap;
+import android.app.admin.ParcelableResource;
import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordPolicy;
import android.app.admin.SecurityLog;
@@ -716,6 +721,8 @@
// Guarded by mHandler
private @UserIdInt int mNetworkLoggingNotificationUserId = UserHandle.USER_NULL;
+ private final DeviceManagementResourcesProvider mDeviceManagementResourcesProvider;
+
private static final boolean ENABLE_LOCK_GUARD = true;
/**
@@ -1740,6 +1747,10 @@
void setDevicePolicySafetyChecker(DevicePolicySafetyChecker safetyChecker) {
mSafetyChecker = safetyChecker;
}
+
+ DeviceManagementResourcesProvider getDeviceManagementResourcesProvider() {
+ return new DeviceManagementResourcesProvider();
+ }
}
/**
@@ -1792,6 +1803,8 @@
mTransferOwnershipMetadataManager = mInjector.newTransferOwnershipMetadataManager();
mBugreportCollectionManager = new RemoteBugreportManager(this, mInjector);
+ mDeviceManagementResourcesProvider = mInjector.getDeviceManagementResourcesProvider();
+
// "Lite" interface is available even when the device doesn't have the feature
LocalServices.addService(DevicePolicyManagerLiteInternal.class, mLocalService);
if (!mHasFeature) {
@@ -1838,6 +1851,8 @@
loadOwners();
performPolicyVersionUpgrade();
+
+ mDeviceManagementResourcesProvider.load();
}
/**
@@ -17956,4 +17971,54 @@
&& mInjector.getUsbManager().getUsbHalVersion() >= UsbManager.USB_HAL_V1_3
);
}
+
+ @Override
+ public void setDrawables(@NonNull List<DevicePolicyDrawableResource> drawables) {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+
+ Objects.requireNonNull(drawables, "drawables must be provided.");
+
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ if (mDeviceManagementResourcesProvider.updateDrawables(drawables)) {
+ sendDrawableUpdatedBroadcast(
+ drawables.stream().mapToInt(d -> d.getDrawableId()).toArray());
+ }
+ });
+ }
+
+ @Override
+ public void resetDrawables(@NonNull int[] drawableIds) {
+ Preconditions.checkCallAuthorization(hasCallingOrSelfPermission(
+ android.Manifest.permission.UPDATE_DEVICE_MANAGEMENT_RESOURCES));
+
+ Objects.requireNonNull(drawableIds, "drawableIds must be provided.");
+
+ mInjector.binderWithCleanCallingIdentity(() -> {
+ if (mDeviceManagementResourcesProvider.removeDrawables(drawableIds)) {
+ sendDrawableUpdatedBroadcast(drawableIds);
+ }
+ });
+ }
+
+ @Override
+ public ParcelableResource getDrawable(int drawableId, int drawableStyle, int drawableSource) {
+ return mInjector.binderWithCleanCallingIdentity(() ->
+ mDeviceManagementResourcesProvider.getDrawable(
+ drawableId, drawableStyle, drawableSource));
+ }
+
+ private void sendDrawableUpdatedBroadcast(int[] drawableIds) {
+ final Intent intent = new Intent(ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
+ intent.putExtra(EXTRA_RESOURCE_ID, drawableIds);
+ intent.putExtra(EXTRA_RESOURCE_TYPE_DRAWABLE, /* value= */ true);
+ intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+ List<UserInfo> users = mUserManager.getAliveUsers();
+ for (int i = 0; i < users.size(); i++) {
+ UserHandle user = users.get(i).getUserHandle();
+ mContext.sendBroadcastAsUser(intent, user);
+ }
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ee8288e..c767f4d 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -152,7 +152,6 @@
import com.android.server.os.SchedulingPolicyService;
import com.android.server.people.PeopleService;
import com.android.server.pm.ApexManager;
-import com.android.server.pm.ApexSystemServiceInfo;
import com.android.server.pm.CrossProfileAppsService;
import com.android.server.pm.DataLoaderManagerService;
import com.android.server.pm.DynamicCodeLoggingService;
@@ -221,8 +220,8 @@
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
-import java.util.List;
import java.util.Locale;
+import java.util.Map;
import java.util.Timer;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
@@ -261,10 +260,6 @@
"com.android.server.companion.virtual.VirtualDeviceManagerService";
private static final String STATS_COMPANION_APEX_PATH =
"/apex/com.android.os.statsd/javalib/service-statsd.jar";
- private static final String SCHEDULING_APEX_PATH =
- "/apex/com.android.scheduling/javalib/service-scheduling.jar";
- private static final String REBOOT_READINESS_LIFECYCLE_CLASS =
- "com.android.server.scheduling.RebootReadinessManagerService$Lifecycle";
private static final String CONNECTIVITY_SERVICE_APEX_PATH =
"/apex/com.android.tethering/javalib/service-connectivity.jar";
private static final String STATS_COMPANION_LIFECYCLE_CLASS =
@@ -1460,7 +1455,7 @@
// TelecomLoader hooks into classes with defined HFP logic,
// so check for either telephony or microphone.
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MICROPHONE) ||
- mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
t.traceBegin("StartTelecomLoaderService");
mSystemServiceManager.startService(TelecomLoaderService.class);
t.traceEnd();
@@ -1468,7 +1463,7 @@
t.traceBegin("StartTelephonyRegistry");
telephonyRegistry = new TelephonyRegistry(
- context, new TelephonyRegistry.ConfigurationProvider());
+ context, new TelephonyRegistry.ConfigurationProvider());
ServiceManager.addService("telephony.registry", telephonyRegistry);
t.traceEnd();
@@ -2547,12 +2542,6 @@
STATS_COMPANION_LIFECYCLE_CLASS, STATS_COMPANION_APEX_PATH);
t.traceEnd();
- // Reboot Readiness
- t.traceBegin("StartRebootReadinessManagerService");
- mSystemServiceManager.startServiceFromJar(
- REBOOT_READINESS_LIFECYCLE_CLASS, SCHEDULING_APEX_PATH);
- t.traceEnd();
-
// Statsd pulled atoms
t.traceBegin("StartStatsPullAtomService");
mSystemServiceManager.startService(STATS_PULL_ATOM_SERVICE_CLASS);
@@ -2999,9 +2988,7 @@
t.traceEnd();
t.traceBegin("MakeTelephonyRegistryReady");
try {
- if (telephonyRegistryF != null) {
- telephonyRegistryF.systemRunning();
- }
+ if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
} catch (Throwable e) {
reportWtf("Notifying TelephonyRegistry running", e);
}
@@ -3066,12 +3053,10 @@
*/
private void startApexServices(@NonNull TimingsTraceAndSlog t) {
t.traceBegin("startApexServices");
- // TODO(b/192880996): get the list from "android" package, once the manifest entries
- // are migrated to system manifest.
- List<ApexSystemServiceInfo> services = ApexManager.getInstance().getApexSystemServices();
- for (ApexSystemServiceInfo info : services) {
- String name = info.getName();
- String jarPath = info.getJarPath();
+ Map<String, String> services = ApexManager.getInstance().getApexSystemServices();
+ // TODO(satayev): introduce android:order for services coming the same apexes
+ for (String name : new TreeSet<>(services.keySet())) {
+ String jarPath = services.get(name);
t.traceBegin("starting " + name);
if (TextUtils.isEmpty(jarPath)) {
mSystemServiceManager.startService(name);
diff --git a/services/tests/apexsystemservices/Android.bp b/services/tests/apexsystemservices/Android.bp
index 01e90a8..a6ed1ae 100644
--- a/services/tests/apexsystemservices/Android.bp
+++ b/services/tests/apexsystemservices/Android.bp
@@ -37,5 +37,8 @@
"truth-prebuilt",
"modules-utils-build-testing",
],
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "mts-core",
+ ],
}
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp b/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
index 0a9b7b1..16d6241 100644
--- a/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/Android.bp
@@ -32,7 +32,7 @@
name: "test_com.android.server",
manifest: "manifest.json",
androidManifest: "AndroidManifest.xml",
- java_libs: ["FakeApexSystemServices"],
+ java_libs: ["FakeApexSystemService"],
file_contexts: ":apex.test-file_contexts",
key: "test_com.android.server.key",
updatable: false,
diff --git a/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml b/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
index 6bec284..eb741ca 100644
--- a/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
+++ b/services/tests/apexsystemservices/apexes/test_com.android.server/AndroidManifest.xml
@@ -21,29 +21,21 @@
<application android:hasCode="false" android:testOnly="true">
<apex-system-service
android:name="com.android.server.testing.FakeApexSystemService"
- android:path="/apex/test_com.android.server/javalib/FakeApexSystemServices.jar"
- android:minSdkVersion="30"
- />
-
- <apex-system-service
- android:name="com.android.server.testing.FakeApexSystemService2"
- android:path="/apex/test_com.android.server/javalib/FakeApexSystemServices.jar"
- android:minSdkVersion="30"
- android:initOrder="1"
- />
+ android:path="/apex/test_com.android.server/javalib/FakeApexSystemService.jar"
+ android:minSdkVersion="30"/>
<!-- Always inactive system service, since maxSdkVersion is low -->
<apex-system-service
- android:name="com.android.server.testing.OldApexSystemService"
- android:path="/apex/test_com.android.server/javalib/fake.jar"
+ android:name="com.android.apex.test.OldApexSystemService"
+ android:path="/apex/com.android.apex.test/javalib/fake.jar"
android:minSdkVersion="1"
android:maxSdkVersion="1"
/>
<!-- Always inactive system service, since minSdkVersion is high -->
<apex-system-service
- android:name="com.android.server.testing.NewApexSystemService"
- android:path="/apex/test_com.android.server/javalib/fake.jar"
+ android:name="com.android.apex.test.NewApexSystemService"
+ android:path="/apex/com.android.apex.test/javalib/fake.jar"
android:minSdkVersion="999999"
/>
</application>
diff --git a/services/tests/apexsystemservices/services/Android.bp b/services/tests/apexsystemservices/service/Android.bp
similarity index 94%
rename from services/tests/apexsystemservices/services/Android.bp
rename to services/tests/apexsystemservices/service/Android.bp
index 477ea4c..9d04f39 100644
--- a/services/tests/apexsystemservices/services/Android.bp
+++ b/services/tests/apexsystemservices/service/Android.bp
@@ -8,7 +8,7 @@
}
java_library {
- name: "FakeApexSystemServices",
+ name: "FakeApexSystemService",
srcs: ["**/*.java"],
sdk_version: "system_server_current",
libs: [
diff --git a/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService.java b/services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
similarity index 100%
rename from services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService.java
rename to services/tests/apexsystemservices/service/src/com/android/server/testing/FakeApexSystemService.java
diff --git a/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java b/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java
deleted file mode 100644
index e83343b..0000000
--- a/services/tests/apexsystemservices/services/src/com/android/server/testing/FakeApexSystemService2.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.testing;
-
-import android.content.Context;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import com.android.server.SystemService;
-
-/**
- * A fake system service that just logs when it is started.
- */
-public class FakeApexSystemService2 extends SystemService {
-
- private static final String TAG = "FakeApexSystemService";
-
- public FakeApexSystemService2(@NonNull Context context) {
- super(context);
- }
-
- @Override
- public void onStart() {
- Log.d(TAG, "FakeApexSystemService2 onStart");
- }
-}
diff --git a/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
index 7ab7b6ed..2b453a9 100644
--- a/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
+++ b/services/tests/apexsystemservices/src/com/android/server/ApexSystemServicesTestCases.java
@@ -37,10 +37,6 @@
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
-import java.util.Objects;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-
@RunWith(DeviceJUnit4ClassRunner.class)
public class ApexSystemServicesTestCases extends BaseHostJUnit4Test {
@@ -71,7 +67,7 @@
}
@Test
- public void testNoApexSystemServiceStartsWithoutApex() throws Exception {
+ public void noApexSystemServerStartsWithoutApex() throws Exception {
mPreparer.reboot();
assertThat(getFakeApexSystemServiceLogcat())
@@ -79,7 +75,7 @@
}
@Test
- public void testApexSystemServiceStarts() throws Exception {
+ public void apexSystemServerStarts() throws Exception {
// Pre-install the apex
String apex = "test_com.android.server.apex";
mPreparer.pushResourceFile(apex, "/system/apex/" + apex);
@@ -90,40 +86,9 @@
.contains("FakeApexSystemService onStart");
}
- @Test
- public void testInitOrder() throws Exception {
- // Pre-install the apex
- String apex = "test_com.android.server.apex";
- mPreparer.pushResourceFile(apex, "/system/apex/" + apex);
- // Reboot activates the apex
- mPreparer.reboot();
-
- assertThat(getFakeApexSystemServiceLogcat().lines()
- .map(ApexSystemServicesTestCases::getDebugMessage)
- .filter(Objects::nonNull)
- .collect(Collectors.toList()))
- .containsExactly(
- // Second service has a higher initOrder and must be started first
- "FakeApexSystemService2 onStart",
- "FakeApexSystemService onStart"
- )
- .inOrder();
- }
-
private String getFakeApexSystemServiceLogcat() throws DeviceNotAvailableException {
return mDevice.executeAdbCommand("logcat", "-v", "brief", "-d", "FakeApexSystemService:D",
"*:S");
}
- private static final Pattern DEBUG_MESSAGE =
- Pattern.compile("(FakeApexSystemService[0-9]* onStart)");
-
- private static String getDebugMessage(String logcatLine) {
- return DEBUG_MESSAGE.matcher(logcatLine)
- .results()
- .map(m -> m.group(1))
- .findFirst()
- .orElse(null);
- }
-
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index c3a364e..171af77 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -25,6 +25,7 @@
"test-apps/JobTestApp/src/**/*.java",
"test-apps/SuspendTestApp/src/**/*.java",
+ ":service-bluetooth-tests-sources", // TODO(b/214988855) : Remove once framework-bluetooth jar is ready
],
static_libs: [
"frameworks-base-testutils",
diff --git a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java b/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
deleted file mode 100644
index a1d4c20..0000000
--- a/services/tests/servicestests/src/com/android/server/BluetoothAirplaneModeListenerTest.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import static org.mockito.Mockito.*;
-
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.os.Looper;
-import android.provider.Settings;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class BluetoothAirplaneModeListenerTest {
- private Context mContext;
- private BluetoothAirplaneModeListener mBluetoothAirplaneModeListener;
- private BluetoothAdapter mBluetoothAdapter;
- private BluetoothModeChangeHelper mHelper;
-
- @Mock BluetoothManagerService mBluetoothManagerService;
-
- @Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getTargetContext();
-
- mHelper = mock(BluetoothModeChangeHelper.class);
- when(mHelper.getSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT))
- .thenReturn(BluetoothAirplaneModeListener.MAX_TOAST_COUNT);
- doNothing().when(mHelper).setSettingsInt(anyString(), anyInt());
- doNothing().when(mHelper).showToastMessage();
- doNothing().when(mHelper).onAirplaneModeChanged(any(BluetoothManagerService.class));
-
- mBluetoothAirplaneModeListener = new BluetoothAirplaneModeListener(
- mBluetoothManagerService, Looper.getMainLooper(), mContext);
- mBluetoothAirplaneModeListener.start(mHelper);
- }
-
- @Test
- public void testIgnoreOnAirplanModeChange() {
- Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
-
- when(mHelper.isBluetoothOn()).thenReturn(true);
- Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
-
- when(mHelper.isMediaProfileConnected()).thenReturn(true);
- Assert.assertFalse(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
-
- when(mHelper.isAirplaneModeOn()).thenReturn(true);
- Assert.assertTrue(mBluetoothAirplaneModeListener.shouldSkipAirplaneModeChange());
- }
-
- @Test
- public void testHandleAirplaneModeChange_InvokeAirplaneModeChanged() {
- mBluetoothAirplaneModeListener.handleAirplaneModeChange();
- verify(mHelper).onAirplaneModeChanged(mBluetoothManagerService);
- }
-
- @Test
- public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_NotPopToast() {
- mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
- when(mHelper.isBluetoothOn()).thenReturn(true);
- when(mHelper.isMediaProfileConnected()).thenReturn(true);
- when(mHelper.isAirplaneModeOn()).thenReturn(true);
- mBluetoothAirplaneModeListener.handleAirplaneModeChange();
-
- verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
- BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
- verify(mHelper, times(0)).showToastMessage();
- verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService);
- }
-
- @Test
- public void testHandleAirplaneModeChange_NotInvokeAirplaneModeChanged_PopToast() {
- mBluetoothAirplaneModeListener.mToastCount = 0;
- when(mHelper.isBluetoothOn()).thenReturn(true);
- when(mHelper.isMediaProfileConnected()).thenReturn(true);
- when(mHelper.isAirplaneModeOn()).thenReturn(true);
- mBluetoothAirplaneModeListener.handleAirplaneModeChange();
-
- verify(mHelper).setSettingsInt(Settings.Global.BLUETOOTH_ON,
- BluetoothManagerService.BLUETOOTH_ON_AIRPLANE);
- verify(mHelper).showToastMessage();
- verify(mHelper, times(0)).onAirplaneModeChanged(mBluetoothManagerService);
- }
-
- @Test
- public void testIsPopToast_PopToast() {
- mBluetoothAirplaneModeListener.mToastCount = 0;
- Assert.assertTrue(mBluetoothAirplaneModeListener.shouldPopToast());
- verify(mHelper).setSettingsInt(BluetoothAirplaneModeListener.TOAST_COUNT, 1);
- }
-
- @Test
- public void testIsPopToast_NotPopToast() {
- mBluetoothAirplaneModeListener.mToastCount = BluetoothAirplaneModeListener.MAX_TOAST_COUNT;
- Assert.assertFalse(mBluetoothAirplaneModeListener.shouldPopToast());
- verify(mHelper, times(0)).setSettingsInt(anyString(), anyInt());
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 176e5a9..54945e4 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -19,6 +19,7 @@
import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyFloat;
@@ -34,18 +35,22 @@
import android.hardware.SensorManager;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
import android.os.Handler;
+import android.os.test.TestLooper;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.testutils.OffsettableClock;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@SmallTest
@@ -61,7 +66,11 @@
private static final float DOZE_SCALE_FACTOR = 0.0f;
private static final boolean RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG = false;
private static final int LIGHT_SENSOR_WARMUP_TIME = 0;
-
+ private static final int AMBIENT_LIGHT_HORIZON_SHORT = 1000;
+ private static final int AMBIENT_LIGHT_HORIZON_LONG = 2000;
+ private static final float EPSILON = 0.001f;
+ private OffsettableClock mClock = new OffsettableClock();
+ private TestLooper mTestLooper;
private Context mContext;
private AutomaticBrightnessController mController;
@@ -91,21 +100,36 @@
}
}
+ private void advanceTime(long timeMs) {
+ mClock.fastForward(timeMs);
+ mTestLooper.dispatchAll();
+ }
+
private AutomaticBrightnessController setupController(Sensor lightSensor) {
+ mClock = new OffsettableClock.Stopped();
+ mTestLooper = new TestLooper(mClock::now);
+
AutomaticBrightnessController controller = new AutomaticBrightnessController(
new AutomaticBrightnessController.Injector() {
@Override
public Handler getBackgroundThreadHandler() {
return mNoOpHandler;
}
- },
- () -> { }, mContext.getMainLooper(), mSensorManager, lightSensor,
+
+ @Override
+ AutomaticBrightnessController.Clock createClock() {
+ return mClock::now;
+ }
+
+ }, // pass in test looper instead, pass in offsetable clock
+ () -> { }, mTestLooper.getLooper(), mSensorManager, lightSensor,
mBrightnessMappingStrategy, LIGHT_SENSOR_WARMUP_TIME, BRIGHTNESS_MIN_FLOAT,
BRIGHTNESS_MAX_FLOAT, DOZE_SCALE_FACTOR, LIGHT_SENSOR_RATE,
INITIAL_LIGHT_SENSOR_RATE, BRIGHTENING_LIGHT_DEBOUNCE_CONFIG,
DARKENING_LIGHT_DEBOUNCE_CONFIG, RESET_AMBIENT_LUX_AFTER_WARMUP_CONFIG,
mAmbientBrightnessThresholds, mScreenBrightnessThresholds,
- mContext, mHbmController, mIdleBrightnessMappingStrategy
+ mContext, mHbmController, mIdleBrightnessMappingStrategy,
+ AMBIENT_LIGHT_HORIZON_SHORT, AMBIENT_LIGHT_HORIZON_LONG
);
when(mHbmController.getCurrentBrightnessMax()).thenReturn(BRIGHTNESS_MAX_FLOAT);
@@ -276,4 +300,95 @@
// Ensure we use the correct mapping strategy
verify(mIdleBrightnessMappingStrategy, times(1)).addUserDataPoint(1000f, 0.5f);
}
+
+ @Test
+ public void testAmbientLightHorizon() throws Exception {
+ // create abc
+ Sensor lightSensor = TestUtils.createSensor(Sensor.TYPE_LIGHT, "Light Sensor");
+ mController = setupController(lightSensor);
+ ArgumentCaptor<SensorEventListener> listenerCaptor =
+ ArgumentCaptor.forClass(SensorEventListener.class);
+ verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(lightSensor),
+ eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+ SensorEventListener listener = listenerCaptor.getValue();
+
+ long increment = 500;
+ // set autobrightness to low
+ // t = 0
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0));
+
+ // t = 500
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0));
+
+ // t = 1000
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0));
+ assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
+
+ // t = 1500
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0));
+ assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
+
+ // t = 2000
+ // ensure that our reading is at 0.
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0));
+ assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
+
+ // t = 2500
+ // first 10000 lux sensor event reading
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 10000));
+ assertTrue(mController.getAmbientLux() > 0.0f);
+ assertTrue(mController.getAmbientLux() < 10000.0f);
+
+ // t = 3000
+ // lux reading should still not yet be 10000.
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 10000));
+ assertTrue(mController.getAmbientLux() > 0.0f);
+ assertTrue(mController.getAmbientLux() < 10000.0f);
+
+ // t = 3500
+ mClock.fastForward(increment);
+ // lux has been high (10000) for 1000ms.
+ // lux reading should be 10000
+ // short horizon (ambient lux) is high, long horizon is still not high
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 10000));
+ assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
+
+ // t = 4000
+ // stay high
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 10000));
+ assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
+
+ // t = 4500
+ Mockito.clearInvocations(mBrightnessMappingStrategy);
+ mClock.fastForward(increment);
+ // short horizon is high, long horizon is high too
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 10000));
+ verify(mBrightnessMappingStrategy, times(1)).getBrightness(10000, null, -1);
+ assertEquals(10000.0f, mController.getAmbientLux(), EPSILON);
+
+ // t = 5000
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0));
+ assertTrue(mController.getAmbientLux() > 0.0f);
+ assertTrue(mController.getAmbientLux() < 10000.0f);
+
+ // t = 5500
+ mClock.fastForward(increment);
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0));
+ assertTrue(mController.getAmbientLux() > 0.0f);
+ assertTrue(mController.getAmbientLux() < 10000.0f);
+
+ // t = 6000
+ mClock.fastForward(increment);
+ // ambient lux goes to 0
+ listener.onSensorChanged(TestUtils.createSensorEvent(lightSensor, 0));
+ assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
index 2f5993d1..7f7c716 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ApexManagerTest.java
@@ -61,7 +61,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.List;
+import java.util.Map;
@SmallTest
@Presubmit
@@ -136,10 +136,9 @@
mApexManager.scanApexPackagesTraced(mPackageParser2,
ParallelPackageParser.makeExecutorService());
- List<ApexSystemServiceInfo> services = mApexManager.getApexSystemServices();
+ Map<String, String> services = mApexManager.getApexSystemServices();
assertThat(services).hasSize(1);
- assertThat(services.stream().map(ApexSystemServiceInfo::getName).findFirst().orElse(null))
- .matches("com.android.apex.test.ApexSystemService");
+ assertThat(services).containsKey("com.android.apex.test.ApexSystemService");
}
@Test
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 53dff54..be233b8 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -42,6 +42,7 @@
import android.telephony.ims.stub.SipTransportImplBase;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import com.android.ims.internal.IImsFeatureStatusCallback;
import com.android.internal.annotations.VisibleForTesting;
@@ -180,6 +181,12 @@
// call ImsFeature#onFeatureRemoved.
private final SparseArray<SparseArray<ImsFeature>> mFeaturesBySlot = new SparseArray<>();
+ // A map of slot id -> boolean array, where each entry in the boolean array corresponds to an
+ // ImsFeature that was created for a slot id and not a sub id for backwards compatibility
+ // purposes.
+ private final SparseArray<SparseBooleanArray> mCreateImsFeatureWithSlotIdFlagMap =
+ new SparseArray<>();
+
private IImsServiceControllerListener mListener;
private Executor mExecutor;
@@ -222,15 +229,36 @@
}
@Override
- public IImsMmTelFeature createMmTelFeature(int slotId) {
- return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId),
- "createMmTelFeature");
+ public IImsMmTelFeature createMmTelFeature(int slotId, int subId) {
+ MmTelFeature f = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL);
+ if (f == null) {
+ return executeMethodAsyncForResult(() -> createMmTelFeatureInternal(slotId, subId),
+ "createMmTelFeature");
+ } else {
+ return f.getBinder();
+ }
}
@Override
- public IImsRcsFeature createRcsFeature(int slotId) {
- return executeMethodAsyncForResult(() -> createRcsFeatureInternal(slotId),
- "createRcsFeature");
+ public IImsMmTelFeature createEmergencyOnlyMmTelFeature(int slotId) {
+ MmTelFeature f = (MmTelFeature) getImsFeature(slotId, ImsFeature.FEATURE_MMTEL);
+ if (f == null) {
+ return executeMethodAsyncForResult(() -> createEmergencyOnlyMmTelFeatureInternal(
+ slotId), "createEmergencyOnlyMmTelFeature");
+ } else {
+ return f.getBinder();
+ }
+ }
+
+ @Override
+ public IImsRcsFeature createRcsFeature(int slotId, int subId) {
+ RcsFeature f = (RcsFeature) getImsFeature(slotId, ImsFeature.FEATURE_RCS);
+ if (f == null) {
+ return executeMethodAsyncForResult(() ->
+ createRcsFeatureInternal(slotId, subId), "createRcsFeature");
+ } else {
+ return f.getBinder();
+ }
}
@Override
@@ -248,9 +276,14 @@
}
@Override
- public void removeImsFeature(int slotId, int featureType) {
+ public void removeImsFeature(int slotId, int featureType, boolean changeSubId) {
+ if (changeSubId && isImsFeatureCreatedForSlot(slotId, featureType)) {
+ Log.w(LOG_TAG, "Do not remove Ims feature for compatibility");
+ return;
+ }
executeMethodAsync(() -> ImsService.this.removeImsFeature(slotId, featureType),
"removeImsFeature");
+ setImsFeatureCreatedForSlot(slotId, featureType, false);
}
@Override
@@ -279,9 +312,10 @@
}
@Override
- public IImsConfig getConfig(int slotId) {
+ public IImsConfig getConfig(int slotId, int subId) {
return executeMethodAsyncForResult(() -> {
- ImsConfigImplBase c = ImsService.this.getConfig(slotId);
+ ImsConfigImplBase c =
+ ImsService.this.getConfigForSubscription(slotId, subId);
if (c != null) {
c.setDefaultExecutor(mExecutor);
return c.getIImsConfig();
@@ -292,9 +326,10 @@
}
@Override
- public IImsRegistration getRegistration(int slotId) {
+ public IImsRegistration getRegistration(int slotId, int subId) {
return executeMethodAsyncForResult(() -> {
- ImsRegistrationImplBase r = ImsService.this.getRegistration(slotId);
+ ImsRegistrationImplBase r =
+ ImsService.this.getRegistrationForSubscription(slotId, subId);
if (r != null) {
r.setDefaultExecutor(mExecutor);
return r.getBinder();
@@ -318,13 +353,15 @@
}
@Override
- public void enableIms(int slotId) {
- executeMethodAsync(() -> ImsService.this.enableIms(slotId), "enableIms");
+ public void enableIms(int slotId, int subId) {
+ executeMethodAsync(() ->
+ ImsService.this.enableImsForSubscription(slotId, subId), "enableIms");
}
@Override
- public void disableIms(int slotId) {
- executeMethodAsync(() -> ImsService.this.disableIms(slotId), "disableIms");
+ public void disableIms(int slotId, int subId) {
+ executeMethodAsync(() ->
+ ImsService.this.disableImsForSubscription(slotId, subId), "disableIms");
}
// Call the methods with a clean calling identity on the executor and wait indefinitely for
@@ -364,16 +401,8 @@
return null;
}
- /**
- * @hide
- */
- @VisibleForTesting
- public SparseArray<ImsFeature> getFeatures(int slotId) {
- return mFeaturesBySlot.get(slotId);
- }
-
- private IImsMmTelFeature createMmTelFeatureInternal(int slotId) {
- MmTelFeature f = createMmTelFeature(slotId);
+ private IImsMmTelFeature createMmTelFeatureInternal(int slotId, int subscriptionId) {
+ MmTelFeature f = createMmTelFeatureForSubscription(slotId, subscriptionId);
if (f != null) {
setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
f.setDefaultExecutor(mExecutor);
@@ -384,8 +413,20 @@
}
}
- private IImsRcsFeature createRcsFeatureInternal(int slotId) {
- RcsFeature f = createRcsFeature(slotId);
+ private IImsMmTelFeature createEmergencyOnlyMmTelFeatureInternal(int slotId) {
+ MmTelFeature f = createEmergencyOnlyMmTelFeature(slotId);
+ if (f != null) {
+ setupFeature(f, slotId, ImsFeature.FEATURE_MMTEL);
+ f.setDefaultExecutor(mExecutor);
+ return f.getBinder();
+ } else {
+ Log.e(LOG_TAG, "createEmergencyOnlyMmTelFeatureInternal: null feature returned.");
+ return null;
+ }
+ }
+
+ private IImsRcsFeature createRcsFeatureInternal(int slotId, int subI) {
+ RcsFeature f = createRcsFeatureForSubscription(slotId, subI);
if (f != null) {
f.setDefaultExecutor(mExecutor);
setupFeature(f, slotId, ImsFeature.FEATURE_RCS);
@@ -466,6 +507,49 @@
f.onFeatureRemoved();
features.remove(featureType);
}
+
+ }
+
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public ImsFeature getImsFeature(int slotId, int featureType) {
+ synchronized (mFeaturesBySlot) {
+ // Get SparseArray for Features, by querying slot Id
+ SparseArray<ImsFeature> features = mFeaturesBySlot.get(slotId);
+ if (features == null) {
+ return null;
+ }
+ return features.get(featureType);
+ }
+ }
+
+ private void setImsFeatureCreatedForSlot(int slotId,
+ @ImsFeature.FeatureType int featureType, boolean createdForSlot) {
+ synchronized (mCreateImsFeatureWithSlotIdFlagMap) {
+ getImsFeatureCreatedForSlot(slotId).put(featureType, createdForSlot);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public boolean isImsFeatureCreatedForSlot(int slotId,
+ @ImsFeature.FeatureType int featureType) {
+ synchronized (mCreateImsFeatureWithSlotIdFlagMap) {
+ return getImsFeatureCreatedForSlot(slotId).get(featureType);
+ }
+ }
+
+ private SparseBooleanArray getImsFeatureCreatedForSlot(int slotId) {
+ SparseBooleanArray createFlag = mCreateImsFeatureWithSlotIdFlagMap.get(slotId);
+ if (createFlag == null) {
+ createFlag = new SparseBooleanArray();
+ mCreateImsFeatureWithSlotIdFlagMap.put(slotId, createFlag);
+ }
+ return createFlag;
}
/**
@@ -524,27 +608,95 @@
}
/**
+ * The framework has enabled IMS for the subscription specified, the ImsService should register
+ * for IMS and perform all appropriate initialization to bring up all ImsFeatures.
+ *
+ * @param slotId The slot ID that IMS will be enabled for.
+ * @param subscriptionId The subscription ID that IMS will be enabled for.
+ */
+ public void enableImsForSubscription(int slotId, int subscriptionId) {
+ enableIms(slotId);
+ }
+
+ /**
+ * The framework has disabled IMS for the subscription specified. The ImsService must deregister
+ * for IMS and set capability status to false for all ImsFeatures.
+ * @param slotId The slot ID that IMS will be disabled for.
+ * @param subscriptionId The subscription ID that IMS will be disabled for.
+ */
+ public void disableImsForSubscription(int slotId, int subscriptionId) {
+ disableIms(slotId);
+ }
+
+ /**
* The framework has enabled IMS for the slot specified, the ImsService should register for IMS
* and perform all appropriate initialization to bring up all ImsFeatures.
+ * @deprecated Use {@link #enableImsForSubscription} instead.
*/
+ @Deprecated
public void enableIms(int slotId) {
}
/**
* The framework has disabled IMS for the slot specified. The ImsService must deregister for IMS
* and set capability status to false for all ImsFeatures.
+ * @deprecated Use {@link #disableImsForSubscription} instead.
*/
+ @Deprecated
public void disableIms(int slotId) {
}
/**
* When called, the framework is requesting that a new {@link MmTelFeature} is created for the
+ * specified subscription.
+ *
+ * @param subscriptionId The subscription ID that the MMTEL Feature is being created for.
+ * @return The newly created {@link MmTelFeature} associated with the subscription or null if
+ * the feature is not supported.
+ */
+ public @Nullable MmTelFeature createMmTelFeatureForSubscription(int slotId,
+ int subscriptionId) {
+ setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true);
+ return createMmTelFeature(slotId);
+ }
+
+ /**
+ * When called, the framework is requesting that a new {@link RcsFeature} is created for the
+ * specified subscription.
+ *
+ * @param subscriptionId The subscription ID that the RCS Feature is being created for.
+ * @return The newly created {@link RcsFeature} associated with the subscription or null if the
+ * feature is not supported.
+ */
+ public @Nullable RcsFeature createRcsFeatureForSubscription(int slotId, int subscriptionId) {
+ setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_RCS, true);
+ return createRcsFeature(slotId);
+ }
+
+ /**
+ * When called, the framework is requesting that a new emergency-only {@link MmTelFeature} is
+ * created for the specified slot. For emergency calls, there is no known Subscription Id.
+ *
+ * @param slotId The slot ID that the MMTEL Feature is being created for.
+ * @return An MmTelFeature instance to be used for the slot ID when there is not
+ * subscription inserted. Only requested when there is no subscription active on
+ * the specified slot.
+ */
+ public @Nullable MmTelFeature createEmergencyOnlyMmTelFeature(int slotId) {
+ setImsFeatureCreatedForSlot(slotId, ImsFeature.FEATURE_MMTEL, true);
+ return createMmTelFeature(slotId);
+ }
+
+ /**
+ * When called, the framework is requesting that a new {@link MmTelFeature} is created for the
* specified slot.
+ * @deprecated Use {@link #createMmTelFeatureForSubscription} instead
*
* @param slotId The slot ID that the MMTEL Feature is being created for.
* @return The newly created {@link MmTelFeature} associated with the slot or null if the
* feature is not supported.
*/
+ @Deprecated
public MmTelFeature createMmTelFeature(int slotId) {
return null;
}
@@ -552,32 +704,62 @@
/**
* When called, the framework is requesting that a new {@link RcsFeature} is created for the
* specified slot.
+ * @deprecated Use {@link #createRcsFeatureForSubscription} instead
*
* @param slotId The slot ID that the RCS Feature is being created for.
* @return The newly created {@link RcsFeature} associated with the slot or null if the feature
* is not supported.
*/
+ @Deprecated
public RcsFeature createRcsFeature(int slotId) {
return null;
}
/**
+ * Return the {@link ImsConfigImplBase} implementation associated with the provided
+ * subscription. This will be used by the platform to get/set specific IMS related
+ * configurations.
+ *
+ * @param subscriptionId The subscription ID that the IMS configuration is associated with.
+ * @return ImsConfig implementation that is associated with the specified subscription.
+ */
+ public @NonNull ImsConfigImplBase getConfigForSubscription(int slotId, int subscriptionId) {
+ return getConfig(slotId);
+ }
+
+ /**
+ * Return the {@link ImsRegistrationImplBase} implementation associated with the provided
+ * subscription.
+ *
+ * @param subscriptionId The subscription ID that is associated with the IMS Registration.
+ * @return the ImsRegistration implementation associated with the subscription.
+ */
+ public @NonNull ImsRegistrationImplBase getRegistrationForSubscription(int slotId,
+ int subscriptionId) {
+ return getRegistration(slotId);
+ }
+
+ /**
* Return the {@link ImsConfigImplBase} implementation associated with the provided slot. This
* will be used by the platform to get/set specific IMS related configurations.
+ * @deprecated use {@link #getConfigForSubscription} instead.
*
* @param slotId The slot that the IMS configuration is associated with.
* @return ImsConfig implementation that is associated with the specified slot.
*/
+ @Deprecated
public ImsConfigImplBase getConfig(int slotId) {
return new ImsConfigImplBase();
}
/**
* Return the {@link ImsRegistrationImplBase} implementation associated with the provided slot.
+ * @deprecated use {@link #getRegistrationForSubscription} instead.
*
* @param slotId The slot that is associated with the IMS Registration.
* @return the ImsRegistration implementation associated with the slot.
*/
+ @Deprecated
public ImsRegistrationImplBase getRegistration(int slotId) {
return new ImsRegistrationImplBase();
}
diff --git a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
index c6966b3..ae6166f 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl
@@ -32,18 +32,19 @@
*/
interface IImsServiceController {
void setListener(IImsServiceControllerListener l);
- IImsMmTelFeature createMmTelFeature(int slotId);
- IImsRcsFeature createRcsFeature(int slotId);
+ IImsMmTelFeature createMmTelFeature(int slotId, int subId);
+ IImsMmTelFeature createEmergencyOnlyMmTelFeature(int slotId);
+ IImsRcsFeature createRcsFeature(int slotId, int subId);
ImsFeatureConfiguration querySupportedImsFeatures();
long getImsServiceCapabilities();
void addFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
void removeFeatureStatusCallback(int slotId, int featureType, in IImsFeatureStatusCallback c);
// Synchronous call to ensure the ImsService is ready before continuing with feature creation.
void notifyImsServiceReadyForFeatureCreation();
- void removeImsFeature(int slotId, int featureType);
- IImsConfig getConfig(int slotId);
- IImsRegistration getRegistration(int slotId);
+ void removeImsFeature(int slotId, int featureType, boolean changeSubId);
+ IImsConfig getConfig(int slotId, int subId);
+ IImsRegistration getRegistration(int slotId, int subId);
ISipTransport getSipTransport(int slotId);
- oneway void enableIms(int slotId);
- oneway void disableIms(int slotId);
+ oneway void enableIms(int slotId, int subId);
+ oneway void disableIms(int slotId, int subId);
}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
index f5f67bd..416096b 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureCallback.aidl
@@ -23,11 +23,11 @@
* {@hide}
*/
oneway interface IImsServiceFeatureCallback {
- void imsFeatureCreated(in ImsFeatureContainer feature);
+ void imsFeatureCreated(in ImsFeatureContainer feature, int subId);
// Reason defined in FeatureConnector.UnavailableReason
void imsFeatureRemoved(int reason);
// Status defined in ImsFeature.ImsState.
- void imsStatusChanged(int status);
+ void imsStatusChanged(int status, int subId);
//Capabilities defined in ImsService.ImsServiceCapability
void updateCapabilities(long capabilities);
}
\ No newline at end of file
diff --git a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
index 6985702..9a88abd 100644
--- a/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
+++ b/tests/DozeTest/src/com/android/dreams/dozetest/DozeTestDream.java
@@ -81,7 +81,8 @@
intent.setPackage(getPackageName());
IntentFilter filter = new IntentFilter();
filter.addAction(intent.getAction());
- registerReceiver(mAlarmReceiver, filter);
+ registerReceiver(mAlarmReceiver, filter,
+ Context.RECEIVER_EXPORTED_UNAUDITED);
mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);