Merge "Use the latest static shared lib version for signature checks."
diff --git a/Android.bp b/Android.bp
index 537f558..cc754f2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -62,12 +62,8 @@
"SPDX-license-identifier-Apache-2.0",
"SPDX-license-identifier-BSD",
"SPDX-license-identifier-CC-BY",
- "SPDX-license-identifier-CPL-1.0",
- "SPDX-license-identifier-GPL",
- "SPDX-license-identifier-GPL-2.0",
"SPDX-license-identifier-MIT",
"SPDX-license-identifier-Unicode-DFS",
- "SPDX-license-identifier-W3C",
"legacy_unencumbered",
],
license_text: [
@@ -81,6 +77,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",
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/METADATA b/METADATA
index 95577d8..5c3f89c 100644
--- a/METADATA
+++ b/METADATA
@@ -1,4 +1,3 @@
third_party {
- # would be NOTICE save for libs/usb/tests/accessorytest/f_accessory.h
- license_type: RESTRICTED
+ license_type: RECIPROCAL
}
diff --git a/apct-tests/perftests/packagemanager/Android.bp b/apct-tests/perftests/packagemanager/Android.bp
index fc70219..81cec91 100644
--- a/apct-tests/perftests/packagemanager/Android.bp
+++ b/apct-tests/perftests/packagemanager/Android.bp
@@ -10,7 +10,10 @@
android_test {
name: "PackageManagerPerfTests",
- srcs: ["src/**/*.java"],
+ srcs: [
+ "src/**/*.java",
+ "src/**/*.kt",
+ ],
static_libs: [
"platform-compat-test-rules",
@@ -21,6 +24,7 @@
"apct-perftests-utils",
"collector-device-lib-platform",
"cts-install-lib-java",
+ "services.core",
],
libs: ["android.test.base"],
diff --git a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
similarity index 92%
rename from apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
rename to apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
index f9ddf9a..e873514 100644
--- a/apct-tests/perftests/core/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -19,9 +19,6 @@
import android.content.pm.PackageParser
import android.content.pm.PackageParserCacheHelper.ReadHelper
import android.content.pm.PackageParserCacheHelper.WriteHelper
-import android.content.pm.parsing.ParsingPackageImpl
-import android.content.pm.parsing.ParsingPackageRead
-import android.content.pm.parsing.ParsingPackageUtils
import android.content.pm.parsing.result.ParseInput
import android.content.pm.parsing.result.ParseTypeImpl
import android.content.res.TypedArray
@@ -29,6 +26,8 @@
import android.perftests.utils.PerfStatusReporter
import androidx.test.filters.LargeTest
import com.android.internal.util.ConcurrentUtils
+import com.android.server.pm.pkg.parsing.ParsingPackageImpl
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import libcore.io.IoUtils
import org.junit.Rule
import org.junit.Test
@@ -42,7 +41,7 @@
@LargeTest
@RunWith(Parameterized::class)
-class PackageParsingPerfTest {
+public class PackageParsingPerfTest {
companion object {
private const val PARALLEL_QUEUE_CAPACITY = 10
@@ -196,8 +195,12 @@
// For testing, just disable enforcement to avoid hooking up to compat framework
ParseTypeImpl(ParseInput.Callback { _, _, _ -> false })
}
- val parser = ParsingPackageUtils(false, null, null, emptyList(),
- object : ParsingPackageUtils.Callback {
+ val parser = ParsingPackageUtils(false,
+ null,
+ null,
+ emptyList(),
+ object :
+ ParsingPackageUtils.Callback {
override fun hasFeature(feature: String) = true
override fun startParsingPackage(
@@ -206,7 +209,12 @@
path: String,
manifestArray: TypedArray,
isCoreApp: Boolean
- ) = ParsingPackageImpl(packageName, baseApkPath, path, manifestArray)
+ ) = ParsingPackageImpl(
+ packageName,
+ baseApkPath,
+ path,
+ manifestArray
+ )
})
override fun parseImpl(file: File) =
@@ -268,6 +276,7 @@
* Re-implementation of the server side PackageCacher, as it's inaccessible here.
*/
class PackageCacher2(cacheDir: File) : PackageCacher<ParsingPackageImpl>(cacheDir) {
- override fun fromParcel(parcel: Parcel) = ParsingPackageImpl(parcel)
+ override fun fromParcel(parcel: Parcel) =
+ ParsingPackageImpl(parcel)
}
}
diff --git a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
index 161a317..9fb1227 100644
--- a/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
+++ b/apex/jobscheduler/framework/java/android/os/PowerExemptionManager.java
@@ -258,6 +258,12 @@
* @hide
*/
public static final int REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED = 207;
+ /**
+ * Broadcast {@link android.content.Intent#ACTION_REFRESH_SAFETY_SOURCES}.
+ * @hide
+ */
+ public static final int REASON_ACTION_REFRESH_SAFETY_SOURCES = 208;
+
/* Reason code range 300-399 are reserved for other internal reasons */
/**
* Device idle system allow list, including EXCEPT-IDLE
@@ -398,6 +404,7 @@
REASON_TIME_CHANGED,
REASON_LOCALE_CHANGED,
REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED,
+ REASON_ACTION_REFRESH_SAFETY_SOURCES,
REASON_SYSTEM_ALLOW_LISTED,
REASON_ALARM_MANAGER_ALARM_CLOCK,
REASON_ALARM_MANAGER_WHILE_IDLE,
@@ -681,6 +688,8 @@
return "LOCALE_CHANGED";
case REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED:
return "REASON_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED";
+ case REASON_ACTION_REFRESH_SAFETY_SOURCES:
+ return "REASON_ACTION_REFRESH_SAFETY_SOURCES";
case REASON_SYSTEM_ALLOW_LISTED:
return "SYSTEM_ALLOW_LISTED";
case REASON_ALARM_MANAGER_ALARM_CLOCK:
diff --git a/core/api/current.txt b/core/api/current.txt
index 9e7bc691..688b66e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -949,6 +949,7 @@
field public static final int left = 16843181; // 0x10101ad
field public static final int letterSpacing = 16843958; // 0x10104b6
field public static final int level = 16844032; // 0x1010500
+ field public static final int lineBreakStyle = 16844365; // 0x101064d
field public static final int lineHeight = 16844159; // 0x101057f
field public static final int lineSpacingExtra = 16843287; // 0x1010217
field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
@@ -1314,6 +1315,7 @@
field public static final int shouldDisableView = 16843246; // 0x10101ee
field public static final int shouldUseDefaultUnfoldTransition = 16844364; // 0x101064c
field public static final int showAsAction = 16843481; // 0x10102d9
+ field public static final int showBackground;
field public static final int showClockAndComplications;
field public static final int showDefault = 16843258; // 0x10101fa
field public static final int showDividers = 16843561; // 0x1010329
@@ -5711,6 +5713,7 @@
public class LocaleManager {
method @NonNull public android.os.LocaleList getApplicationLocales();
+ method @NonNull @RequiresPermission(value="android.permission.READ_APP_SPECIFIC_LOCALES", conditional=true) public android.os.LocaleList getApplicationLocales(@NonNull String);
method public void setApplicationLocales(@NonNull android.os.LocaleList);
}
@@ -7286,6 +7289,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);
@@ -7509,6 +7516,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";
@@ -7584,6 +7592,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
@@ -7678,6 +7688,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();
@@ -10786,7 +10825,7 @@
method public boolean bindIsolatedService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
method public abstract boolean bindService(@RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int);
method public boolean bindService(@NonNull @RequiresPermission android.content.Intent, int, @NonNull java.util.concurrent.Executor, @NonNull android.content.ServiceConnection);
- method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.INTERACT_ACROSS_PROFILES}) public boolean bindServiceAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
+ method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.INTERACT_ACROSS_USERS_FULL", android.Manifest.permission.INTERACT_ACROSS_PROFILES}, conditional=true) public boolean bindServiceAsUser(@NonNull @RequiresPermission android.content.Intent, @NonNull android.content.ServiceConnection, int, @NonNull android.os.UserHandle);
method @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)") public abstract int checkCallingOrSelfPermission(@NonNull String);
method @CheckResult(suggest="#enforceCallingOrSelfUriPermission(Uri,int,String)") public abstract int checkCallingOrSelfUriPermission(android.net.Uri, int);
method @NonNull public int[] checkCallingOrSelfUriPermissions(@NonNull java.util.List<android.net.Uri>, int);
@@ -15242,6 +15281,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 {
@@ -16648,6 +16692,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);
@@ -17533,6 +17578,17 @@
package android.graphics.text {
+ public final class LineBreakConfig {
+ ctor public LineBreakConfig();
+ method public int getLineBreakStyle();
+ method public void set(@Nullable android.graphics.text.LineBreakConfig);
+ method public void setLineBreakStyle(int);
+ field public static final int LINE_BREAK_STYLE_LOOSE = 1; // 0x1
+ field public static final int LINE_BREAK_STYLE_NONE = 0; // 0x0
+ field public static final int LINE_BREAK_STYLE_NORMAL = 2; // 0x2
+ field public static final int LINE_BREAK_STYLE_STRICT = 3; // 0x3
+ }
+
public class LineBreaker {
method @NonNull public android.graphics.text.LineBreaker.Result computeLineBreaks(@NonNull android.graphics.text.MeasuredText, @NonNull android.graphics.text.LineBreaker.ParagraphConstraints, @IntRange(from=0) int);
field public static final int BREAK_STRATEGY_BALANCED = 2; // 0x2
@@ -17588,6 +17644,7 @@
ctor public MeasuredText.Builder(@NonNull android.graphics.text.MeasuredText);
method @NonNull public android.graphics.text.MeasuredText.Builder appendReplacementRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, @FloatRange(from=0) @Px float);
method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @IntRange(from=0) int, boolean);
+ method @NonNull public android.graphics.text.MeasuredText.Builder appendStyleRun(@NonNull android.graphics.Paint, @Nullable android.graphics.text.LineBreakConfig, @IntRange(from=0) int, boolean);
method @NonNull public android.graphics.text.MeasuredText build();
method @Deprecated @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(boolean);
method @NonNull public android.graphics.text.MeasuredText.Builder setComputeHyphenation(int);
@@ -18028,6 +18085,7 @@
field public static final String STRING_TYPE_GRAVITY = "android.sensor.gravity";
field public static final String STRING_TYPE_GYROSCOPE = "android.sensor.gyroscope";
field public static final String STRING_TYPE_GYROSCOPE_UNCALIBRATED = "android.sensor.gyroscope_uncalibrated";
+ field public static final String STRING_TYPE_HEAD_TRACKER = "android.sensor.head_tracker";
field public static final String STRING_TYPE_HEART_BEAT = "android.sensor.heart_beat";
field public static final String STRING_TYPE_HEART_RATE = "android.sensor.heart_rate";
field public static final String STRING_TYPE_HINGE_ANGLE = "android.sensor.hinge_angle";
@@ -18058,6 +18116,7 @@
field public static final int TYPE_GRAVITY = 9; // 0x9
field public static final int TYPE_GYROSCOPE = 4; // 0x4
field public static final int TYPE_GYROSCOPE_UNCALIBRATED = 16; // 0x10
+ field public static final int TYPE_HEAD_TRACKER = 37; // 0x25
field public static final int TYPE_HEART_BEAT = 31; // 0x1f
field public static final int TYPE_HEART_RATE = 21; // 0x15
field public static final int TYPE_HINGE_ANGLE = 36; // 0x24
@@ -18120,6 +18179,7 @@
method public void onFlushCompleted(android.hardware.Sensor);
method public void onSensorAdditionalInfo(android.hardware.SensorAdditionalInfo);
method public void onSensorChanged(android.hardware.SensorEvent);
+ method public void onSensorDiscontinuity(@NonNull android.hardware.Sensor);
}
public interface SensorEventListener {
@@ -43370,6 +43430,7 @@
field public static final int RESULT_RIL_BLOCKED_DUE_TO_CALL = 123; // 0x7b
field public static final int RESULT_RIL_CANCELLED = 119; // 0x77
field public static final int RESULT_RIL_ENCODING_ERR = 109; // 0x6d
+ field public static final int RESULT_RIL_GENERIC_ERROR = 124; // 0x7c
field public static final int RESULT_RIL_INTERNAL_ERR = 113; // 0x71
field public static final int RESULT_RIL_INVALID_ARGUMENTS = 104; // 0x68
field public static final int RESULT_RIL_INVALID_MODEM_STATE = 115; // 0x73
@@ -44178,6 +44239,7 @@
field public static final int TYPE_DEFAULT = 17; // 0x11
field public static final int TYPE_DUN = 8; // 0x8
field public static final int TYPE_EMERGENCY = 512; // 0x200
+ field public static final int TYPE_ENTERPRISE = 16384; // 0x4000
field public static final int TYPE_FOTA = 32; // 0x20
field public static final int TYPE_HIPRI = 16; // 0x10
field public static final int TYPE_IA = 256; // 0x100
@@ -44374,7 +44436,7 @@
method public boolean isEnabled();
method public boolean isSimPortAvailable(int);
method public void startResolutionActivity(android.app.Activity, int, android.content.Intent, android.app.PendingIntent) throws android.content.IntentSender.SendIntentException;
- method @Deprecated @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
+ method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, android.app.PendingIntent);
method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void switchToSubscription(int, int, @NonNull android.app.PendingIntent);
method @RequiresPermission("android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS") public void updateSubscriptionNickname(int, @Nullable String, @NonNull android.app.PendingIntent);
field public static final String ACTION_MANAGE_EMBEDDED_SUBSCRIPTIONS = "android.telephony.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS";
@@ -44394,6 +44456,7 @@
field public static final int ERROR_INSTALL_PROFILE = 10009; // 0x2719
field public static final int ERROR_INVALID_ACTIVATION_CODE = 10001; // 0x2711
field public static final int ERROR_INVALID_CONFIRMATION_CODE = 10002; // 0x2712
+ field public static final int ERROR_INVALID_PORT = 10017; // 0x2721
field public static final int ERROR_INVALID_RESPONSE = 10015; // 0x271f
field public static final int ERROR_NO_PROFILES_AVAILABLE = 10013; // 0x271d
field public static final int ERROR_OPERATION_BUSY = 10016; // 0x2720
@@ -45388,6 +45451,7 @@
public static final class PrecomputedText.Params {
method public int getBreakStrategy();
method public int getHyphenationFrequency();
+ method @Nullable public android.graphics.text.LineBreakConfig getLineBreakConfig();
method @NonNull public android.text.TextDirectionHeuristic getTextDirection();
method @NonNull public android.text.TextPaint getTextPaint();
}
@@ -45398,6 +45462,7 @@
method @NonNull public android.text.PrecomputedText.Params build();
method public android.text.PrecomputedText.Params.Builder setBreakStrategy(int);
method public android.text.PrecomputedText.Params.Builder setHyphenationFrequency(int);
+ method @NonNull public android.text.PrecomputedText.Params.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
method public android.text.PrecomputedText.Params.Builder setTextDirection(@NonNull android.text.TextDirectionHeuristic);
}
@@ -45558,6 +45623,7 @@
method @NonNull public android.text.StaticLayout.Builder setIncludePad(boolean);
method @NonNull public android.text.StaticLayout.Builder setIndents(@Nullable int[], @Nullable int[]);
method @NonNull public android.text.StaticLayout.Builder setJustificationMode(int);
+ method @NonNull public android.text.StaticLayout.Builder setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
method @NonNull public android.text.StaticLayout.Builder setLineSpacing(float, @FloatRange(from=0.0) float);
method @NonNull public android.text.StaticLayout.Builder setMaxLines(@IntRange(from=0) int);
method public android.text.StaticLayout.Builder setText(CharSequence);
@@ -48033,15 +48099,33 @@
public final class Choreographer {
method public static android.view.Choreographer getInstance();
+ method public void postExtendedFrameCallback(@NonNull android.view.Choreographer.ExtendedFrameCallback);
method public void postFrameCallback(android.view.Choreographer.FrameCallback);
method public void postFrameCallbackDelayed(android.view.Choreographer.FrameCallback, long);
+ method public void removeExtendedFrameCallback(@Nullable android.view.Choreographer.ExtendedFrameCallback);
method public void removeFrameCallback(android.view.Choreographer.FrameCallback);
}
+ public static interface Choreographer.ExtendedFrameCallback {
+ method public void onVsync(@NonNull android.view.Choreographer.FrameData);
+ }
+
public static interface Choreographer.FrameCallback {
method public void doFrame(long);
}
+ public static class Choreographer.FrameData {
+ method public long getFrameTimeNanos();
+ method @NonNull public android.view.Choreographer.FrameTimeline[] getFrameTimelines();
+ method @NonNull public android.view.Choreographer.FrameTimeline getPreferredFrameTimeline();
+ }
+
+ public static class Choreographer.FrameTimeline {
+ method public long getDeadlineNanos();
+ method public long getExpectedPresentTimeNanos();
+ method public long getVsyncId();
+ }
+
public interface CollapsibleActionView {
method public void onActionViewCollapsed();
method public void onActionViewExpanded();
@@ -48187,6 +48271,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();
@@ -52384,6 +52480,8 @@
method @NonNull public android.view.accessibility.CaptioningManager.CaptionStyle getUserStyle();
method public boolean isCallCaptioningEnabled();
method public final boolean isEnabled();
+ method public final boolean isSystemAudioCaptioningRequested();
+ method public final boolean isSystemAudioCaptioningUiRequested();
method public void removeCaptioningChangeListener(@NonNull android.view.accessibility.CaptioningManager.CaptioningChangeListener);
}
@@ -52412,6 +52510,8 @@
method public void onEnabledChanged(boolean);
method public void onFontScaleChanged(float);
method public void onLocaleChanged(@Nullable java.util.Locale);
+ method public void onSystemAudioCaptioningChanged(boolean);
+ method public void onSystemAudioCaptioningUiChanged(boolean);
method public void onUserStyleChanged(@NonNull android.view.accessibility.CaptioningManager.CaptionStyle);
}
@@ -52454,6 +52554,7 @@
method public int getRepeatCount();
method public int getRepeatMode();
method protected float getScaleFactor();
+ method public boolean getShowBackground();
method public long getStartOffset();
method public long getStartTime();
method public boolean getTransformation(long, android.view.animation.Transformation);
@@ -52479,6 +52580,7 @@
method public void setInterpolator(android.view.animation.Interpolator);
method public void setRepeatCount(int);
method public void setRepeatMode(int);
+ method public void setShowBackground(boolean);
method public void setStartOffset(long);
method public void setStartTime(long);
method public void setZAdjustment(int);
@@ -52984,6 +53086,7 @@
method public int getCharacterBoundsFlags(int);
method public CharSequence getComposingText();
method public int getComposingTextStart();
+ method @Nullable public android.view.inputmethod.EditorBoundsInfo getEditorBoundsInfo();
method public float getInsertionMarkerBaseline();
method public float getInsertionMarkerBottom();
method public int getInsertionMarkerFlags();
@@ -53005,11 +53108,27 @@
method public android.view.inputmethod.CursorAnchorInfo build();
method public void reset();
method public android.view.inputmethod.CursorAnchorInfo.Builder setComposingText(int, CharSequence);
+ method @NonNull public android.view.inputmethod.CursorAnchorInfo.Builder setEditorBoundsInfo(@Nullable android.view.inputmethod.EditorBoundsInfo);
method public android.view.inputmethod.CursorAnchorInfo.Builder setInsertionMarkerLocation(float, float, float, float, int);
method public android.view.inputmethod.CursorAnchorInfo.Builder setMatrix(android.graphics.Matrix);
method public android.view.inputmethod.CursorAnchorInfo.Builder setSelectionRange(int, int);
}
+ public final class EditorBoundsInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.graphics.RectF getEditorBounds();
+ method @Nullable public android.graphics.RectF getHandwritingBounds();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.view.inputmethod.EditorBoundsInfo> CREATOR;
+ }
+
+ public static final class EditorBoundsInfo.Builder {
+ ctor public EditorBoundsInfo.Builder();
+ method @NonNull public android.view.inputmethod.EditorBoundsInfo build();
+ method @NonNull public android.view.inputmethod.EditorBoundsInfo.Builder setEditorBounds(@Nullable android.graphics.RectF);
+ method @NonNull public android.view.inputmethod.EditorBoundsInfo.Builder setHandwritingBounds(@Nullable android.graphics.RectF);
+ }
+
public class EditorInfo implements android.text.InputType android.os.Parcelable {
ctor public EditorInfo();
method public int describeContents();
@@ -55136,6 +55255,7 @@
method protected boolean isInFilterMode();
method public boolean isItemChecked(int);
method public boolean isScrollingCacheEnabled();
+ method public boolean isSelectedChildViewEnabled();
method public boolean isSmoothScrollbarEnabled();
method public boolean isStackFromBottom();
method public boolean isTextFilterEnabled();
@@ -55171,6 +55291,7 @@
method public void setRemoteViewsAdapter(android.content.Intent);
method public void setScrollIndicators(android.view.View, android.view.View);
method public void setScrollingCacheEnabled(boolean);
+ method public void setSelectedChildViewEnabled(boolean);
method public void setSelectionFromTop(int, int);
method public void setSelector(@DrawableRes int);
method public void setSelector(android.graphics.drawable.Drawable);
@@ -57583,6 +57704,7 @@
method public final android.text.Layout getLayout();
method public float getLetterSpacing();
method public int getLineBounds(int, android.graphics.Rect);
+ method @NonNull public android.graphics.text.LineBreakConfig getLineBreakConfig();
method public int getLineCount();
method public int getLineHeight();
method public float getLineSpacingExtra();
@@ -57710,6 +57832,7 @@
method public void setKeyListener(android.text.method.KeyListener);
method public void setLastBaselineToBottomHeight(@IntRange(from=0) @Px int);
method public void setLetterSpacing(float);
+ method public void setLineBreakConfig(@NonNull android.graphics.text.LineBreakConfig);
method public void setLineHeight(@IntRange(from=0) @Px int);
method public void setLineSpacing(float, float);
method public void setLines(int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 23a0276..313fc75 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -293,6 +293,7 @@
field public static final String SET_ORIENTATION = "android.permission.SET_ORIENTATION";
field public static final String SET_POINTER_SPEED = "android.permission.SET_POINTER_SPEED";
field public static final String SET_SCREEN_COMPATIBILITY = "android.permission.SET_SCREEN_COMPATIBILITY";
+ field public static final String SET_SYSTEM_AUDIO_CAPTION = "android.permission.SET_SYSTEM_AUDIO_CAPTION";
field public static final String SET_VOLUME_KEY_LONG_PRESS_LISTENER = "android.permission.SET_VOLUME_KEY_LONG_PRESS_LISTENER";
field public static final String SET_WALLPAPER_COMPONENT = "android.permission.SET_WALLPAPER_COMPONENT";
field public static final String SHOW_KEYGUARD_MESSAGE = "android.permission.SHOW_KEYGUARD_MESSAGE";
@@ -798,7 +799,6 @@
}
public class LocaleManager {
- method @NonNull @RequiresPermission(android.Manifest.permission.READ_APP_SPECIFIC_LOCALES) public android.os.LocaleList getApplicationLocales(@NonNull String);
method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void setApplicationLocales(@NonNull String, @NonNull android.os.LocaleList);
}
@@ -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);
@@ -1409,13 +1423,6 @@
}
-package android.app.communal {
-
- public final class CommunalManager {
- }
-
-}
-
package android.app.compat {
public final class CompatChanges {
@@ -2632,7 +2639,6 @@
field public static final String BATTERY_STATS_SERVICE = "batterystats";
field @Deprecated public static final int BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS = 1048576; // 0x100000
field public static final int BIND_ALLOW_FOREGROUND_SERVICE_STARTS_FROM_BACKGROUND = 262144; // 0x40000
- field public static final String COMMUNAL_SERVICE = "communal";
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
field public static final String CONTEXTHUB_SERVICE = "contexthub";
field public static final String ETHERNET_SERVICE = "ethernet";
@@ -8218,6 +8224,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
@@ -13137,6 +13144,7 @@
}
public final class UiccSlotMapping implements android.os.Parcelable {
+ ctor public UiccSlotMapping(int, int, int);
method public int describeContents();
method @IntRange(from=0) public int getLogicalSlotIndex();
method @IntRange(from=0) public int getPhysicalSlotIndex();
@@ -13194,6 +13202,7 @@
field public static final String TYPE_DEFAULT_STRING = "default";
field public static final String TYPE_DUN_STRING = "dun";
field public static final String TYPE_EMERGENCY_STRING = "emergency";
+ field public static final String TYPE_ENTERPRISE_STRING = "enterprise";
field public static final String TYPE_FOTA_STRING = "fota";
field public static final String TYPE_HIPRI_STRING = "hipri";
field public static final String TYPE_IA_STRING = "ia";
@@ -14054,14 +14063,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();
@@ -15188,6 +15204,11 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY) public void unregisterSystemAction(int);
}
+ public class CaptioningManager {
+ method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningRequested(boolean);
+ method @RequiresPermission(android.Manifest.permission.SET_SYSTEM_AUDIO_CAPTION) public final void setSystemAudioCaptioningUiRequested(boolean);
+ }
+
}
package android.view.autofill {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index f1b4624..d6a9f7f 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -43,7 +43,6 @@
field public static final String TEST_BIOMETRIC = "android.permission.TEST_BIOMETRIC";
field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
- field public static final String WRITE_COMMUNAL_STATE = "android.permission.WRITE_COMMUNAL_STATE";
field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
field @Deprecated public static final String WRITE_MEDIA_STORAGE = "android.permission.WRITE_MEDIA_STORAGE";
field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
@@ -557,14 +556,6 @@
}
-package android.app.communal {
-
- public final class CommunalManager {
- method @RequiresPermission(android.Manifest.permission.WRITE_COMMUNAL_STATE) public void setCommunalViewShowing(boolean);
- }
-
-}
-
package android.app.contentsuggestions {
public final class ContentSuggestionsManager {
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 324e1ae..96487de 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -71,6 +71,9 @@
}
// Access modes for handleIncomingUser.
+ /**
+ * Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_USERS}.
+ */
public static final int ALLOW_NON_FULL = 0;
/**
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
@@ -78,13 +81,18 @@
* Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
*/
public static final int ALLOW_NON_FULL_IN_PROFILE = 1;
+ /**
+ * Allows access to a caller only if it has the full
+ * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}.
+ */
public static final int ALLOW_FULL_ONLY = 2;
/**
* Allows access to a caller with {@link android.Manifest.permission#INTERACT_ACROSS_PROFILES}
- * or {@link android.Manifest.permission#INTERACT_ACROSS_USERS} if in the same profile group.
- * Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} is required.
+ * if in the same profile group.
+ * Otherwise, {@link android.Manifest.permission#INTERACT_ACROSS_USERS} is required and suffices
+ * as in {@link #ALLOW_NON_FULL}.
*/
- public static final int ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE = 3;
+ public static final int ALLOW_PROFILES_OR_NON_FULL = 3;
/**
* Returns profile information in free form string in two separate strings.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7ac4bdd..686ca3b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1646,7 +1646,7 @@
@Override
public void dumpCacheInfo(ParcelFileDescriptor pfd, String[] args) {
- PropertyInvalidatedCache.dumpCacheInfo(pfd.getFileDescriptor(), args);
+ PropertyInvalidatedCache.dumpCacheInfo(pfd, args);
IoUtils.closeQuietly(pfd);
}
@@ -6391,9 +6391,7 @@
if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);
if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
- for (PropertyInvalidatedCache pic : PropertyInvalidatedCache.getActiveCaches()) {
- pic.clear();
- }
+ PropertyInvalidatedCache.onTrimMemory();
}
final ArrayList<ComponentCallbacks2> callbacks =
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 49c75c4..7b55b6c 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -62,6 +62,7 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
@@ -73,12 +74,6 @@
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.ArtManager;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.result.ParseInput;
-import android.content.pm.parsing.result.ParseResult;
-import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -2335,37 +2330,6 @@
return info.loadLabel(this);
}
- @Nullable
- public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath, int flags) {
- return getPackageArchiveInfo(archiveFilePath, PackageInfoFlags.of(flags));
- }
-
- @Nullable
- public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
- PackageInfoFlags flags) {
- long flagsBits = flags.getValue();
- if ((flagsBits & (PackageManager.MATCH_DIRECT_BOOT_UNAWARE
- | PackageManager.MATCH_DIRECT_BOOT_AWARE)) == 0) {
- // Caller expressed no opinion about what encryption
- // aware/unaware components they want to see, so match both
- flagsBits |= PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
- }
-
- boolean collectCertificates = (flagsBits & PackageManager.GET_SIGNATURES) != 0
- || (flagsBits & PackageManager.GET_SIGNING_CERTIFICATES) != 0;
-
- ParseInput input = ParseTypeImpl.forParsingWithoutPlatformCompat().reset();
- ParseResult<ParsingPackage> result = ParsingPackageUtils.parseDefault(input,
- new File(archiveFilePath), 0, getPermissionManager().getSplitPermissions(),
- collectCertificates);
- if (result.isError()) {
- return null;
- }
- return PackageInfoWithoutStateUtils.generate(result.getResult(), null, flagsBits, 0, 0,
- null, FrameworkPackageUserState.DEFAULT, UserHandle.getCallingUserId());
- }
-
@Override
public int installExistingPackage(String packageName) throws NameNotFoundException {
return installExistingPackage(packageName, INSTALL_REASON_UNKNOWN);
diff --git a/core/java/android/app/LocaleManager.java b/core/java/android/app/LocaleManager.java
index 2aa7c8e..332a621 100644
--- a/core/java/android/app/LocaleManager.java
+++ b/core/java/android/app/LocaleManager.java
@@ -95,18 +95,20 @@
}
/**
- * Returns the current UI locales for a specific app (described by package name).
+ * Returns the current UI locales for a specified app (described by package name).
*
* <p>Returns a {@link LocaleList#getEmptyLocaleList()} if no app-specific locales are set.
*
- * <b>Note:</b> Non-system apps should read Locale information via their in-process
- * LocaleLists.
+ * <p>This API can be used by an app's installer
+ * (per {@link android.content.pm.InstallSourceInfo#getInstallingPackageName}) to retrieve
+ * the app's locales.
+ * All other cases require {@code android.Manifest.permission#READ_APP_SPECIFIC_LOCALES}.
+ * Apps should generally retrieve their own locales via their in-process LocaleLists,
+ * or by calling {@link #getApplicationLocales()}.
*
* @param appPackageName the package name of the app for which to retrieve the locales.
- * @hide
*/
- @SystemApi
- @RequiresPermission(Manifest.permission.READ_APP_SPECIFIC_LOCALES)
+ @RequiresPermission(value = Manifest.permission.READ_APP_SPECIFIC_LOCALES, conditional = true)
@UserHandleAware
@NonNull
public LocaleList getApplicationLocales(@NonNull String appPackageName) {
diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java
index 978160c..ec8d989 100644
--- a/core/java/android/app/PropertyInvalidatedCache.java
+++ b/core/java/android/app/PropertyInvalidatedCache.java
@@ -20,6 +20,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
@@ -29,7 +30,6 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastPrintWriter;
-import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -355,11 +355,12 @@
private final int mMaxEntries;
/**
- * Make a new property invalidated cache.
+ * Make a new property invalidated cache. This constructor names the cache after the
+ * property name. New clients should prefer the constructor that takes an explicit
+ * cache name.
*
* @param maxEntries Maximum number of entries to cache; LRU discard
- * @param propertyName Name of the system property holding the cache invalidation nonce
- * Defaults the cache name to the property name.
+ * @param propertyName Name of the system property holding the cache invalidation nonce.
*/
public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) {
this(maxEntries, propertyName, propertyName);
@@ -418,7 +419,7 @@
* Enable or disable testing. The testing property map is cleared every time this
* method is called.
*/
- @VisibleForTesting
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static void setTestMode(boolean mode) {
sTesting = mode;
synchronized (sTestingPropertyMap) {
@@ -426,12 +427,12 @@
}
}
- /**
- * Enable testing the specific cache key. Only keys in the map are subject to testing.
- * There is no method to stop testing a property name. Just disable the test mode.
- */
- @VisibleForTesting
- public static void testPropertyName(String name) {
+ /**
+ * Enable testing the specific cache key. Only keys in the map are subject to testing.
+ * There is no method to stop testing a property name. Just disable the test mode.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public static void testPropertyName(@NonNull String name) {
synchronized (sTestingPropertyMap) {
sTestingPropertyMap.put(name, (long) NONCE_UNSET);
}
@@ -505,21 +506,23 @@
* block. If this function returns null, the result of the cache query is null. There is no
* "negative cache" in the query: we don't cache null results at all.
*/
- public abstract Result recompute(Query query);
+ public abstract @NonNull Result recompute(@NonNull Query query);
/**
* Return true if the query should bypass the cache. The default behavior is to
* always use the cache but the method can be overridden for a specific class.
*/
- public boolean bypass(Query query) {
+ public boolean bypass(@NonNull Query query) {
return false;
}
/**
- * Determines if a pair of responses are considered equal. Used to determine whether
- * a cache is inadvertently returning stale results when VERIFY is set to true.
+ * Determines if a pair of responses are considered equal. Used to determine whether a
+ * cache is inadvertently returning stale results when VERIFY is set to true. Some
+ * existing clients override this method, but it is now deprecated in favor of a valid
+ * equals() method on the Result class.
*/
- protected boolean resultEquals(Result cachedResult, Result fetchedResult) {
+ public boolean resultEquals(Result cachedResult, Result fetchedResult) {
// If a service crashes and returns a null result, the cached value remains valid.
if (fetchedResult != null) {
return Objects.equals(cachedResult, fetchedResult);
@@ -544,8 +547,11 @@
}
/**
- * Disable the use of this cache in this process.
+ * Disable the use of this cache in this process. This method is using during
+ * testing. To disable a cache in normal code, use disableLocal().
+ * @hide
*/
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public final void disableInstance() {
synchronized (mLock) {
mDisabled = true;
@@ -558,7 +564,7 @@
* using the key will be disabled now, and all future cache instances that use the key will be
* disabled in their constructor.
*/
- public static final void disableLocal(@NonNull String name) {
+ private static final void disableLocal(@NonNull String name) {
synchronized (sCorkLock) {
sDisabledKeys.add(name);
for (PropertyInvalidatedCache cache : sCaches.keySet()) {
@@ -570,7 +576,21 @@
}
/**
+ * Stop disabling local caches with a particular name. Any caches that are currently
+ * disabled remain disabled (the "disabled" setting is sticky). However, new caches
+ * with this name will not be disabled. It is not an error if the cache name is not
+ * found in the list of disabled caches.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ public final void clearDisableLocal() {
+ synchronized (sCorkLock) {
+ sDisabledKeys.remove(mCacheName);
+ }
+ }
+
+ /**
* Disable this cache in the current process, and all other caches that use the same
+ * name. This does not affect caches that have a different name but use the same
* property.
*/
public final void disableLocal() {
@@ -580,6 +600,7 @@
/**
* Return whether the cache is disabled in this process.
*/
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public final boolean isDisabledLocal() {
return mDisabled || !sEnabled;
}
@@ -587,7 +608,7 @@
/**
* Get a value from the cache or recompute it.
*/
- public Result query(Query query) {
+ public @NonNull Result query(@NonNull Query query) {
// Let access to mDisabled race: it's atomic anyway.
long currentNonce = (!isDisabledLocal()) ? getCurrentNonce() : NONCE_DISABLED;
if (bypass(query)) {
@@ -704,6 +725,7 @@
* the cache objects to invalidate all of the cache objects becomes confusing and you should
* just use the static version of this function.
*/
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public final void disableSystemWide() {
disableSystemWide(mPropertyName);
}
@@ -714,7 +736,7 @@
*
* @param name Name of the cache-key property to invalidate
*/
- public static void disableSystemWide(@NonNull String name) {
+ private static void disableSystemWide(@NonNull String name) {
if (!sEnabled) {
return;
}
@@ -784,8 +806,8 @@
"invalidating cache [%s]: [%s] -> [%s]",
name, nonce, Long.toString(newValue)));
}
- // TODO(dancol): add an atomic compare and exchange property set operation to avoid a
- // small race with concurrent disable here.
+ // There is a small race with concurrent disables here. A compare-and-exchange
+ // property operation would be required to eliminate the race condition.
setNonce(name, newValue);
long invalidateCount = sInvalidates.getOrDefault(name, (long) 0);
sInvalidates.put(name, ++invalidateCount);
@@ -990,6 +1012,10 @@
}
}
+ /**
+ * Return the result generated by a given query to the cache, performing debugging checks when
+ * enabled.
+ */
private Result maybeCheckConsistency(Query query, Result proposedResult) {
if (VERIFY) {
Result resultToCompare = recompute(query);
@@ -1007,24 +1033,27 @@
}
/**
- * Return the name of the cache, to be used in debug messages. The
- * method is public so clients can use it.
+ * Return the name of the cache, to be used in debug messages.
*/
- public String cacheName() {
+ private final @NonNull String cacheName() {
return mCacheName;
}
/**
- * Return the query as a string, to be used in debug messages. The
- * method is public so clients can use it in external debug messages.
+ * Return the query as a string, to be used in debug messages. New clients should not
+ * override this, but should instead add the necessary toString() method to the Query
+ * class.
*/
- public String queryToString(Query query) {
+ protected @NonNull String queryToString(@NonNull Query query) {
return Objects.toString(query);
}
/**
- * Disable all caches in the local process. Once disabled it is not
- * possible to re-enable caching in the current process.
+ * Disable all caches in the local process. This is primarily useful for testing when
+ * the test needs to bypass the cache or when the test is for a server, and the test
+ * process does not have privileges to write SystemProperties. Once disabled it is not
+ * possible to re-enable caching in the current process. If a client wants to
+ * temporarily disable caching, use the corking mechanism.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
public static void disableForTestMode() {
@@ -1044,7 +1073,7 @@
/**
* Returns a list of caches alive at the current time.
*/
- public static ArrayList<PropertyInvalidatedCache> getActiveCaches() {
+ private static @NonNull ArrayList<PropertyInvalidatedCache> getActiveCaches() {
synchronized (sCorkLock) {
return new ArrayList<PropertyInvalidatedCache>(sCaches.keySet());
}
@@ -1053,7 +1082,7 @@
/**
* Returns a list of the active corks in a process.
*/
- public static ArrayList<Map.Entry<String, Integer>> getActiveCorks() {
+ private static @NonNull ArrayList<Map.Entry<String, Integer>> getActiveCorks() {
synchronized (sCorkLock) {
return new ArrayList<Map.Entry<String, Integer>>(sCorks.entrySet());
}
@@ -1104,14 +1133,14 @@
}
/**
- * Dumps contents of every cache in the process to the provided FileDescriptor.
+ * Dumps the contents of every cache in the process to the provided ParcelFileDescriptor.
*/
- public static void dumpCacheInfo(FileDescriptor fd, String[] args) {
+ public static void dumpCacheInfo(@NonNull ParcelFileDescriptor pfd, @NonNull String[] args) {
ArrayList<PropertyInvalidatedCache> activeCaches;
ArrayList<Map.Entry<String, Integer>> activeCorks;
try (
- FileOutputStream fout = new FileOutputStream(fd);
+ FileOutputStream fout = new FileOutputStream(pfd.getFileDescriptor());
PrintWriter pw = new FastPrintWriter(fout);
) {
if (!sEnabled) {
@@ -1142,4 +1171,13 @@
Log.e(TAG, "Failed to dump PropertyInvalidatedCache instances");
}
}
+
+ /**
+ * Trim memory by clearing all the caches.
+ */
+ public static void onTrimMemory() {
+ for (PropertyInvalidatedCache pic : getActiveCaches()) {
+ pic.clear();
+ }
+ }
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 85ddff9..67c42f6 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -26,8 +26,6 @@
import android.app.admin.IDevicePolicyManager;
import android.app.appsearch.AppSearchManagerFrameworkInitializer;
import android.app.blob.BlobStoreManagerFrameworkInitializer;
-import android.app.communal.CommunalManager;
-import android.app.communal.ICommunalManager;
import android.app.contentsuggestions.ContentSuggestionsManager;
import android.app.contentsuggestions.IContentSuggestionsManager;
import android.app.job.JobSchedulerFrameworkInitializer;
@@ -130,6 +128,7 @@
import android.media.tv.interactive.TvIAppManager;
import android.media.tv.tunerresourcemanager.ITunerResourceManager;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
+import android.nearby.NearbyFrameworkInitializer;
import android.net.ConnectivityFrameworkInitializer;
import android.net.ConnectivityFrameworkInitializerTiramisu;
import android.net.EthernetManager;
@@ -1519,21 +1518,6 @@
}
});
- registerService(Context.COMMUNAL_SERVICE, CommunalManager.class,
- new CachedServiceFetcher<CommunalManager>() {
- @Override
- public CommunalManager createService(ContextImpl ctx) {
- if (!ctx.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_COMMUNAL_MODE)) {
- return null;
- }
- IBinder iBinder =
- ServiceManager.getService(Context.COMMUNAL_SERVICE);
- return iBinder != null ? new CommunalManager(
- ICommunalManager.Stub.asInterface(iBinder)) : null;
- }
- });
-
sInitializing = true;
try {
// Note: the following functions need to be @SystemApis, once they become mainline
@@ -1554,6 +1538,7 @@
UwbFrameworkInitializer.registerServiceWrappers();
SafetyCenterFrameworkInitializer.registerServiceWrappers();
ConnectivityFrameworkInitializerTiramisu.registerServiceWrappers();
+ NearbyFrameworkInitializer.registerServiceWrappers();
} finally {
// If any of the above code throws, we're in a pretty bad shape and the process
// will likely crash, but we'll reset it just in case there's an exception handler...
diff --git a/core/java/android/content/pm/parsing/component/ParsedService.java b/core/java/android/app/admin/DevicePolicyDrawableResource.aidl
similarity index 65%
copy from core/java/android/content/pm/parsing/component/ParsedService.java
copy to core/java/android/app/admin/DevicePolicyDrawableResource.aidl
index 6736afa..6b73d981 100644
--- a/core/java/android/content/pm/parsing/component/ParsedService.java
+++ b/core/java/android/app/admin/DevicePolicyDrawableResource.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,6 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package android.app.admin;
-import android.annotation.Nullable;
-
-/** @hide **/
-public interface ParsedService extends ParsedMainComponent {
-
- int getForegroundServiceType();
-
- @Nullable
- String getPermission();
-}
+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 070fab3..2bfb938 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;
@@ -3233,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
@@ -14424,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/content/pm/parsing/component/ParsedService.java b/core/java/android/app/admin/ParcelableResource.aidl
similarity index 65%
copy from core/java/android/content/pm/parsing/component/ParsedService.java
copy to core/java/android/app/admin/ParcelableResource.aidl
index 6736afa..dd2b975 100644
--- a/core/java/android/content/pm/parsing/component/ParsedService.java
+++ b/core/java/android/app/admin/ParcelableResource.aidl
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +15,6 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package android.app.admin;
-import android.annotation.Nullable;
-
-/** @hide **/
-public interface ParsedService extends ParsedMainComponent {
-
- int getForegroundServiceType();
-
- @Nullable
- String getPermission();
-}
+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/app/communal/CommunalManager.java b/core/java/android/app/communal/CommunalManager.java
deleted file mode 100644
index c7368ad..0000000
--- a/core/java/android/app/communal/CommunalManager.java
+++ /dev/null
@@ -1,62 +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.app.communal;
-
-import android.Manifest;
-import android.annotation.RequiresFeature;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.annotation.TestApi;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-
-/**
- * System private class for talking with the
- * {@link com.android.server.communal.CommunalManagerService} that handles communal mode state.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
-@SystemService(Context.COMMUNAL_SERVICE)
-@RequiresFeature(PackageManager.FEATURE_COMMUNAL_MODE)
-public final class CommunalManager {
- private final ICommunalManager mService;
-
- /** @hide */
- public CommunalManager(ICommunalManager service) {
- mService = service;
- }
-
- /**
- * Updates whether or not the communal view is currently showing over the lockscreen.
- *
- * @param isShowing Whether communal view is showing.
- *
- * @hide
- */
- @TestApi
- @RequiresPermission(Manifest.permission.WRITE_COMMUNAL_STATE)
- public void setCommunalViewShowing(boolean isShowing) {
- try {
- mService.setCommunalViewShowing(isShowing);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-}
diff --git a/core/java/android/app/communal/ICommunalManager.aidl b/core/java/android/app/communal/ICommunalManager.aidl
deleted file mode 100644
index df9d7ce..0000000
--- a/core/java/android/app/communal/ICommunalManager.aidl
+++ /dev/null
@@ -1,27 +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.app.communal;
-
-/**
- * System private API for talking with the communal manager service that handles communal mode
- * state.
- *
- * @hide
- */
-interface ICommunalManager {
- oneway void setCommunalViewShowing(boolean isShowing);
-}
\ No newline at end of file
diff --git a/core/java/android/app/communal/OWNERS b/core/java/android/app/communal/OWNERS
deleted file mode 100644
index b02883d..0000000
--- a/core/java/android/app/communal/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-brycelee@google.com
-justinkoh@google.com
-lusilva@google.com
-xilei@google.com
\ No newline at end of file
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 9985cc0..1291766c 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -36,5 +36,5 @@
boolean isDeviceSecure(int userId);
boolean isTrustUsuallyManaged(int userId);
void unlockedByBiometricForUser(int userId, in BiometricSourceType source);
- void clearAllBiometricRecognized(in BiometricSourceType target);
+ void clearAllBiometricRecognized(in BiometricSourceType target, int unlockedUser);
}
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 177de83..e214007 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -217,9 +217,9 @@
* Clears authentication by the specified biometric type for all users.
*/
@RequiresPermission(Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE)
- public void clearAllBiometricRecognized(BiometricSourceType source) {
+ public void clearAllBiometricRecognized(BiometricSourceType source, int unlockedUser) {
try {
- mService.clearAllBiometricRecognized(source);
+ mService.clearAllBiometricRecognized(source, unlockedUser);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
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 9982fa6..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/companion/CompanionDeviceService.java b/core/java/android/companion/CompanionDeviceService.java
index 12ced96..610b7ee 100644
--- a/core/java/android/companion/CompanionDeviceService.java
+++ b/core/java/android/companion/CompanionDeviceService.java
@@ -31,29 +31,71 @@
import java.util.Objects;
/**
- * Service to be implemented by apps that manage a companion device.
+ * A service that receives calls from the system when the associated companion device appears
+ * nearby or is connected, as well as when the device is no longer "present" or connected.
+ * See {@link #onDeviceAppeared(AssociationInfo)}/{@link #onDeviceDisappeared(AssociationInfo)}.
*
- * System will keep this service bound whenever an associated device is nearby for Bluetooth
- * devices or companion app manages the connectivity and reports disappeared, ensuring app stays
- * alive
+ * <p>
+ * Additionally, the service will receive a call from the system, if and when the system needs to
+ * transfer data to the companion device.
+ * See {@link #dispatchMessage(int, int, byte[])}).
*
- * An app must be {@link CompanionDeviceManager#associate associated} with at leas one device,
- * before it can take advantage of this service.
+ * <p>
+ * Companion applications must create a service that {@code extends}
+ * {@link CompanionDeviceService}, and declare it in their AndroidManifest.xml with the
+ * "android.permission.BIND_COMPANION_DEVICE_SERVICE" permission
+ * (see {@link android.Manifest.permission#BIND_COMPANION_DEVICE_SERVICE}),
+ * as well as add an intent filter for the "android.companion.CompanionDeviceService" action
+ * (see {@link #SERVICE_INTERFACE}).
*
- * You must declare this service in your manifest with an
- * intent-filter action of {@link #SERVICE_INTERFACE} and
- * permission of {@link android.Manifest.permission#BIND_COMPANION_DEVICE_SERVICE}
+ * <p>
+ * Following is an example of such declaration:
+ * <pre>{@code
+ * <service
+ * android:name=".CompanionService"
+ * android:label="@string/service_name"
+ * android:exported="true"
+ * android:permission="android.permission.BIND_COMPANION_DEVICE_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.companion.CompanionDeviceService" />
+ * </intent-filter>
+ * </service>
+ * }</pre>
*
- * <p>If you want to declare more than one of these services, you must declare the meta-data in the
- * service of your manifest with the corresponding name and value to true to indicate the
- * primary service.
- * Only the primary one will get the callback from
- * {@link #onDeviceAppeared(AssociationInfo associationInfo)}.</p>
+ * <p>
+ * If the companion application has requested observing device presence (see
+ * {@link CompanionDeviceManager#startObservingDevicePresence(String)}) the system will
+ * <a href="https://developer.android.com/guide/components/bound-services"> bind the service</a>
+ * when it detects the device nearby (for BLE devices) or when the device is connected
+ * (for Bluetooth devices).
*
- * Example:
+ * <p>
+ * The system binding {@link CompanionDeviceService} elevates the priority of the process that
+ * the service is running in, and thus may prevent
+ * <a href="https://developer.android.com/topic/performance/memory-management#low-memory_killer">
+ * the Low-memory killer</a> from killing the process at expense of other processes with lower
+ * priority.
+ *
+ * <p>
+ * It is possible for an application to declare multiple {@link CompanionDeviceService}-s.
+ * In such case, the system will bind all declared services, but will deliver
+ * {@link #onDeviceAppeared(AssociationInfo)}, {@link #onDeviceDisappeared(AssociationInfo)} and
+ * {@link #dispatchMessage(int, int, byte[])} only to one "primary" services.
+ * Applications that declare multiple {@link CompanionDeviceService}-s should indicate the "primary"
+ * service using "android.companion.primary" tag.
+ * <pre>{@code
* <meta-data
- * android:name="primary"
- * android:value="true" />
+ * android:name="android.companion.primary"
+ * android:value="true" />
+ * }</pre>
+ *
+ * <p>
+ * If the application declares multiple {@link CompanionDeviceService}-s, but does not indicate
+ * the "primary" one, the system will pick one of the declared services to use as "primary".
+ *
+ * <p>
+ * If the application declares multiple "primary" {@link CompanionDeviceService}-s, the system
+ * will pick single one of them to use as "primary".
*/
public abstract class CompanionDeviceService extends Service {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2df6f9a..2309fb6 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3601,10 +3601,18 @@
* Binds to a service in the given {@code user} in the same manner as
* {@link #bindService(Intent, ServiceConnection, int)}.
*
- * <p>If the given {@code user} is in the same profile group and the target package is the
- * same as the caller, {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} is
- * sufficient. Otherwise, requires {@code android.Manifest.permission.INTERACT_ACROSS_USERS}
- * for interacting with other users.
+ * <p>Requires that one of the following conditions are met:
+ * <ul>
+ * <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}</li>
+ * <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS} and is the same
+ * package as the {@code service} (determined by its component's package) and the Android
+ * version is at least {@link android.os.Build.VERSION_CODES#S}</li>
+ * <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_USERS} and is in same
+ * profile group as the given {@code user}</li>
+ * <li>caller has {@code android.Manifest.permission.INTERACT_ACROSS_PROFILES} and is in same
+ * profile group as the given {@code user} and is the same package as the {@code service}
+ * </li>
+ * </ul>
*
* @param service Identifies the service to connect to. The Intent must
* specify an explicit component name.
@@ -3626,8 +3634,9 @@
@SuppressWarnings("unused")
@RequiresPermission(anyOf = {
android.Manifest.permission.INTERACT_ACROSS_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
android.Manifest.permission.INTERACT_ACROSS_PROFILES
- })
+ }, conditional = true)
public boolean bindServiceAsUser(
@NonNull @RequiresPermission Intent service, @NonNull ServiceConnection conn, int flags,
@NonNull UserHandle user) {
@@ -3640,7 +3649,11 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.INTERACT_ACROSS_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ android.Manifest.permission.INTERACT_ACROSS_PROFILES
+ }, conditional = true)
@UnsupportedAppUsage(trackingBug = 136728678)
public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
Handler handler, UserHandle user) {
@@ -5882,17 +5895,6 @@
/**
* Use with {@link #getSystemService(String)} to retrieve a
- * {@link android.app.communal.CommunalManager} for interacting with the global system state.
- *
- * @see #getSystemService(String)
- * @see android.app.communal.CommunalManager
- * @hide
- */
- @SystemApi
- public static final String COMMUNAL_SERVICE = "communal";
-
- /**
- * Use with {@link #getSystemService(String)} to retrieve a
* {@link android.app.LocaleManager}.
*
* @see #getSystemService(String)
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d817f1e..c8f88f2 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -50,6 +50,7 @@
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.dex.ArtManager;
+import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.pm.verify.domain.DomainVerificationManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -88,6 +89,7 @@
import dalvik.system.VMRuntime;
+import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.cert.Certificate;
@@ -7891,8 +7893,7 @@
@Deprecated
@Nullable
public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath, int flags) {
- throw new UnsupportedOperationException(
- "getPackageArchiveInfo() not implemented in subclass");
+ return getPackageArchiveInfo(archiveFilePath, PackageInfoFlags.of(flags));
}
/**
@@ -7901,8 +7902,29 @@
@Nullable
public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
@NonNull PackageInfoFlags flags) {
- throw new UnsupportedOperationException(
- "getPackageArchiveInfo() not implemented in subclass");
+ long flagsBits = flags.getValue();
+ final PackageParser parser = new PackageParser();
+ parser.setCallback(new PackageParser.CallbackImpl(this));
+ final File apkFile = new File(archiveFilePath);
+ try {
+ if ((flagsBits & (MATCH_DIRECT_BOOT_UNAWARE | MATCH_DIRECT_BOOT_AWARE)) != 0) {
+ // Caller expressed an explicit opinion about what encryption
+ // aware/unaware components they want to see, so fall through and
+ // give them what they want
+ } else {
+ // Caller expressed no opinion, so match everything
+ flagsBits |= MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE;
+ }
+
+ PackageParser.Package pkg = parser.parsePackage(apkFile, 0, false);
+ if ((flagsBits & GET_SIGNATURES) != 0) {
+ PackageParser.collectCertificates(pkg, false /* skipVerify */);
+ }
+ return PackageParser.generatePackageInfo(pkg, null, (int) flagsBits, 0, 0, null,
+ FrameworkPackageUserState.DEFAULT);
+ } catch (PackageParser.PackageParserException e) {
+ return null;
+ }
}
/**
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index e2c91a4b..701c546 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 The Android Open Source Project
+ * 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.
@@ -37,6 +37,8 @@
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
+import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
@@ -55,11 +57,9 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.pkg.FrameworkPackageUserState;
-import android.content.pm.pkg.PackageUserStateUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
+import android.content.pm.pkg.FrameworkPackageUserState;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -68,6 +68,7 @@
import android.content.res.XmlResourceParser;
import android.os.Build;
import android.os.Bundle;
+import android.os.Debug;
import android.os.FileUtils;
import android.os.Parcel;
import android.os.Parcelable;
@@ -83,6 +84,7 @@
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Base64;
+import android.util.DebugUtils;
import android.util.DisplayMetrics;
import android.util.IntArray;
import android.util.Log;
@@ -128,6 +130,7 @@
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -148,7 +151,7 @@
* </ul>
*
* @deprecated This class is mostly unused and no new changes should be added to it. Use
- * {@link android.content.pm.parsing.ParsingPackageUtils} and related parsing v2 infrastructure in
+ * ParsingPackageUtils and related parsing v2 infrastructure in
* the core/services parsing subpackages. Or for a quick parse of a provided APK, use
* {@link PackageManager#getPackageArchiveInfo(String, int)}.
*
@@ -655,7 +658,7 @@
// If available for the target user, or trying to match uninstalled packages and it's
// a system app.
- return PackageUserStateUtils.isAvailable(state, flags)
+ return isAvailable(state, flags)
|| (appInfo != null && appInfo.isSystemApp()
&& ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
|| (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
@@ -765,7 +768,7 @@
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final Activity a = p.activities.get(i);
- if (PackageUserStateUtils.isMatch(state, a.info, flags)) {
+ if (isMatch(state, a.info, flags)) {
if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(a.className)) {
continue;
}
@@ -782,7 +785,7 @@
final ActivityInfo[] res = new ActivityInfo[N];
for (int i = 0; i < N; i++) {
final Activity a = p.receivers.get(i);
- if (PackageUserStateUtils.isMatch(state, a.info, flags)) {
+ if (isMatch(state, a.info, flags)) {
res[num++] = generateActivityInfo(a, flags, state, userId);
}
}
@@ -796,7 +799,7 @@
final ServiceInfo[] res = new ServiceInfo[N];
for (int i = 0; i < N; i++) {
final Service s = p.services.get(i);
- if (PackageUserStateUtils.isMatch(state, s.info, flags)) {
+ if (isMatch(state, s.info, flags)) {
res[num++] = generateServiceInfo(s, flags, state, userId);
}
}
@@ -810,7 +813,7 @@
final ProviderInfo[] res = new ProviderInfo[N];
for (int i = 0; i < N; i++) {
final Provider pr = p.providers.get(i);
- if (PackageUserStateUtils.isMatch(state, pr.info, flags)) {
+ if (isMatch(state, pr.info, flags)) {
res[num++] = generateProviderInfo(pr, flags, state, userId);
}
}
@@ -7428,7 +7431,7 @@
mCompileSdkVersionCodename = dest.readString();
mUpgradeKeySets = (ArraySet<String>) dest.readArraySet(boot);
- mKeySetMapping = ParsingPackageUtils.readKeySetMapping(dest);
+ mKeySetMapping = readKeySetMapping(dest);
cpuAbiOverride = dest.readString();
use32bitAbi = (dest.readInt() == 1);
@@ -7554,7 +7557,7 @@
dest.writeInt(mCompileSdkVersion);
dest.writeString(mCompileSdkVersionCodename);
dest.writeArraySet(mUpgradeKeySets);
- ParsingPackageUtils.writeKeySetMapping(dest, mKeySetMapping);
+ writeKeySetMapping(dest, mKeySetMapping);
dest.writeString(cpuAbiOverride);
dest.writeInt(use32bitAbi ? 1 : 0);
dest.writeByteArray(restrictUpdateHash);
@@ -7977,7 +7980,7 @@
if (ai.category == ApplicationInfo.CATEGORY_UNDEFINED) {
ai.category = FallbackCategoryProvider.getFallbackCategory(ai.packageName);
}
- ai.seInfoUser = SELinuxUtil.getSeinfoUser(state);
+ ai.seInfoUser = getSeinfoUser(state);
final OverlayPaths overlayPaths = state.getAllOverlayPaths();
if (overlayPaths != null) {
ai.resourceDirs = overlayPaths.getResourceDirs().toArray(new String[0]);
@@ -9074,4 +9077,194 @@
return mCachedSplitApks[0][0];
}
}
+
+
+
+ public static boolean isMatch(@NonNull FrameworkPackageUserState state,
+ ComponentInfo componentInfo, long flags) {
+ return isMatch(state, componentInfo.applicationInfo.isSystemApp(),
+ componentInfo.applicationInfo.enabled, componentInfo.enabled,
+ componentInfo.directBootAware, componentInfo.name, flags);
+ }
+
+ public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem,
+ boolean isPackageEnabled, ComponentInfo component, long flags) {
+ return isMatch(state, isSystem, isPackageEnabled, component.isEnabled(),
+ component.directBootAware, component.name, flags);
+ }
+
+ /**
+ * Test if the given component is considered installed, enabled and a match for the given
+ * flags.
+ *
+ * <p>
+ * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and {@link
+ * PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
+ * </p>
+ */
+ public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem,
+ boolean isPackageEnabled, boolean isComponentEnabled,
+ boolean isComponentDirectBootAware, String componentName, long flags) {
+ final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
+ if (!isAvailable(state, flags) && !(isSystem && matchUninstalled)) {
+ return reportIfDebug(false, flags);
+ }
+
+ if (!isEnabled(state, isPackageEnabled, isComponentEnabled, componentName, flags)) {
+ return reportIfDebug(false, flags);
+ }
+
+ if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) {
+ if (!isSystem) {
+ return reportIfDebug(false, flags);
+ }
+ }
+
+ final boolean matchesUnaware = ((flags & PackageManager.MATCH_DIRECT_BOOT_UNAWARE) != 0)
+ && !isComponentDirectBootAware;
+ final boolean matchesAware = ((flags & PackageManager.MATCH_DIRECT_BOOT_AWARE) != 0)
+ && isComponentDirectBootAware;
+ return reportIfDebug(matchesUnaware || matchesAware, flags);
+ }
+
+ public static boolean isAvailable(@NonNull FrameworkPackageUserState state, long flags) {
+ // True if it is installed for this user and it is not hidden. If it is hidden,
+ // still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
+ final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
+ final boolean matchUninstalled = (flags & PackageManager.MATCH_UNINSTALLED_PACKAGES) != 0;
+ return matchAnyUser
+ || (state.isInstalled()
+ && (!state.isHidden() || matchUninstalled));
+ }
+
+ public static boolean reportIfDebug(boolean result, long flags) {
+ if (DEBUG_PARSER && !result) {
+ Slog.i(TAG, "No match!; flags: "
+ + DebugUtils.flagsToString(PackageManager.class, "MATCH_", flags) + " "
+ + Debug.getCaller());
+ }
+ return result;
+ }
+
+ public static boolean isEnabled(@NonNull FrameworkPackageUserState state, ComponentInfo componentInfo,
+ long flags) {
+ return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled,
+ componentInfo.name, flags);
+ }
+
+ public static boolean isEnabled(@NonNull FrameworkPackageUserState state, boolean isPackageEnabled,
+ ComponentInfo parsedComponent, long flags) {
+ return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
+ parsedComponent.name, flags);
+ }
+
+ /**
+ * Test if the given component is considered enabled.
+ */
+ public static boolean isEnabled(@NonNull FrameworkPackageUserState state,
+ boolean isPackageEnabled, boolean isComponentEnabled, String componentName,
+ long flags) {
+ if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
+ return true;
+ }
+
+ // First check if the overall package is disabled; if the package is
+ // enabled then fall through to check specific component
+ switch (state.getEnabledState()) {
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
+ return false;
+ case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
+ if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) == 0) {
+ return false;
+ }
+ // fallthrough
+ case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
+ if (!isPackageEnabled) {
+ return false;
+ }
+ // fallthrough
+ case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
+ break;
+ }
+
+ // Check if component has explicit state before falling through to
+ // the manifest default
+ if (state.isComponentEnabled(componentName)) {
+ return true;
+ } else if (state.isComponentDisabled(componentName)) {
+ return false;
+ }
+
+ return isComponentEnabled;
+ }
+
+ /**
+ * Writes the keyset mapping to the provided package. {@code null} mappings are permitted.
+ */
+ public static void writeKeySetMapping(@NonNull Parcel dest,
+ @NonNull Map<String, ArraySet<PublicKey>> keySetMapping) {
+ if (keySetMapping == null) {
+ dest.writeInt(-1);
+ return;
+ }
+
+ final int N = keySetMapping.size();
+ dest.writeInt(N);
+
+ for (String key : keySetMapping.keySet()) {
+ dest.writeString(key);
+ ArraySet<PublicKey> keys = keySetMapping.get(key);
+ if (keys == null) {
+ dest.writeInt(-1);
+ continue;
+ }
+
+ final int M = keys.size();
+ dest.writeInt(M);
+ for (int j = 0; j < M; j++) {
+ dest.writeSerializable(keys.valueAt(j));
+ }
+ }
+ }
+
+ /**
+ * Reads a keyset mapping from the given parcel at the given data position. May return
+ * {@code null} if the serialized mapping was {@code null}.
+ */
+ @NonNull
+ public static ArrayMap<String, ArraySet<PublicKey>> readKeySetMapping(@NonNull Parcel in) {
+ final int N = in.readInt();
+ if (N == -1) {
+ return null;
+ }
+
+ ArrayMap<String, ArraySet<PublicKey>> keySetMapping = new ArrayMap<>();
+ for (int i = 0; i < N; ++i) {
+ String key = in.readString();
+ final int M = in.readInt();
+ if (M == -1) {
+ keySetMapping.put(key, null);
+ continue;
+ }
+
+ ArraySet<PublicKey> keys = new ArraySet<>(M);
+ for (int j = 0; j < M; ++j) {
+ PublicKey pk =
+ in.readSerializable(PublicKey.class.getClassLoader(), PublicKey.class);
+ keys.add(pk);
+ }
+
+ keySetMapping.put(key, keys);
+ }
+
+ return keySetMapping;
+ }
+
+ public static String getSeinfoUser(FrameworkPackageUserState userState) {
+ if (userState.isInstantApp()) {
+ return ":ephemeralapp:complete";
+ }
+ return ":complete";
+ }
}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index 1639ee9..d5498a0 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -18,13 +18,6 @@
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-import static android.content.pm.parsing.ParsingPackageUtils.PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY;
-import static android.content.pm.parsing.ParsingPackageUtils.checkRequiredSystemProperties;
-import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
-import static android.content.pm.parsing.ParsingPackageUtils.validateName;
-import static android.content.pm.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
-import static android.content.pm.parsing.ParsingUtils.DEFAULT_MIN_SDK_VERSION;
-import static android.content.pm.parsing.ParsingUtils.DEFAULT_TARGET_SDK_VERSION;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
import android.annotation.NonNull;
@@ -37,6 +30,7 @@
import android.content.pm.parsing.result.ParseResult;
import android.content.res.ApkAssets;
import android.content.res.XmlResourceParser;
+import android.os.Build;
import android.os.Trace;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -66,7 +60,7 @@
/** @hide */
public class ApkLiteParseUtils {
- private static final String TAG = ParsingUtils.TAG;
+ private static final String TAG = "ApkLiteParseUtils";
private static final int PARSE_DEFAULT_INSTALL_LOCATION =
PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
@@ -75,6 +69,26 @@
public static final String APK_FILE_EXTENSION = ".apk";
+
+ // Constants copied from services.jar side since they're not accessible
+ private static final String ANDROID_RES_NAMESPACE =
+ "http://schemas.android.com/apk/res/android";
+ private static final int DEFAULT_MIN_SDK_VERSION = 1;
+ private static final int DEFAULT_TARGET_SDK_VERSION = 0;
+ public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
+ private static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
+ private static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
+ private static final String TAG_APPLICATION = "application";
+ private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
+ private static final String TAG_PROFILEABLE = "profileable";
+ private static final String TAG_RECEIVER = "receiver";
+ private static final String TAG_OVERLAY = "overlay";
+ private static final String TAG_USES_SDK = "uses-sdk";
+ private static final String TAG_USES_SPLIT = "uses-split";
+ private static final String TAG_MANIFEST = "manifest";
+ private static final int SDK_VERSION = Build.VERSION.SDK_INT;
+ private static final String[] SDK_CODENAMES = Build.VERSION.ACTIVE_CODENAMES;
+
/**
* Parse only lightweight details about the package at the given location.
* Automatically detects if the package is a monolithic style (single APK
@@ -312,15 +326,16 @@
"Failed to parse " + apkPath, e);
}
- parser = apkAssets.openXml(ParsingPackageUtils.ANDROID_MANIFEST_FILENAME);
+ parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME);
final SigningDetails signingDetails;
- if ((flags & ParsingPackageUtils.PARSE_COLLECT_CERTIFICATES) != 0) {
- final boolean skipVerify = (flags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
+ if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
+ final boolean skipVerify = (flags & PARSE_IS_SYSTEM_DIR) != 0;
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
try {
final ParseResult<SigningDetails> result =
- ParsingPackageUtils.getSigningDetails(input, apkFile.getAbsolutePath(),
+ FrameworkParsingPackageUtils.getSigningDetails(input,
+ apkFile.getAbsolutePath(),
skipVerify, /* isStaticSharedLibrary */ false,
SigningDetails.UNKNOWN, DEFAULT_TARGET_SDK_VERSION);
if (result.isError()) {
@@ -417,12 +432,12 @@
continue;
}
- if (ParsingPackageUtils.TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
+ if (TAG_PACKAGE_VERIFIER.equals(parser.getName())) {
final VerifierInfo verifier = parseVerifier(parser);
if (verifier != null) {
verifiers.add(verifier);
}
- } else if (ParsingPackageUtils.TAG_APPLICATION.equals(parser.getName())) {
+ } else if (TAG_APPLICATION.equals(parser.getName())) {
debuggable = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "debuggable",
false);
multiArch = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "multiArch",
@@ -453,15 +468,15 @@
continue;
}
- if (ParsingPackageUtils.TAG_PROFILEABLE.equals(parser.getName())) {
+ if (TAG_PROFILEABLE.equals(parser.getName())) {
profilableByShell = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE,
"shell", profilableByShell);
- } else if (ParsingPackageUtils.TAG_RECEIVER.equals(parser.getName())) {
+ } else if (TAG_RECEIVER.equals(parser.getName())) {
hasDeviceAdminReceiver |= isDeviceAdminReceiver(
parser, hasBindDeviceAdminPermission);
}
}
- } else if (ParsingPackageUtils.TAG_OVERLAY.equals(parser.getName())) {
+ } else if (TAG_OVERLAY.equals(parser.getName())) {
requiredSystemPropertyName = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
"requiredSystemPropertyName");
requiredSystemPropertyValue = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
@@ -470,7 +485,7 @@
overlayIsStatic = parser.getAttributeBooleanValue(ANDROID_RES_NAMESPACE, "isStatic",
false);
overlayPriority = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "priority", 0);
- } else if (ParsingPackageUtils.TAG_USES_SPLIT.equals(parser.getName())) {
+ } else if (TAG_USES_SPLIT.equals(parser.getName())) {
if (usesSplitName != null) {
Slog.w(TAG, "Only one <uses-split> permitted. Ignoring others.");
continue;
@@ -481,8 +496,8 @@
return input.error(PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"<uses-split> tag requires 'android:name' attribute");
}
- } else if (ParsingPackageUtils.TAG_USES_SDK.equals(parser.getName())) {
- // Mirrors ParsingPackageUtils#parseUsesSdk until lite and full parsing is combined
+ } else if (TAG_USES_SDK.equals(parser.getName())) {
+ // Mirrors FrameworkParsingPackageUtils#parseUsesSdk until lite and full parsing is combined
String minSdkVersionString = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
"minSdkVersion");
String targetSdkVersionString = parser.getAttributeValue(ANDROID_RES_NAMESPACE,
@@ -515,16 +530,15 @@
targetCode = minCode;
}
- ParseResult<Integer> targetResult = ParsingPackageUtils.computeTargetSdkVersion(
- targetVer, targetCode, ParsingPackageUtils.SDK_CODENAMES, input);
+ ParseResult<Integer> targetResult = FrameworkParsingPackageUtils.computeTargetSdkVersion(
+ targetVer, targetCode, SDK_CODENAMES, input);
if (targetResult.isError()) {
return input.error(targetResult);
}
targetSdkVersion = targetResult.getResult();
- ParseResult<Integer> minResult = ParsingPackageUtils.computeMinSdkVersion(
- minVer, minCode, ParsingPackageUtils.SDK_VERSION,
- ParsingPackageUtils.SDK_CODENAMES, input);
+ ParseResult<Integer> minResult = FrameworkParsingPackageUtils.computeMinSdkVersion(
+ minVer, minCode, SDK_VERSION, SDK_CODENAMES, input);
if (minResult.isError()) {
return input.error(minResult);
}
@@ -533,9 +547,9 @@
}
// Check to see if overlay should be excluded based on system property condition
- if ((flags & PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY) == 0
- && !checkRequiredSystemProperties(
- requiredSystemPropertyName, requiredSystemPropertyValue)) {
+ if ((flags & FrameworkParsingPackageUtils.PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY)
+ == 0 && !FrameworkParsingPackageUtils.checkRequiredSystemProperties(
+ requiredSystemPropertyName, requiredSystemPropertyValue)) {
String message = "Skipping target and overlay pair " + targetPackage + " and "
+ codePath + ": overlay ignored due to required system property: "
+ requiredSystemPropertyName + " with value: " + requiredSystemPropertyValue;
@@ -600,14 +614,15 @@
return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"No start tag found");
}
- if (!parser.getName().equals(ParsingPackageUtils.TAG_MANIFEST)) {
+ if (!parser.getName().equals(TAG_MANIFEST)) {
return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
"No <manifest> tag");
}
final String packageName = parser.getAttributeValue(null, "package");
if (!"android".equals(packageName)) {
- final ParseResult<?> nameResult = validateName(input, packageName, true, true);
+ final ParseResult<?> nameResult = FrameworkParsingPackageUtils.validateName(input,
+ packageName, true, true);
if (nameResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Invalid manifest package: " + nameResult.getErrorMessage());
@@ -619,7 +634,8 @@
if (splitName.length() == 0) {
splitName = null;
} else {
- final ParseResult<?> nameResult = validateName(input, splitName, false, false);
+ final ParseResult<?> nameResult = FrameworkParsingPackageUtils.validateName(input,
+ splitName, false, false);
if (nameResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
"Invalid manifest split: " + nameResult.getErrorMessage());
@@ -666,7 +682,7 @@
final String type = value.trim();
// Using requireFilename as true because it limits length of the name to the
// {@link #MAX_FILE_NAME_SIZE}.
- final ParseResult<?> nameResult = validateName(input, type,
+ final ParseResult<?> nameResult = FrameworkParsingPackageUtils.validateName(input, type,
false /* requireSeparator */, true /* requireFilename */);
if (nameResult.isError()) {
return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
@@ -688,7 +704,7 @@
return null;
}
- final PublicKey publicKey = parsePublicKey(encodedPublicKey);
+ final PublicKey publicKey = FrameworkParsingPackageUtils.parsePublicKey(encodedPublicKey);
if (publicKey == null) {
Slog.i(TAG, "Unable to parse verifier public key for " + packageName);
return null;
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
new file mode 100644
index 0000000..8b86a16
--- /dev/null
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -0,0 +1,397 @@
+/*
+ * 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.content.pm.parsing;
+
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+
+import android.annotation.CheckResult;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.pm.PackageManager;
+import android.content.pm.Signature;
+import android.content.pm.SigningDetails;
+import android.content.pm.parsing.result.ParseInput;
+import android.content.pm.parsing.result.ParseResult;
+import android.os.Build;
+import android.os.FileUtils;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Slog;
+import android.util.apk.ApkSignatureVerifier;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
+/** @hide */
+public class FrameworkParsingPackageUtils {
+
+ private static final String TAG = "FrameworkParsingPackageUtils";
+
+ /**
+ * For those names would be used as a part of the file name. Limits size to 223 and reserves 32
+ * for the OS.
+ */
+ private static final int MAX_FILE_NAME_SIZE = 223;
+
+ public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
+
+ /**
+ * Check if the given name is valid.
+ *
+ * @param name The name to check.
+ * @param requireSeparator {@code true} if the name requires containing a separator at least.
+ * @param requireFilename {@code true} to apply file name validation to the given name. It also
+ * limits length of the name to the {@link #MAX_FILE_NAME_SIZE}.
+ * @return Success if it's valid.
+ */
+ public static String validateName(String name, boolean requireSeparator,
+ boolean requireFilename) {
+ final int N = name.length();
+ boolean hasSep = false;
+ boolean front = true;
+ for (int i = 0; i < N; i++) {
+ final char c = name.charAt(i);
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ front = false;
+ continue;
+ }
+ if (!front) {
+ if ((c >= '0' && c <= '9') || c == '_') {
+ continue;
+ }
+ }
+ if (c == '.') {
+ hasSep = true;
+ front = true;
+ continue;
+ }
+ return "bad character '" + c + "'";
+ }
+ if (requireFilename) {
+ if (!FileUtils.isValidExtFilename(name)) {
+ return "Invalid filename";
+ } else if (N > MAX_FILE_NAME_SIZE) {
+ return "the length of the name is greater than " + MAX_FILE_NAME_SIZE;
+ }
+ }
+ return hasSep || !requireSeparator ? null : "must have at least one '.' separator";
+ }
+
+ /**
+ * @see #validateName(String, boolean, boolean)
+ */
+ public static ParseResult validateName(ParseInput input, String name, boolean requireSeparator,
+ boolean requireFilename) {
+ final String errorMessage = validateName(name, requireSeparator, requireFilename);
+ if (errorMessage != null) {
+ return input.error(errorMessage);
+ }
+ return input.success(null);
+ }
+
+ /**
+ * @return {@link PublicKey} of a given encoded public key.
+ */
+ public static PublicKey parsePublicKey(final String encodedPublicKey) {
+ if (encodedPublicKey == null) {
+ Slog.w(TAG, "Could not parse null public key");
+ return null;
+ }
+
+ try {
+ return parsePublicKey(Base64.decode(encodedPublicKey, Base64.DEFAULT));
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
+ return null;
+ }
+ }
+
+ /**
+ * @return {@link PublicKey} of the given byte array of a public key.
+ */
+ public static PublicKey parsePublicKey(final byte[] publicKey) {
+ if (publicKey == null) {
+ Slog.w(TAG, "Could not parse null public key");
+ return null;
+ }
+
+ final EncodedKeySpec keySpec;
+ try {
+ keySpec = new X509EncodedKeySpec(publicKey);
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
+ return null;
+ }
+
+ /* First try the key as an RSA key. */
+ try {
+ final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePublic(keySpec);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
+ } catch (InvalidKeySpecException e) {
+ // Not a RSA public key.
+ }
+
+ /* Now try it as a ECDSA key. */
+ try {
+ final KeyFactory keyFactory = KeyFactory.getInstance("EC");
+ return keyFactory.generatePublic(keySpec);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
+ } catch (InvalidKeySpecException e) {
+ // Not a ECDSA public key.
+ }
+
+ /* Now try it as a DSA key. */
+ try {
+ final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
+ return keyFactory.generatePublic(keySpec);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
+ } catch (InvalidKeySpecException e) {
+ // Not a DSA public key.
+ }
+
+ /* Not a supported key type */
+ return null;
+ }
+
+ /**
+ * Returns {@code true} if both the property name and value are empty or if the given system
+ * property is set to the specified value. Properties can be one or more, and if properties are
+ * more than one, they must be separated by comma, and count of names and values must be equal,
+ * and also every given system property must be set to the corresponding value.
+ * In all other cases, returns {@code false}
+ */
+ public static boolean checkRequiredSystemProperties(@Nullable String rawPropNames,
+ @Nullable String rawPropValues) {
+ if (TextUtils.isEmpty(rawPropNames) || TextUtils.isEmpty(rawPropValues)) {
+ if (!TextUtils.isEmpty(rawPropNames) || !TextUtils.isEmpty(rawPropValues)) {
+ // malformed condition - incomplete
+ Slog.w(TAG, "Disabling overlay - incomplete property :'" + rawPropNames
+ + "=" + rawPropValues + "' - require both requiredSystemPropertyName"
+ + " AND requiredSystemPropertyValue to be specified.");
+ return false;
+ }
+ // no valid condition set - so no exclusion criteria, overlay will be included.
+ return true;
+ }
+
+ final String[] propNames = rawPropNames.split(",");
+ final String[] propValues = rawPropValues.split(",");
+
+ if (propNames.length != propValues.length) {
+ Slog.w(TAG, "Disabling overlay - property :'" + rawPropNames
+ + "=" + rawPropValues + "' - require both requiredSystemPropertyName"
+ + " AND requiredSystemPropertyValue lists to have the same size.");
+ return false;
+ }
+ for (int i = 0; i < propNames.length; i++) {
+ // Check property value: make sure it is both set and equal to expected value
+ final String currValue = SystemProperties.get(propNames[i]);
+ if (!TextUtils.equals(currValue, propValues[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @CheckResult
+ public static ParseResult<SigningDetails> getSigningDetails(ParseInput input,
+ String baseCodePath, boolean skipVerify, boolean isStaticSharedLibrary,
+ @NonNull SigningDetails existingSigningDetails, int targetSdk) {
+ int minSignatureScheme = ApkSignatureVerifier.getMinimumSignatureSchemeVersionForTargetSdk(
+ targetSdk);
+ if (isStaticSharedLibrary) {
+ // must use v2 signing scheme
+ minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V2;
+ }
+ final ParseResult<SigningDetails> verified;
+ if (skipVerify) {
+ // systemDir APKs are already trusted, save time by not verifying; since the
+ // signature is not verified and some system apps can have their V2+ signatures
+ // stripped allow pulling the certs from the jar signature.
+ verified = ApkSignatureVerifier.unsafeGetCertsWithoutVerification(input, baseCodePath,
+ SigningDetails.SignatureSchemeVersion.JAR);
+ } else {
+ verified = ApkSignatureVerifier.verify(input, baseCodePath, minSignatureScheme);
+ }
+
+ if (verified.isError()) {
+ return input.error(verified);
+ }
+
+ // Verify that entries are signed consistently with the first pkg
+ // we encountered. Note that for splits, certificates may have
+ // already been populated during an earlier parse of a base APK.
+ if (existingSigningDetails == SigningDetails.UNKNOWN) {
+ return verified;
+ } else {
+ if (!Signature.areExactMatch(existingSigningDetails.getSignatures(),
+ verified.getResult().getSignatures())) {
+ return input.error(INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
+ baseCodePath + " has mismatched certificates");
+ }
+
+ return input.success(existingSigningDetails);
+ }
+ }
+
+ /**
+ * Computes the minSdkVersion to use at runtime. If the package is not compatible with this
+ * platform, populates {@code outError[0]} with an error message.
+ * <p>
+ * If {@code minCode} is not specified, e.g. the value is {@code null}, then behavior varies
+ * based on the {@code platformSdkVersion}:
+ * <ul>
+ * <li>If the platform SDK version is greater than or equal to the
+ * {@code minVers}, returns the {@code mniVers} unmodified.
+ * <li>Otherwise, returns -1 to indicate that the package is not
+ * compatible with this platform.
+ * </ul>
+ * <p>
+ * Otherwise, the behavior varies based on whether the current platform
+ * is a pre-release version, e.g. the {@code platformSdkCodenames} array
+ * has length > 0:
+ * <ul>
+ * <li>If this is a pre-release platform and the value specified by
+ * {@code targetCode} is contained within the array of allowed pre-release
+ * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
+ * <li>If this is a released platform, this method will return -1 to
+ * indicate that the package is not compatible with this platform.
+ * </ul>
+ *
+ * @param minVers minSdkVersion number, if specified in the application manifest,
+ * or 1 otherwise
+ * @param minCode minSdkVersion code, if specified in the application manifest, or
+ * {@code null} otherwise
+ * @param platformSdkVersion platform SDK version number, typically Build.VERSION.SDK_INT
+ * @param platformSdkCodenames array of allowed prerelease SDK codenames for this platform
+ * @return the minSdkVersion to use at runtime if successful
+ */
+ public static ParseResult<Integer> computeMinSdkVersion(@IntRange(from = 1) int minVers,
+ @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
+ @NonNull String[] platformSdkCodenames, @NonNull ParseInput input) {
+ // If it's a release SDK, make sure we meet the minimum SDK requirement.
+ if (minCode == null) {
+ if (minVers <= platformSdkVersion) {
+ return input.success(minVers);
+ }
+
+ // We don't meet the minimum SDK requirement.
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+ "Requires newer sdk version #" + minVers
+ + " (current version is #" + platformSdkVersion + ")");
+ }
+
+ // If it's a pre-release SDK and the codename matches this platform, we
+ // definitely meet the minimum SDK requirement.
+ if (matchTargetCode(platformSdkCodenames, minCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ // Otherwise, we're looking at an incompatible pre-release SDK.
+ if (platformSdkCodenames.length > 0) {
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+ "Requires development platform " + minCode
+ + " (current platform is any of "
+ + Arrays.toString(platformSdkCodenames) + ")");
+ } else {
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+ "Requires development platform " + minCode
+ + " but this is a release platform.");
+ }
+ }
+
+ /**
+ * Computes the targetSdkVersion to use at runtime. If the package is not compatible with this
+ * platform, populates {@code outError[0]} with an error message.
+ * <p>
+ * If {@code targetCode} is not specified, e.g. the value is {@code null}, then the {@code
+ * targetVers} will be returned unmodified.
+ * <p>
+ * Otherwise, the behavior varies based on whether the current platform is a pre-release
+ * version, e.g. the {@code platformSdkCodenames} array has length > 0:
+ * <ul>
+ * <li>If this is a pre-release platform and the value specified by
+ * {@code targetCode} is contained within the array of allowed pre-release
+ * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
+ * <li>If this is a released platform, this method will return -1 to
+ * indicate that the package is not compatible with this platform.
+ * </ul>
+ *
+ * @param targetVers targetSdkVersion number, if specified in the application
+ * manifest, or 0 otherwise
+ * @param targetCode targetSdkVersion code, if specified in the application manifest,
+ * or {@code null} otherwise
+ * @param platformSdkCodenames array of allowed pre-release SDK codenames for this platform
+ * @return the targetSdkVersion to use at runtime if successful
+ */
+ public static ParseResult<Integer> computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
+ @Nullable String targetCode, @NonNull String[] platformSdkCodenames,
+ @NonNull ParseInput input) {
+ // If it's a release SDK, return the version number unmodified.
+ if (targetCode == null) {
+ return input.success(targetVers);
+ }
+
+ // If it's a pre-release SDK and the codename matches this platform, it
+ // definitely targets this SDK.
+ if (matchTargetCode(platformSdkCodenames, targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+
+ // Otherwise, we're looking at an incompatible pre-release SDK.
+ if (platformSdkCodenames.length > 0) {
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+ "Requires development platform " + targetCode
+ + " (current platform is any of "
+ + Arrays.toString(platformSdkCodenames) + ")");
+ } else {
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
+ "Requires development platform " + targetCode
+ + " but this is a release platform.");
+ }
+ }
+
+ /**
+ * Matches a given {@code targetCode} against a set of release codeNames. Target codes can
+ * either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form {@code
+ * [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}).
+ */
+ private static boolean matchTargetCode(@NonNull String[] codeNames,
+ @NonNull String targetCode) {
+ final String targetCodeName;
+ final int targetCodeIdx = targetCode.indexOf('.');
+ if (targetCodeIdx == -1) {
+ targetCodeName = targetCode;
+ } else {
+ targetCodeName = targetCode.substring(0, targetCodeIdx);
+ }
+ return ArrayUtils.contains(codeNames, targetCodeName);
+ }
+}
diff --git a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
index 1a3fc85..c323704 100644
--- a/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
+++ b/core/java/android/content/pm/parsing/result/ParseTypeImpl.java
@@ -16,14 +16,11 @@
package android.content.pm.parsing.result;
-import static android.content.pm.parsing.ParsingUtils.NOT_SET;
-
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.pm.parsing.ParsingUtils;
import android.os.ServiceManager;
import android.util.ArrayMap;
import android.util.Log;
@@ -35,7 +32,7 @@
/** @hide */
public class ParseTypeImpl implements ParseInput, ParseResult<Object> {
- private static final String TAG = ParsingUtils.TAG;
+ private static final String TAG = "ParseTypeImpl";
public static final boolean DEBUG_FILL_STACK_TRACE = false;
@@ -64,7 +61,7 @@
private ArrayMap<Long, String> mDeferredErrors = null;
private String mPackageName;
- private int mTargetSdkVersion = NOT_SET;
+ private int mTargetSdkVersion = -1;
/**
* Specifically for {@link PackageManager#getPackageArchiveInfo(String, int)} where
@@ -121,7 +118,7 @@
// how many APKs they're going through.
mDeferredErrors.erase();
}
- mTargetSdkVersion = NOT_SET;
+ mTargetSdkVersion = -1;
return this;
}
@@ -141,7 +138,7 @@
if (DEBUG_THROW_ALL_ERRORS) {
return error(parseError);
}
- if (mTargetSdkVersion != NOT_SET) {
+ if (mTargetSdkVersion != -1) {
if (mDeferredErrors != null && mDeferredErrors.containsKey(deferredError)) {
// If the map already contains the key, that means it's already been checked and
// found to be disabled. Otherwise it would've failed when mTargetSdkVersion was
diff --git a/core/java/android/content/pm/pkg/FrameworkPackageUserState.java b/core/java/android/content/pm/pkg/FrameworkPackageUserState.java
index 0daf6cf..bac29b4 100644
--- a/core/java/android/content/pm/pkg/FrameworkPackageUserState.java
+++ b/core/java/android/content/pm/pkg/FrameworkPackageUserState.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -31,8 +31,9 @@
* See the services variant for method documentation.
*
* @hide
- * @deprecated Unless you know exactly what you're doing, you probably want the services variant.
+ * @deprecated Unused by framework.
*/
+@Deprecated
public interface FrameworkPackageUserState {
FrameworkPackageUserState DEFAULT = new FrameworkPackageUserStateDefault();
diff --git a/core/java/android/content/pm/pkg/FrameworkPackageUserStateDefault.java b/core/java/android/content/pm/pkg/FrameworkPackageUserStateDefault.java
index 27255da..3590620 100644
--- a/core/java/android/content/pm/pkg/FrameworkPackageUserStateDefault.java
+++ b/core/java/android/content/pm/pkg/FrameworkPackageUserStateDefault.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -25,7 +25,11 @@
import java.util.Map;
import java.util.Set;
-/** @hide */
+/**
+ * @hide
+ * @deprecated Unused by framework.
+ */
+@Deprecated
class FrameworkPackageUserStateDefault implements FrameworkPackageUserState {
@Override
diff --git a/core/java/android/content/pm/split/OWNERS b/core/java/android/content/pm/split/OWNERS
deleted file mode 100644
index 3d126d2..0000000
--- a/core/java/android/content/pm/split/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-# Bug component: 36137
-
-toddke@android.com
-toddke@google.com
-patb@google.com
diff --git a/core/java/android/hardware/ISerialManager.aidl b/core/java/android/hardware/ISerialManager.aidl
index 74d30f7..65a0fa4 100644
--- a/core/java/android/hardware/ISerialManager.aidl
+++ b/core/java/android/hardware/ISerialManager.aidl
@@ -22,8 +22,10 @@
interface ISerialManager
{
/* Returns a list of all available serial ports */
+ @EnforcePermission("SERIAL_PORT")
String[] getSerialPorts();
/* Returns a file descriptor for the serial port. */
+ @EnforcePermission("SERIAL_PORT")
ParcelFileDescriptor openSerialPort(String name);
}
diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java
index 0e42b02..37cfb49 100644
--- a/core/java/android/hardware/Sensor.java
+++ b/core/java/android/hardware/Sensor.java
@@ -712,6 +712,20 @@
public static final String STRING_TYPE_HINGE_ANGLE = "android.sensor.hinge_angle";
/**
+ * A constant describing a head tracker sensor.
+ *
+ * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+ */
+ public static final int TYPE_HEAD_TRACKER = 37;
+
+ /**
+ * A constant string describing a head tracker sensor.
+ *
+ * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details.
+ */
+ public static final String STRING_TYPE_HEAD_TRACKER = "android.sensor.head_tracker";
+
+ /**
* A constant describing all sensor types.
*/
@@ -831,6 +845,7 @@
1, // SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT
6, // SENSOR_TYPE_ACCELEROMETER_UNCALIBRATED
1, // SENSOR_TYPE_HINGE_ANGLE
+ 6, // SENSOR_TYPE_HEAD_TRACKER (discontinuity count is excluded)
};
/**
@@ -1283,6 +1298,9 @@
case TYPE_HINGE_ANGLE:
mStringType = STRING_TYPE_HINGE_ANGLE;
return true;
+ case TYPE_HEAD_TRACKER:
+ mStringType = STRING_TYPE_HEAD_TRACKER;
+ return true;
default:
return false;
}
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 232f234..c77c8cc 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -641,6 +641,41 @@
* <li> values[0]: Measured hinge angle between 0 and 360 degrees inclusive</li>
* </ul>
*
+ * <h4>{@link android.hardware.Sensor#TYPE_HEAD_TRACKER Sensor.TYPE_HEAD_TRACKER}:</h4>
+ *
+ * A sensor of this type measures the orientation of a user's head relative to an arbitrary
+ * reference frame, as well as the rate of rotation.
+ *
+ * Events produced by this sensor follow a special head-centric coordinate frame, where:
+ * <ul>
+ * <li> The X axis crosses through the user's ears, with the positive X direction extending
+ * out of the user's right ear</li>
+ * <li> The Y axis crosses from the back of the user's head through their nose, with the
+ * positive direction extending out of the nose, and the X/Y plane being nominally
+ * parallel to the ground when the user is upright and looking straight ahead</li>
+ * <li> The Z axis crosses from the neck through the top of the user's head, with the
+ * positive direction extending out from the top of the head</li>
+ * </ul>
+ *
+ * Data is provided in Euler vector representation, which is a vector whose direction indicates
+ * the axis of rotation and magnitude indicates the angle to rotate around that axis, in
+ * radians.
+ *
+ * The first three elements provide the transform from the (arbitrary, possibly slowly drifting)
+ * reference frame to the head frame. The magnitude of this vector is in range [0, π]
+ * radians, while the value of individual axes is in range [-π, π]. The next three
+ * elements provide the estimated rotational velocity of the user's head relative to itself, in
+ * radians per second.
+ *
+ * <ul>
+ * <li> values[0] : X component of Euler vector representing rotation</li>
+ * <li> values[1] : Y component of Euler vector representing rotation</li>
+ * <li> values[2] : Z component of Euler vector representing rotation</li>
+ * <li> values[3] : X component of Euler vector representing angular velocity</li>
+ * <li> values[4] : Y component of Euler vector representing angular velocity</li>
+ * <li> values[5] : Z component of Euler vector representing angular velocity</li>
+ * </ul>
+ *
* @see GeomagneticField
*/
public final float[] values;
diff --git a/core/java/android/hardware/SensorEventCallback.java b/core/java/android/hardware/SensorEventCallback.java
index bac212a..7b0092d 100644
--- a/core/java/android/hardware/SensorEventCallback.java
+++ b/core/java/android/hardware/SensorEventCallback.java
@@ -16,6 +16,8 @@
package android.hardware;
+import android.annotation.NonNull;
+
/**
* Used for receiving sensor additional information frames.
*/
@@ -52,4 +54,21 @@
* reported from sensor hardware.
*/
public void onSensorAdditionalInfo(SensorAdditionalInfo info) {}
+
+ /**
+ * Called when the next {@link android.hardware.SensorEvent SensorEvent} to be delivered via the
+ * {@link #onSensorChanged(SensorEvent) onSensorChanged} method represents the first event after
+ * a discontinuity.
+ *
+ * The exact meaning of discontinuity depends on the sensor type. For {@link
+ * android.hardware.Sensor#TYPE_HEAD_TRACKER Sensor.TYPE_HEAD_TRACKER}, this means that the
+ * reference frame has suddenly and significantly changed.
+ *
+ * Note that this concept is either not relevant to or not supported by most sensor types,
+ * {@link android.hardware.Sensor#TYPE_HEAD_TRACKER Sensor.TYPE_HEAD_TRACKER} being the notable
+ * exception.
+ *
+ * @param sensor The {@link android.hardware.Sensor Sensor} which experienced the discontinuity.
+ */
+ public void onSensorDiscontinuity(@NonNull Sensor sensor) {}
}
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 3a8513b..32a5ee7 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -676,6 +676,7 @@
private long mNativeSensorEventQueue;
private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
+ protected final SparseIntArray mSensorDiscontinuityCounts = new SparseIntArray();
private final CloseGuard mCloseGuard = CloseGuard.get();
protected final SystemSensorManager mManager;
@@ -875,10 +876,21 @@
// call onAccuracyChanged() only if the value changes
final int accuracy = mSensorAccuracies.get(handle);
- if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {
+ if (t.accuracy >= 0 && accuracy != t.accuracy) {
mSensorAccuracies.put(handle, t.accuracy);
mListener.onAccuracyChanged(t.sensor, t.accuracy);
}
+
+ // call onSensorDiscontinuity() if the discontinuity counter changed
+ if (t.sensor.getType() == Sensor.TYPE_HEAD_TRACKER
+ && mListener instanceof SensorEventCallback) {
+ final int lastCount = mSensorDiscontinuityCounts.get(handle);
+ final int curCount = Float.floatToIntBits(values[6]);
+ if (lastCount >= 0 && lastCount != curCount) {
+ ((SensorEventCallback) mListener).onSensorDiscontinuity(t.sensor);
+ }
+ }
+
mListener.onSensorChanged(t);
}
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/os/Binder.java b/core/java/android/os/Binder.java
index 429450c..80cf2f8 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -311,6 +311,7 @@
private final long mObject;
private IInterface mOwner;
+ @Nullable
private String mDescriptor;
private volatile String[] mTransactionTraceNames = null;
private volatile String mSimpleDescriptor = null;
@@ -930,8 +931,8 @@
transactionNames[i] = buf.toString();
buf.setLength(0);
}
- mTransactionTraceNames = transactionNames;
mSimpleDescriptor = descriptor;
+ mTransactionTraceNames = transactionNames;
}
final int index = transactionCode - FIRST_CALL_TRANSACTION;
if (index < 0 || index >= mTransactionTraceNames.length) {
@@ -940,13 +941,19 @@
return mTransactionTraceNames[index];
}
- private String getSimpleDescriptor() {
- final int dot = mDescriptor.lastIndexOf(".");
+ private @NonNull String getSimpleDescriptor() {
+ String descriptor = mDescriptor;
+ if (descriptor == null) {
+ // Just "Binder" to avoid null checks in transaction name tracing.
+ return "Binder";
+ }
+
+ final int dot = descriptor.lastIndexOf(".");
if (dot > 0) {
// Strip the package name
- return mDescriptor.substring(dot + 1);
+ return descriptor.substring(dot + 1);
}
- return mDescriptor;
+ return descriptor;
}
/**
diff --git a/core/java/android/service/games/OWNERS b/core/java/android/service/games/OWNERS
new file mode 100644
index 0000000..81d94e0
--- /dev/null
+++ b/core/java/android/service/games/OWNERS
@@ -0,0 +1 @@
+include /GAME_MANAGER_OWNERS
diff --git a/core/java/android/text/MeasuredParagraph.java b/core/java/android/text/MeasuredParagraph.java
index 6a3c618..748d551 100644
--- a/core/java/android/text/MeasuredParagraph.java
+++ b/core/java/android/text/MeasuredParagraph.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.graphics.Paint;
import android.graphics.Rect;
+import android.graphics.text.LineBreakConfig;
import android.graphics.text.MeasuredText;
import android.text.AutoGrowArray.ByteArray;
import android.text.AutoGrowArray.FloatArray;
@@ -124,7 +125,7 @@
// The native MeasuredParagraph.
private @Nullable MeasuredText mMeasuredText;
- // Following two objects are for avoiding object allocation.
+ // Following three objects are for avoiding object allocation.
private @NonNull TextPaint mCachedPaint = new TextPaint();
private @Nullable Paint.FontMetricsInt mCachedFm;
@@ -350,7 +351,8 @@
if (mt.mSpanned == null) {
// No style change by MetricsAffectingSpan. Just measure all text.
mt.applyMetricsAffectingSpan(
- paint, null /* spans */, start, end, null /* native builder ptr */);
+ paint, null /* lineBreakConfig */, null /* spans */, start, end,
+ null /* native builder ptr */);
} else {
// There may be a MetricsAffectingSpan. Split into span transitions and apply styles.
int spanEnd;
@@ -360,7 +362,8 @@
MetricAffectingSpan.class);
spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class);
mt.applyMetricsAffectingSpan(
- paint, spans, spanStart, spanEnd, null /* native builder ptr */);
+ paint, null /* line break config */, spans, spanStart, spanEnd,
+ null /* native builder ptr */);
}
}
return mt;
@@ -373,6 +376,7 @@
* result to recycle and returns recycle.
*
* @param paint the paint to be used for rendering the text.
+ * @param lineBreakConfig the line break configuration for text wrapping.
* @param text the character sequence to be measured
* @param start the inclusive start offset of the target region in the text
* @param end the exclusive end offset of the target region in the text
@@ -386,6 +390,7 @@
*/
public static @NonNull MeasuredParagraph buildForStaticLayout(
@NonNull TextPaint paint,
+ @Nullable LineBreakConfig lineBreakConfig,
@NonNull CharSequence text,
@IntRange(from = 0) int start,
@IntRange(from = 0) int end,
@@ -411,7 +416,8 @@
} else {
if (mt.mSpanned == null) {
// No style change by MetricsAffectingSpan. Just measure all text.
- mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, builder);
+ mt.applyMetricsAffectingSpan(paint, lineBreakConfig, null /* spans */, start, end,
+ builder);
mt.mSpanEndCache.append(end);
} else {
// There may be a MetricsAffectingSpan. Split into span transitions and apply
@@ -424,7 +430,9 @@
MetricAffectingSpan.class);
spans = TextUtils.removeEmptySpans(spans, mt.mSpanned,
MetricAffectingSpan.class);
- mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd, builder);
+ // TODO: Update line break config with spans.
+ mt.applyMetricsAffectingSpan(paint, lineBreakConfig, spans, spanStart, spanEnd,
+ builder);
mt.mSpanEndCache.append(spanEnd);
}
}
@@ -500,12 +508,13 @@
private void applyReplacementRun(@NonNull ReplacementSpan replacement,
@IntRange(from = 0) int start, // inclusive, in copied buffer
@IntRange(from = 0) int end, // exclusive, in copied buffer
+ @NonNull TextPaint paint,
@Nullable MeasuredText.Builder builder) {
// Use original text. Shouldn't matter.
// TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for
// backward compatibility? or Should we initialize them for getFontMetricsInt?
final float width = replacement.getSize(
- mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm);
+ paint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm);
if (builder == null) {
// Assigns all width to the first character. This is the same behavior as minikin.
mWidths.set(start, width);
@@ -514,22 +523,24 @@
}
mWholeWidth += width;
} else {
- builder.appendReplacementRun(mCachedPaint, end - start, width);
+ builder.appendReplacementRun(paint, end - start, width);
}
}
private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer
@IntRange(from = 0) int end, // exclusive, in copied buffer
+ @NonNull TextPaint paint,
+ @Nullable LineBreakConfig config,
@Nullable MeasuredText.Builder builder) {
if (mLtrWithoutBidi) {
// If the whole text is LTR direction, just apply whole region.
if (builder == null) {
- mWholeWidth += mCachedPaint.getTextRunAdvances(
+ mWholeWidth += paint.getTextRunAdvances(
mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */,
mWidths.getRawArray(), start);
} else {
- builder.appendStyleRun(mCachedPaint, end - start, false /* isRtl */);
+ builder.appendStyleRun(paint, config, end - start, false /* isRtl */);
}
} else {
// If there is multiple bidi levels, split into individual bidi level and apply style.
@@ -541,11 +552,11 @@
final boolean isRtl = (level & 0x1) != 0;
if (builder == null) {
final int levelLength = levelEnd - levelStart;
- mWholeWidth += mCachedPaint.getTextRunAdvances(
+ mWholeWidth += paint.getTextRunAdvances(
mCopiedBuffer, levelStart, levelLength, levelStart, levelLength,
isRtl, mWidths.getRawArray(), levelStart);
} else {
- builder.appendStyleRun(mCachedPaint, levelEnd - levelStart, isRtl);
+ builder.appendStyleRun(paint, config, levelEnd - levelStart, isRtl);
}
if (levelEnd == end) {
break;
@@ -559,6 +570,7 @@
private void applyMetricsAffectingSpan(
@NonNull TextPaint paint,
+ @Nullable LineBreakConfig lineBreakConfig,
@Nullable MetricAffectingSpan[] spans,
@IntRange(from = 0) int start, // inclusive, in original text buffer
@IntRange(from = 0) int end, // exclusive, in original text buffer
@@ -595,9 +607,11 @@
}
if (replacement != null) {
- applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, builder);
+ applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer, mCachedPaint,
+ builder);
} else {
- applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, builder);
+ applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, mCachedPaint,
+ lineBreakConfig, builder);
}
if (needFontMetrics) {
diff --git a/core/java/android/text/PrecomputedText.java b/core/java/android/text/PrecomputedText.java
index 152570f..ce63376 100644
--- a/core/java/android/text/PrecomputedText.java
+++ b/core/java/android/text/PrecomputedText.java
@@ -22,6 +22,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
+import android.graphics.text.LineBreakConfig;
import android.graphics.text.MeasuredText;
import android.text.style.MetricAffectingSpan;
@@ -96,6 +97,9 @@
// The hyphenation frequency for this measured text.
private final @Layout.HyphenationFrequency int mHyphenationFrequency;
+ // The line break configuration for calculating text wrapping.
+ private final @Nullable LineBreakConfig mLineBreakConfig;
+
/**
* A builder for creating {@link Params}.
*/
@@ -113,6 +117,9 @@
private @Layout.HyphenationFrequency int mHyphenationFrequency =
Layout.HYPHENATION_FREQUENCY_NORMAL;
+ // The line break configuration for calculating text wrapping.
+ private @Nullable LineBreakConfig mLineBreakConfig;
+
/**
* Builder constructor.
*
@@ -130,6 +137,7 @@
mTextDir = params.mTextDir;
mBreakStrategy = params.mBreakStrategy;
mHyphenationFrequency = params.mHyphenationFrequency;
+ mLineBreakConfig = params.mLineBreakConfig;
}
/**
@@ -177,24 +185,41 @@
}
/**
+ * Set the line break config for the text wrapping.
+ *
+ * @param lineBreakConfig the newly line break configuration.
+ * @return this builder, useful for chaining.
+ * @see StaticLayout.Builder#setLineBreakConfig
+ */
+ public @NonNull Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
+ mLineBreakConfig = lineBreakConfig;
+ return this;
+ }
+
+ /**
* Build the {@link Params}.
*
* @return the layout parameter
*/
public @NonNull Params build() {
- return new Params(mPaint, mTextDir, mBreakStrategy, mHyphenationFrequency);
+ return new Params(mPaint, mLineBreakConfig, mTextDir, mBreakStrategy,
+ mHyphenationFrequency);
}
}
// This is public hidden for internal use.
// For the external developers, use Builder instead.
/** @hide */
- public Params(@NonNull TextPaint paint, @NonNull TextDirectionHeuristic textDir,
- @Layout.BreakStrategy int strategy, @Layout.HyphenationFrequency int frequency) {
+ public Params(@NonNull TextPaint paint,
+ @Nullable LineBreakConfig lineBreakConfig,
+ @NonNull TextDirectionHeuristic textDir,
+ @Layout.BreakStrategy int strategy,
+ @Layout.HyphenationFrequency int frequency) {
mPaint = paint;
mTextDir = textDir;
mBreakStrategy = strategy;
mHyphenationFrequency = frequency;
+ mLineBreakConfig = lineBreakConfig;
}
/**
@@ -233,6 +258,15 @@
return mHyphenationFrequency;
}
+ /**
+ * Return the line break configuration for this text.
+ *
+ * @return the current line break configuration, null if no line break configuration is set.
+ */
+ public @Nullable LineBreakConfig getLineBreakConfig() {
+ return mLineBreakConfig;
+ }
+
/** @hide */
@IntDef(value = { UNUSABLE, NEED_RECOMPUTE, USABLE })
@Retention(RetentionPolicy.SOURCE)
@@ -262,8 +296,9 @@
/** @hide */
public @CheckResultUsableResult int checkResultUsable(@NonNull TextPaint paint,
@NonNull TextDirectionHeuristic textDir, @Layout.BreakStrategy int strategy,
- @Layout.HyphenationFrequency int frequency) {
+ @Layout.HyphenationFrequency int frequency, @Nullable LineBreakConfig lbConfig) {
if (mBreakStrategy == strategy && mHyphenationFrequency == frequency
+ && isLineBreakEquals(mLineBreakConfig, lbConfig)
&& mPaint.equalsForTextMeasurement(paint)) {
return mTextDir == textDir ? USABLE : NEED_RECOMPUTE;
} else {
@@ -272,6 +307,29 @@
}
/**
+ * Check the two LineBreakConfig instances are equal.
+ * This method assumes they are equal if one parameter is null and the other parameter has
+ * a LineBreakStyle value of LineBreakConfig.LINE_BREAK_STYLE_NONE.
+ *
+ * @param o1 the first LineBreakConfig instance.
+ * @param o2 the second LineBreakConfig instance.
+ * @return true if the two LineBreakConfig instances are equal.
+ */
+ private boolean isLineBreakEquals(LineBreakConfig o1, LineBreakConfig o2) {
+ if (Objects.equals(o1, o2)) {
+ return true;
+ }
+ if (o1 == null && (o2 != null
+ && o2.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) {
+ return true;
+ } else if (o2 == null && (o1 != null
+ && o1.getLineBreakStyle() == LineBreakConfig.LINE_BREAK_STYLE_NONE)) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Check if the same text layout.
*
* @return true if this and the given param result in the same text layout
@@ -286,21 +344,25 @@
}
Params param = (Params) o;
return checkResultUsable(param.mPaint, param.mTextDir, param.mBreakStrategy,
- param.mHyphenationFrequency) == Params.USABLE;
+ param.mHyphenationFrequency, param.mLineBreakConfig) == Params.USABLE;
}
@Override
public int hashCode() {
// TODO: implement MinikinPaint::hashCode and use it to keep consistency with equals.
+ int lineBreakStyle = (mLineBreakConfig != null)
+ ? mLineBreakConfig.getLineBreakStyle() : LineBreakConfig.LINE_BREAK_STYLE_NONE;
return Objects.hash(mPaint.getTextSize(), mPaint.getTextScaleX(), mPaint.getTextSkewX(),
mPaint.getLetterSpacing(), mPaint.getWordSpacing(), mPaint.getFlags(),
mPaint.getTextLocales(), mPaint.getTypeface(),
mPaint.getFontVariationSettings(), mPaint.isElegantTextHeight(), mTextDir,
- mBreakStrategy, mHyphenationFrequency);
+ mBreakStrategy, mHyphenationFrequency, lineBreakStyle);
}
@Override
public String toString() {
+ int lineBreakStyle = (mLineBreakConfig != null)
+ ? mLineBreakConfig.getLineBreakStyle() : LineBreakConfig.LINE_BREAK_STYLE_NONE;
return "{"
+ "textSize=" + mPaint.getTextSize()
+ ", textScaleX=" + mPaint.getTextScaleX()
@@ -313,6 +375,7 @@
+ ", textDir=" + mTextDir
+ ", breakStrategy=" + mBreakStrategy
+ ", hyphenationFrequency=" + mHyphenationFrequency
+ + ", lineBreakStyle=" + lineBreakStyle
+ "}";
}
};
@@ -369,7 +432,8 @@
final PrecomputedText.Params hintParams = hintPct.getParams();
final @Params.CheckResultUsableResult int checkResult =
hintParams.checkResultUsable(params.mPaint, params.mTextDir,
- params.mBreakStrategy, params.mHyphenationFrequency);
+ params.mBreakStrategy, params.mHyphenationFrequency,
+ params.mLineBreakConfig);
switch (checkResult) {
case Params.USABLE:
return hintPct;
@@ -418,9 +482,9 @@
final int paraStart = pct.getParagraphStart(i);
final int paraEnd = pct.getParagraphEnd(i);
result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
- params.getTextPaint(), pct, paraStart, paraEnd, params.getTextDirection(),
- hyphenationMode, computeLayout, pct.getMeasuredParagraph(i),
- null /* no recycle */)));
+ params.getTextPaint(), params.getLineBreakConfig(), pct, paraStart, paraEnd,
+ params.getTextDirection(), hyphenationMode, computeLayout,
+ pct.getMeasuredParagraph(i), null /* no recycle */)));
}
return result.toArray(new ParagraphInfo[result.size()]);
}
@@ -456,8 +520,9 @@
}
result.add(new ParagraphInfo(paraEnd, MeasuredParagraph.buildForStaticLayout(
- params.getTextPaint(), text, paraStart, paraEnd, params.getTextDirection(),
- hyphenationMode, computeLayout, null /* no hint */, null /* no recycle */)));
+ params.getTextPaint(), params.getLineBreakConfig(), text, paraStart, paraEnd,
+ params.getTextDirection(), hyphenationMode, computeLayout, null /* no hint */,
+ null /* no recycle */)));
}
return result.toArray(new ParagraphInfo[result.size()]);
}
@@ -544,11 +609,11 @@
public @Params.CheckResultUsableResult int checkResultUsable(@IntRange(from = 0) int start,
@IntRange(from = 0) int end, @NonNull TextDirectionHeuristic textDir,
@NonNull TextPaint paint, @Layout.BreakStrategy int strategy,
- @Layout.HyphenationFrequency int frequency) {
+ @Layout.HyphenationFrequency int frequency, @NonNull LineBreakConfig lbConfig) {
if (mStart != start || mEnd != end) {
return Params.UNUSABLE;
} else {
- return mParams.checkResultUsable(paint, textDir, strategy, frequency);
+ return mParams.checkResultUsable(paint, textDir, strategy, frequency, lbConfig);
}
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index b1bc766..b10fc37 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -22,6 +22,7 @@
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.Paint;
+import android.graphics.text.LineBreakConfig;
import android.graphics.text.LineBreaker;
import android.os.Build;
import android.text.style.LeadingMarginSpan;
@@ -403,6 +404,21 @@
}
/**
+ * Set the line break configuration. The line break will be passed to native used for
+ * calculating the text wrapping. The default value of the line break style is
+ * {@link LineBreakConfig#LINE_BREAK_STYLE_NONE}
+ *
+ * @param lineBreakConfig the line break configuration for text wrapping.
+ * @return this builder, useful for chaining.
+ * @see android.widget.TextView#setLineBreakConfig
+ */
+ @NonNull
+ public Builder setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
+ mLineBreakConfig = lineBreakConfig;
+ return this;
+ }
+
+ /**
* Build the {@link StaticLayout} after options have been set.
*
* <p>Note: the builder object must not be reused in any way after calling this
@@ -438,6 +454,7 @@
@Nullable private int[] mRightIndents;
private int mJustificationMode;
private boolean mAddLastLineLineSpacing;
+ private LineBreakConfig mLineBreakConfig;
private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
@@ -670,7 +687,7 @@
PrecomputedText precomputed = (PrecomputedText) source;
final @PrecomputedText.Params.CheckResultUsableResult int checkResult =
precomputed.checkResultUsable(bufStart, bufEnd, textDir, paint,
- b.mBreakStrategy, b.mHyphenationFrequency);
+ b.mBreakStrategy, b.mHyphenationFrequency, b.mLineBreakConfig);
switch (checkResult) {
case PrecomputedText.Params.UNUSABLE:
break;
@@ -680,6 +697,7 @@
.setBreakStrategy(b.mBreakStrategy)
.setHyphenationFrequency(b.mHyphenationFrequency)
.setTextDirection(textDir)
+ .setLineBreakConfig(b.mLineBreakConfig)
.build();
precomputed = PrecomputedText.create(precomputed, newParams);
paragraphInfo = precomputed.getParagraphInfo();
@@ -692,8 +710,8 @@
}
if (paragraphInfo == null) {
- final PrecomputedText.Params param = new PrecomputedText.Params(paint, textDir,
- b.mBreakStrategy, b.mHyphenationFrequency);
+ final PrecomputedText.Params param = new PrecomputedText.Params(paint,
+ b.mLineBreakConfig, textDir, b.mBreakStrategy, b.mHyphenationFrequency);
paragraphInfo = PrecomputedText.createMeasuredParagraphs(source, param, bufStart,
bufEnd, false /* computeLayout */);
}
diff --git a/core/java/android/util/apk/ApkSignatureVerifier.java b/core/java/android/util/apk/ApkSignatureVerifier.java
index 41b749e..bff5426 100644
--- a/core/java/android/util/apk/ApkSignatureVerifier.java
+++ b/core/java/android/util/apk/ApkSignatureVerifier.java
@@ -27,7 +27,7 @@
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningDetails.SignatureSchemeVersion;
-import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.os.Build;
@@ -380,7 +380,7 @@
// Gather certs from AndroidManifest.xml, which every APK must have, as an optimization
// to not need to verify the whole APK when verifyFUll == false.
final ZipEntry manifestEntry = jarFile.findEntry(
- ParsingPackageUtils.ANDROID_MANIFEST_FILENAME);
+ ApkLiteParseUtils.ANDROID_MANIFEST_FILENAME);
if (manifestEntry == null) {
return input.error(INSTALL_PARSE_FAILED_BAD_MANIFEST,
"Package " + apkPath + " has no manifest");
@@ -394,7 +394,7 @@
if (ArrayUtils.isEmpty(lastCerts)) {
return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Package "
+ apkPath + " has no certificates at entry "
- + ParsingPackageUtils.ANDROID_MANIFEST_FILENAME);
+ + ApkLiteParseUtils.ANDROID_MANIFEST_FILENAME);
}
lastSigs = convertToSignatures(lastCerts);
@@ -407,7 +407,7 @@
final String entryName = entry.getName();
if (entryName.startsWith("META-INF/")) continue;
- if (entryName.equals(ParsingPackageUtils.ANDROID_MANIFEST_FILENAME)) continue;
+ if (entryName.equals(ApkLiteParseUtils.ANDROID_MANIFEST_FILENAME)) continue;
toVerify.add(entry);
}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index be172f7..9b8523f 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -19,6 +19,9 @@
import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP;
import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.graphics.FrameInfo;
@@ -151,10 +154,15 @@
private static final int MSG_DO_SCHEDULE_VSYNC = 1;
private static final int MSG_DO_SCHEDULE_CALLBACK = 2;
- // All frame callbacks posted by applications have this token.
+ // All frame callbacks posted by applications have this token or EXTENDED_FRAME_CALLBACK_TOKEN.
private static final Object FRAME_CALLBACK_TOKEN = new Object() {
public String toString() { return "FRAME_CALLBACK_TOKEN"; }
};
+ private static final Object EXTENDED_FRAME_CALLBACK_TOKEN = new Object() {
+ public String toString() {
+ return "EXTENDED_FRAME_CALLBACK_TOKEN";
+ }
+ };
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private final Object mLock = new Object();
@@ -484,6 +492,24 @@
}
/**
+ * Posts an extended frame callback to run on the next frame.
+ * <p>
+ * The callback runs once then is automatically removed.
+ * </p>
+ *
+ * @param callback The extended frame callback to run during the next frame.
+ *
+ * @see #removeExtendedFrameCallback
+ */
+ public void postExtendedFrameCallback(@NonNull ExtendedFrameCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback must not be null");
+ }
+
+ postCallbackDelayedInternal(CALLBACK_ANIMATION, callback, EXTENDED_FRAME_CALLBACK_TOKEN, 0);
+ }
+
+ /**
* Removes callbacks that have the specified action and token.
*
* @param callbackType The callback type.
@@ -573,6 +599,21 @@
}
/**
+ * Removes a previously posted extended frame callback.
+ *
+ * @param callback The extended frame callback to remove.
+ *
+ * @see #postExtendedFrameCallback
+ */
+ public void removeExtendedFrameCallback(@Nullable ExtendedFrameCallback callback) {
+ if (callback == null) {
+ throw new IllegalArgumentException("callback must not be null");
+ }
+
+ removeCallbacksInternal(CALLBACK_ANIMATION, callback, EXTENDED_FRAME_CALLBACK_TOKEN);
+ }
+
+ /**
* Gets the time when the current frame started.
* <p>
* This method provides the time in milliseconds when the frame started being rendered.
@@ -673,7 +714,7 @@
* @hide
*/
public long getVsyncId() {
- return mLastVsyncEventData.id;
+ return mLastVsyncEventData.preferredFrameTimeline().vsyncId;
}
/**
@@ -684,7 +725,7 @@
* @hide
*/
public long getFrameDeadline() {
- return mLastVsyncEventData.frameDeadline;
+ return mLastVsyncEventData.preferredFrameTimeline().deadline;
}
void setFPSDivisor(int divisor) {
@@ -705,8 +746,9 @@
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- "Choreographer#doFrame " + vsyncEventData.id);
+ "Choreographer#doFrame " + vsyncEventData.preferredFrameTimeline().vsyncId);
}
+ FrameData frameData = new FrameData(frameTimeNanos, vsyncEventData);
synchronized (mLock) {
if (!mFrameScheduled) {
traceMessage("Frame not scheduled");
@@ -737,6 +779,7 @@
+ "time to " + (lastFrameOffset * 0.000001f) + " ms in the past.");
}
frameTimeNanos = startNanos - lastFrameOffset;
+ frameData.setFrameTimeNanos(-lastFrameOffset);
}
if (frameTimeNanos < mLastFrameTimeNanos) {
@@ -758,8 +801,10 @@
}
}
- mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos, vsyncEventData.id,
- vsyncEventData.frameDeadline, startNanos, vsyncEventData.frameInterval);
+ mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos,
+ vsyncEventData.preferredFrameTimeline().vsyncId,
+ vsyncEventData.preferredFrameTimeline().deadline, startNanos,
+ vsyncEventData.frameInterval);
mFrameScheduled = false;
mLastFrameTimeNanos = frameTimeNanos;
mLastFrameIntervalNanos = frameIntervalNanos;
@@ -769,17 +814,17 @@
AnimationUtils.lockAnimationClock(frameTimeNanos / TimeUtils.NANOS_PER_MS);
mFrameInfo.markInputHandlingStart();
- doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos, frameIntervalNanos);
+ doCallbacks(Choreographer.CALLBACK_INPUT, frameData, frameIntervalNanos);
mFrameInfo.markAnimationsStart();
- doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos, frameIntervalNanos);
- doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameTimeNanos,
+ doCallbacks(Choreographer.CALLBACK_ANIMATION, frameData, frameIntervalNanos);
+ doCallbacks(Choreographer.CALLBACK_INSETS_ANIMATION, frameData,
frameIntervalNanos);
mFrameInfo.markPerformTraversalsStart();
- doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos, frameIntervalNanos);
+ doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameData, frameIntervalNanos);
- doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos, frameIntervalNanos);
+ doCallbacks(Choreographer.CALLBACK_COMMIT, frameData, frameIntervalNanos);
} finally {
AnimationUtils.unlockAnimationClock();
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
@@ -793,8 +838,9 @@
}
}
- void doCallbacks(int callbackType, long frameTimeNanos, long frameIntervalNanos) {
+ void doCallbacks(int callbackType, FrameData frameData, long frameIntervalNanos) {
CallbackRecord callbacks;
+ long frameTimeNanos = frameData.mFrameTimeNanos;
synchronized (mLock) {
// We use "now" to determine when callbacks become due because it's possible
// for earlier processing phases in a frame to post callbacks that should run
@@ -831,6 +877,7 @@
}
frameTimeNanos = now - lastFrameOffset;
mLastFrameTimeNanos = frameTimeNanos;
+ frameData.setFrameTimeNanos(frameTimeNanos);
}
}
}
@@ -842,7 +889,7 @@
+ ", action=" + c.action + ", token=" + c.token
+ ", latencyMillis=" + (SystemClock.uptimeMillis() - c.dueTime));
}
- c.run(frameTimeNanos);
+ c.run(frameData);
}
} finally {
synchronized (mLock) {
@@ -942,6 +989,130 @@
public void doFrame(long frameTimeNanos);
}
+ /** Holds data that describes one possible VSync frame event to render at. */
+ public static class FrameTimeline {
+ static final FrameTimeline INVALID_FRAME_TIMELINE = new FrameTimeline(
+ FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE);
+
+ FrameTimeline(long vsyncId, long expectedPresentTimeNanos, long deadlineNanos) {
+ this.mVsyncId = vsyncId;
+ this.mExpectedPresentTimeNanos = expectedPresentTimeNanos;
+ this.mDeadlineNanos = deadlineNanos;
+ }
+
+ private long mVsyncId;
+ private long mExpectedPresentTimeNanos;
+ private long mDeadlineNanos;
+
+ /**
+ * The id that corresponds to this frame timeline, used to correlate a frame
+ * produced by HWUI with the timeline data stored in Surface Flinger.
+ */
+ public long getVsyncId() {
+ return mVsyncId;
+ }
+
+ /** Sets the vsync ID. */
+ void resetVsyncId() {
+ mVsyncId = FrameInfo.INVALID_VSYNC_ID;
+ }
+
+ /**
+ * The time in {@link System#nanoTime()} timebase which this frame is expected to be
+ * presented.
+ */
+ public long getExpectedPresentTimeNanos() {
+ return mExpectedPresentTimeNanos;
+ }
+
+ /**
+ * The time in {@link System#nanoTime()} timebase which this frame needs to be ready by.
+ */
+ public long getDeadlineNanos() {
+ return mDeadlineNanos;
+ }
+ }
+
+ /**
+ * The payload for {@link ExtendedFrameCallback} which includes frame information such as when
+ * the frame started being rendered, and multiple possible frame timelines and their
+ * information including deadline and expected present time.
+ */
+ public static class FrameData {
+ static final FrameTimeline[] INVALID_FRAME_TIMELINES = new FrameTimeline[0];
+ FrameData() {
+ this.mFrameTimelines = INVALID_FRAME_TIMELINES;
+ this.mPreferredFrameTimeline = FrameTimeline.INVALID_FRAME_TIMELINE;
+ }
+
+ FrameData(long frameTimeNanos, DisplayEventReceiver.VsyncEventData vsyncEventData) {
+ FrameTimeline[] frameTimelines =
+ new FrameTimeline[vsyncEventData.frameTimelines.length];
+ for (int i = 0; i < vsyncEventData.frameTimelines.length; i++) {
+ DisplayEventReceiver.VsyncEventData.FrameTimeline frameTimeline =
+ vsyncEventData.frameTimelines[i];
+ frameTimelines[i] = new FrameTimeline(frameTimeline.vsyncId,
+ frameTimeline.expectedPresentTime, frameTimeline.deadline);
+ }
+ this.mFrameTimeNanos = frameTimeNanos;
+ this.mFrameTimelines = frameTimelines;
+ this.mPreferredFrameTimeline =
+ frameTimelines[vsyncEventData.preferredFrameTimelineIndex];
+ }
+
+ private long mFrameTimeNanos;
+ private final FrameTimeline[] mFrameTimelines;
+ private final FrameTimeline mPreferredFrameTimeline;
+
+ void setFrameTimeNanos(long frameTimeNanos) {
+ mFrameTimeNanos = frameTimeNanos;
+ for (FrameTimeline ft : mFrameTimelines) {
+ // The ID is no longer valid because the frame time that was registered with the ID
+ // no longer matches.
+ // TODO(b/205721584): Ask SF for valid vsync information.
+ ft.resetVsyncId();
+ }
+ }
+
+ /** The time in nanoseconds when the frame started being rendered. */
+ public long getFrameTimeNanos() {
+ return mFrameTimeNanos;
+ }
+
+ /** The possible frame timelines, sorted chronologically. */
+ @NonNull
+ @SuppressLint("ArrayReturn") // For API consistency and speed.
+ public FrameTimeline[] getFrameTimelines() {
+ return mFrameTimelines;
+ }
+
+ /** The platform-preferred frame timeline. */
+ @NonNull
+ public FrameTimeline getPreferredFrameTimeline() {
+ return mPreferredFrameTimeline;
+ }
+ }
+
+ /**
+ * Implement this interface to receive a callback to start the next frame. The callback is
+ * invoked on the {@link Looper} thread to which the {@link Choreographer} is attached. The
+ * callback payload contains information about multiple possible frames, allowing choice of
+ * the appropriate frame based on latency requirements.
+ *
+ * @see FrameCallback
+ */
+ public interface ExtendedFrameCallback {
+ /**
+ * Called when a new display frame is being rendered.
+ *
+ * @param data The payload which includes frame information. Divide nanosecond values by
+ * {@code 1000000} to convert it to the {@link SystemClock#uptimeMillis()}
+ * time base.
+ * @see FrameCallback#doFrame
+ **/
+ void onVsync(@NonNull FrameData data);
+ }
+
private final class FrameHandler extends Handler {
public FrameHandler(Looper looper) {
super(looper);
@@ -983,7 +1154,8 @@
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
- "Choreographer#onVsync " + vsyncEventData.id);
+ "Choreographer#onVsync "
+ + vsyncEventData.preferredFrameTimeline().vsyncId);
}
// Post the vsync event to the Handler.
// The idea is to prevent incoming vsync events from completely starving
@@ -1026,7 +1198,9 @@
private static final class CallbackRecord {
public CallbackRecord next;
public long dueTime;
- public Object action; // Runnable or FrameCallback
+ /** Runnable or FrameCallback or ExtendedFrameCallback object. */
+ public Object action;
+ /** Denotes the action type. */
public Object token;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1037,6 +1211,14 @@
((Runnable)action).run();
}
}
+
+ void run(FrameData frameData) {
+ if (token == EXTENDED_FRAME_CALLBACK_TOKEN) {
+ ((ExtendedFrameCallback) action).onVsync(frameData);
+ } else {
+ run(frameData.getFrameTimeNanos());
+ }
+ }
}
private final class CallbackQueue {
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/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index 5c08632..774bab4 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -138,13 +138,28 @@
}
static final class VsyncEventData {
- // The frame timeline vsync id, used to correlate a frame
- // produced by HWUI with the timeline data stored in Surface Flinger.
- public final long id;
- // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
- // allotted for the frame to be completed.
- public final long frameDeadline;
+ static final FrameTimeline[] INVALID_FRAME_TIMELINES =
+ {new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)};
+
+ public static class FrameTimeline {
+ FrameTimeline(long vsyncId, long expectedPresentTime, long deadline) {
+ this.vsyncId = vsyncId;
+ this.expectedPresentTime = expectedPresentTime;
+ this.deadline = deadline;
+ }
+
+ // The frame timeline vsync id, used to correlate a frame
+ // produced by HWUI with the timeline data stored in Surface Flinger.
+ public final long vsyncId;
+
+ // The frame timestamp for when the frame is expected to be presented.
+ public final long expectedPresentTime;
+
+ // The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
+ // allotted for the frame to be completed.
+ public final long deadline;
+ }
/**
* The current interval between frames in ns. This will be used to align
@@ -153,16 +168,27 @@
*/
public final long frameInterval;
- VsyncEventData(long id, long frameDeadline, long frameInterval) {
- this.id = id;
- this.frameDeadline = frameDeadline;
+ public final FrameTimeline[] frameTimelines;
+
+ public final int preferredFrameTimelineIndex;
+
+ // Called from native code.
+ @SuppressWarnings("unused")
+ VsyncEventData(FrameTimeline[] frameTimelines, int preferredFrameTimelineIndex,
+ long frameInterval) {
+ this.frameTimelines = frameTimelines;
+ this.preferredFrameTimelineIndex = preferredFrameTimelineIndex;
this.frameInterval = frameInterval;
}
VsyncEventData() {
- this.id = FrameInfo.INVALID_VSYNC_ID;
- this.frameDeadline = Long.MAX_VALUE;
this.frameInterval = -1;
+ this.frameTimelines = INVALID_FRAME_TIMELINES;
+ this.preferredFrameTimelineIndex = 0;
+ }
+
+ public FrameTimeline preferredFrameTimeline() {
+ return frameTimelines[preferredFrameTimelineIndex];
}
}
@@ -256,9 +282,8 @@
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
- long frameTimelineVsyncId, long frameDeadline, long frameInterval) {
- onVsync(timestampNanos, physicalDisplayId, frame,
- new VsyncEventData(frameTimelineVsyncId, frameDeadline, frameInterval));
+ VsyncEventData vsyncEventData) {
+ onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData);
}
// Called from native code.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9ce59bb..41a31e1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8663,15 +8663,34 @@
if (mAttachInfo == null) {
return;
}
-
RectF position = mAttachInfo.mTmpTransformRect;
- position.set(0, 0, mRight - mLeft, mBottom - mTop);
- mapRectFromViewToScreenCoords(position, clipToParent);
+ getBoundsToScreenInternal(position, clipToParent);
outRect.set(Math.round(position.left), Math.round(position.top),
Math.round(position.right), Math.round(position.bottom));
}
/**
+ * Gets the location of this view in screen coordinates.
+ *
+ * @param outRect The output location
+ * @param clipToParent Whether to clip child bounds to the parent ones.
+ * @hide
+ */
+ public void getBoundsOnScreen(RectF outRect, boolean clipToParent) {
+ if (mAttachInfo == null) {
+ return;
+ }
+ RectF position = mAttachInfo.mTmpTransformRect;
+ getBoundsToScreenInternal(position, clipToParent);
+ outRect.set(position.left, position.top, position.right, position.bottom);
+ }
+
+ private void getBoundsToScreenInternal(RectF position, boolean clipToParent) {
+ position.set(0, 0, mRight - mLeft, mBottom - mTop);
+ mapRectFromViewToScreenCoords(position, clipToParent);
+ }
+
+ /**
* Map a rectangle from view-relative coordinates to screen-relative coordinates
*
* @param rect The rectangle to be mapped
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 7a33507..e54ed18 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1766,6 +1766,74 @@
}
}
+ /**
+ * Sets the system audio caption enabled state.
+ *
+ * @param isEnabled The system audio captioning enabled state.
+ * @param userId The user Id.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
+ public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.setSystemAudioCaptioningRequested(isEnabled, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the system audio caption UI enabled state.
+ *
+ * @param userId The user Id.
+ * @return the system audio caption UI enabled state.
+ * @hide
+ */
+ public boolean isSystemAudioCaptioningUiRequested(int userId) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return false;
+ }
+ }
+ try {
+ return service.isSystemAudioCaptioningUiRequested(userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the system audio caption UI enabled state.
+ *
+ * @param isEnabled The system audio captioning UI enabled state.
+ * @param userId The user Id.
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
+ public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+ final IAccessibilityManager service;
+ synchronized (mLock) {
+ service = getServiceLocked();
+ if (service == null) {
+ return;
+ }
+ }
+ try {
+ service.setSystemAudioCaptioningUiRequested(isEnabled, userId);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
private IAccessibilityManager getServiceLocked() {
if (mService == null) {
tryConnectToServiceLocked(null);
diff --git a/core/java/android/view/accessibility/CaptioningManager.java b/core/java/android/view/accessibility/CaptioningManager.java
index 3f6a871..05c74f2 100644
--- a/core/java/android/view/accessibility/CaptioningManager.java
+++ b/core/java/android/view/accessibility/CaptioningManager.java
@@ -16,8 +16,11 @@
package android.view.accessibility;
+import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ContentResolver;
@@ -44,6 +47,7 @@
public class CaptioningManager {
/** Default captioning enabled value. */
private static final int DEFAULT_ENABLED = 0;
+ private static final boolean SYSTEM_AUDIO_CAPTIONING_DEFAULT_ENABLED = false;
/** Default style preset as an index into {@link CaptionStyle#PRESETS}. */
private static final int DEFAULT_PRESET = 0;
@@ -55,6 +59,8 @@
private final ContentResolver mContentResolver;
private final ContentObserver mContentObserver;
private final Resources mResources;
+ private final Context mContext;
+ private final AccessibilityManager mAccessibilityManager;
/**
* Creates a new captioning manager for the specified context.
@@ -62,7 +68,9 @@
* @hide
*/
public CaptioningManager(Context context) {
+ mContext = context;
mContentResolver = context.getContentResolver();
+ mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class);
final Handler handler = new Handler(context.getMainLooper());
mContentObserver = new MyContentObserver(handler);
@@ -142,6 +150,60 @@
}
/**
+ * @return the system audio caption enabled state.
+ */
+ public final boolean isSystemAudioCaptioningRequested() {
+ return Secure.getIntForUser(mContentResolver, Secure.ODI_CAPTIONS_ENABLED,
+ SYSTEM_AUDIO_CAPTIONING_DEFAULT_ENABLED ? 1 : 0, mContext.getUserId()) == 1;
+ }
+
+ /**
+ * Sets the system audio caption enabled state.
+ *
+ * @param isEnabled The system audio captioning enabled state.
+ *
+ * @throws SecurityException if the caller does not have permission
+ * {@link Manifest.permission#SET_SYSTEM_AUDIO_CAPTION}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
+ public final void setSystemAudioCaptioningRequested(boolean isEnabled) {
+ if (mAccessibilityManager != null) {
+ mAccessibilityManager.setSystemAudioCaptioningRequested(isEnabled,
+ mContext.getUserId());
+ }
+ }
+
+ /**
+ * @return the system audio caption UI enabled state.
+ */
+ public final boolean isSystemAudioCaptioningUiRequested() {
+ return mAccessibilityManager != null
+ && mAccessibilityManager.isSystemAudioCaptioningUiRequested(mContext.getUserId());
+ }
+
+ /**
+ * Sets the system audio caption UI enabled state.
+ *
+ * @param isEnabled The system audio captioning UI enabled state.
+ *
+ * @throws SecurityException if the caller does not have permission
+ * {@link Manifest.permission#SET_SYSTEM_AUDIO_CAPTION}
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
+ public final void setSystemAudioCaptioningUiRequested(boolean isEnabled) {
+ if (mAccessibilityManager != null) {
+ mAccessibilityManager.setSystemAudioCaptioningUiRequested(isEnabled,
+ mContext.getUserId());
+ }
+ }
+
+ /**
* Adds a listener for changes in the user's preferred captioning enabled
* state and visual properties.
*
@@ -160,6 +222,8 @@
registerObserver(Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE);
registerObserver(Secure.ACCESSIBILITY_CAPTIONING_LOCALE);
registerObserver(Secure.ACCESSIBILITY_CAPTIONING_PRESET);
+ registerObserver(Secure.ODI_CAPTIONS_ENABLED);
+ registerObserver(Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED);
}
mListeners.add(listener);
@@ -229,6 +293,24 @@
}
}
+ private void notifySystemAudioCaptionChanged() {
+ final boolean enabled = isSystemAudioCaptioningRequested();
+ synchronized (mListeners) {
+ for (CaptioningChangeListener listener : mListeners) {
+ listener.onSystemAudioCaptioningChanged(enabled);
+ }
+ }
+ }
+
+ private void notifySystemAudioCaptionUiChanged() {
+ final boolean enabled = isSystemAudioCaptioningUiRequested();
+ synchronized (mListeners) {
+ for (CaptioningChangeListener listener : mListeners) {
+ listener.onSystemAudioCaptioningUiChanged(enabled);
+ }
+ }
+ }
+
private class MyContentObserver extends ContentObserver {
private final Handler mHandler;
@@ -248,6 +330,10 @@
notifyLocaleChanged();
} else if (Secure.ACCESSIBILITY_CAPTIONING_FONT_SCALE.equals(name)) {
notifyFontScaleChanged();
+ } else if (Secure.ODI_CAPTIONS_ENABLED.equals(name)) {
+ notifySystemAudioCaptionChanged();
+ } else if (Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED.equals(name)) {
+ notifySystemAudioCaptionUiChanged();
} else {
// We only need a single callback when multiple style properties
// change in rapid succession.
@@ -565,5 +651,51 @@
* @see CaptioningManager#getFontScale()
*/
public void onFontScaleChanged(float fontScale) {}
+
+
+ /**
+ * Called when the system audio caption enabled state changes.
+ *
+ * @param enabled the system audio caption enabled state
+ */
+ public void onSystemAudioCaptioningChanged(boolean enabled) {}
+
+ /**
+ * Called when the system audio caption UI enabled state changes.
+ *
+ * @param enabled the system audio caption UI enabled state
+ */
+ public void onSystemAudioCaptioningUiChanged(boolean enabled) {}
+ }
+
+ /**
+ * Interface for accessing the system audio captioning related secure setting keys.
+ *
+ * @hide
+ */
+ public interface SystemAudioCaptioningAccessing {
+ /**
+ * Sets the system audio caption enabled state.
+ *
+ * @param isEnabled The system audio captioning enabled state.
+ * @param userId The user Id.
+ */
+ void setSystemAudioCaptioningRequested(boolean isEnabled, int userId);
+
+ /**
+ * Gets the system audio caption UI enabled state.
+ *
+ * @param userId The user Id.
+ * @return the system audio caption UI enabled state.
+ */
+ boolean isSystemAudioCaptioningUiRequested(int userId);
+
+ /**
+ * Sets the system audio caption UI enabled state.
+ *
+ * @param isEnabled The system audio captioning UI enabled state.
+ * @param userId The user Id.
+ */
+ void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId);
}
}
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 4e8d2da..645ddf5 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -100,4 +100,14 @@
int getFocusColor();
boolean isAudioDescriptionByDefaultEnabled();
+
+ // Requires Manifest.permission.SET_SYSTEM_AUDIO_CAPTION
+ // System process only
+ void setSystemAudioCaptioningRequested(boolean isEnabled, int userId);
+
+ boolean isSystemAudioCaptioningUiRequested(int userId);
+
+ // Requires Manifest.permission.SET_SYSTEM_AUDIO_CAPTION
+ // System process only
+ void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId);
}
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index b1d618e..ab749ee 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -209,6 +209,13 @@
private boolean mShowWallpaper;
private boolean mHasRoundedCorners;
+ /**
+ * Whether to show a background behind the windows during the animation.
+ * @see #getShowBackground()
+ * @see #setShowBackground(boolean)
+ */
+ private boolean mShowBackground;
+
private boolean mMore = true;
private boolean mOneMoreTime = true;
@@ -266,6 +273,8 @@
a.getBoolean(com.android.internal.R.styleable.Animation_showWallpaper, false));
setHasRoundedCorners(
a.getBoolean(com.android.internal.R.styleable.Animation_hasRoundedCorners, false));
+ setShowBackground(
+ a.getBoolean(com.android.internal.R.styleable.Animation_showBackground, false));
final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
@@ -698,6 +707,24 @@
}
/**
+ * If showBackground is {@code true} and this animation is applied on a window, then the windows
+ * in the animation will animate with the background associated with this window behind them.
+ *
+ * The background comes from the {@link android.R.styleable#Theme_colorBackground} that is
+ * applied to this window through its theme.
+ *
+ * If multiple animating windows have showBackground set to {@code true} during an animation,
+ * the top most window with showBackground set to {@code true} and a valid background color
+ * takes precedence.
+ *
+ * @param showBackground Whether to show a background behind the windows during the animation.
+ * @attr ref android.R.styleable#Animation_showBackground
+ */
+ public void setShowBackground(boolean showBackground) {
+ mShowBackground = showBackground;
+ }
+
+ /**
* Gets the acceleration curve type for this animation.
*
* @return the {@link Interpolator} associated to this animation
@@ -838,6 +865,24 @@
}
/**
+ * If showBackground is {@code true} and this animation is applied on a window, then the windows
+ * in the animation will animate with the background associated with this window behind them.
+ *
+ * The background comes from the {@link android.R.styleable#Theme_colorBackground} that is
+ * applied to this window through its theme.
+ *
+ * If multiple animating windows have showBackground set to {@code true} during an animation,
+ * the top most window with showBackground set to {@code true} and a valid background color
+ * takes precedence.
+ *
+ * @return if the background of this window should be shown behind the animating windows.
+ * @attr ref android.R.styleable#Animation_showBackground
+ */
+ public boolean getShowBackground() {
+ return mShowBackground;
+ }
+
+ /**
* <p>Indicates whether or not this animation will affect the transformation
* matrix. For instance, a fade animation will not affect the matrix whereas
* a scale animation will.</p>
diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java
index fbc9470..e3d3bfd 100644
--- a/core/java/android/view/inputmethod/CursorAnchorInfo.java
+++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java
@@ -105,6 +105,13 @@
private final SparseRectFArray mCharacterBoundsArray;
/**
+ * Container of rectangular position of Editor in the local coordinates that will be transformed
+ * with the transformation matrix when rendered on the screen.
+ * @see {@link EditorBoundsInfo}.
+ */
+ private final EditorBoundsInfo mEditorBoundsInfo;
+
+ /**
* Transformation matrix that is applied to any positional information of this class to
* transform local coordinates into screen coordinates.
*/
@@ -141,6 +148,7 @@
mInsertionMarkerBaseline = source.readFloat();
mInsertionMarkerBottom = source.readFloat();
mCharacterBoundsArray = source.readParcelable(SparseRectFArray.class.getClassLoader());
+ mEditorBoundsInfo = source.readTypedObject(EditorBoundsInfo.CREATOR);
mMatrixValues = source.createFloatArray();
}
@@ -163,6 +171,7 @@
dest.writeFloat(mInsertionMarkerBaseline);
dest.writeFloat(mInsertionMarkerBottom);
dest.writeParcelable(mCharacterBoundsArray, flags);
+ dest.writeTypedObject(mEditorBoundsInfo, flags);
dest.writeFloatArray(mMatrixValues);
}
@@ -216,6 +225,10 @@
return false;
}
+ if (!Objects.equals(mEditorBoundsInfo, that.mEditorBoundsInfo)) {
+ return false;
+ }
+
// Following fields are (partially) covered by hashCode().
if (mComposingTextStart != that.mComposingTextStart
@@ -248,6 +261,7 @@
+ " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline
+ " mInsertionMarkerBottom=" + mInsertionMarkerBottom
+ " mCharacterBoundsArray=" + Objects.toString(mCharacterBoundsArray)
+ + " mEditorBoundsInfo=" + mEditorBoundsInfo
+ " mMatrix=" + Arrays.toString(mMatrixValues)
+ "}";
}
@@ -266,6 +280,7 @@
private float mInsertionMarkerBottom = Float.NaN;
private int mInsertionMarkerFlags = 0;
private SparseRectFArrayBuilder mCharacterBoundsArrayBuilder = null;
+ private EditorBoundsInfo mEditorBoundsInfo = null;
private float[] mMatrixValues = null;
private boolean mMatrixInitialized = false;
@@ -356,6 +371,17 @@
}
/**
+ * Sets the current editor related bounds.
+ *
+ * @param bounds {@link EditorBoundsInfo} in local coordinates.
+ */
+ @NonNull
+ public Builder setEditorBoundsInfo(@Nullable EditorBoundsInfo bounds) {
+ mEditorBoundsInfo = bounds;
+ return this;
+ }
+
+ /**
* Sets the matrix that transforms local coordinates into screen coordinates.
* @param matrix transformation matrix from local coordinates into screen coordinates. null
* is interpreted as an identity matrix.
@@ -410,6 +436,7 @@
if (mCharacterBoundsArrayBuilder != null) {
mCharacterBoundsArrayBuilder.reset();
}
+ mEditorBoundsInfo = null;
}
}
@@ -425,6 +452,7 @@
mInsertionMarkerBottom = builder.mInsertionMarkerBottom;
mCharacterBoundsArray = builder.mCharacterBoundsArrayBuilder != null
? builder.mCharacterBoundsArrayBuilder.build() : null;
+ mEditorBoundsInfo = builder.mEditorBoundsInfo;
mMatrixValues = new float[9];
if (builder.mMatrixInitialized) {
System.arraycopy(builder.mMatrixValues, 0, mMatrixValues, 0, 9);
@@ -547,6 +575,14 @@
}
/**
+ * Returns {@link EditorBoundsInfo} editor related bounds.
+ */
+ @Nullable
+ public EditorBoundsInfo getEditorBoundsInfo() {
+ return mEditorBoundsInfo;
+ }
+
+ /**
* Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation
* matrix that is to be applied other positional data in this class.
* @return a new instance (copy) of the transformation matrix.
diff --git a/core/java/android/view/inputmethod/EditorBoundsInfo.java b/core/java/android/view/inputmethod/EditorBoundsInfo.java
new file mode 100644
index 0000000..081dc81
--- /dev/null
+++ b/core/java/android/view/inputmethod/EditorBoundsInfo.java
@@ -0,0 +1,177 @@
+/*
+ * 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.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.RectF;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Container of rectangular position related info for the Editor.
+ */
+public final class EditorBoundsInfo implements Parcelable {
+
+ /**
+ * Container of rectangular position of Editor in the current window.
+ */
+ private final RectF mEditorBounds;
+
+ /**
+ * Container of rectangular position of Editor with additional padding around for initiating
+ * Stylus Handwriting in the current window.
+ */
+ private final RectF mHandwritingBounds;
+
+ private final int mHashCode;
+
+ private EditorBoundsInfo(@NonNull Parcel source) {
+ mHashCode = source.readInt();
+ mEditorBounds = source.readTypedObject(RectF.CREATOR);
+ mHandwritingBounds = source.readTypedObject(RectF.CREATOR);
+ }
+
+ /**
+ * Returns the bounds of the Editor in local coordinates.
+ *
+ * Screen coordinates can be obtained by transforming with the
+ * {@link CursorAnchorInfo#getMatrix} of the containing {@code CursorAnchorInfo}.
+ */
+ @Nullable
+ public RectF getEditorBounds() {
+ return mEditorBounds;
+ }
+
+ /**
+ * Returns the bounds of the area that should be considered for initiating stylus handwriting
+ * in local coordinates.
+ *
+ * Screen coordinates can be obtained by transforming with the
+ * {@link CursorAnchorInfo#getMatrix} of the containing {@code CursorAnchorInfo}.
+ */
+ @Nullable
+ public RectF getHandwritingBounds() {
+ return mHandwritingBounds;
+ }
+
+ @Override
+ public int hashCode() {
+ return mHashCode;
+ }
+
+ @Override
+ public String toString() {
+ return "EditorBoundsInfo{mEditorBounds=" + mEditorBounds
+ + " mHandwritingBounds=" + mHandwritingBounds
+ + "}";
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (obj == null) {
+ return false;
+ }
+ EditorBoundsInfo bounds;
+ if (obj instanceof EditorBoundsInfo) {
+ bounds = (EditorBoundsInfo) obj;
+ } else {
+ return false;
+ }
+ return Objects.equals(bounds.mEditorBounds, mEditorBounds)
+ && Objects.equals(bounds.mHandwritingBounds, mHandwritingBounds);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mHashCode);
+ dest.writeTypedObject(mEditorBounds, flags);
+ dest.writeTypedObject(mHandwritingBounds, flags);
+ }
+
+ /**
+ * Used to make this class parcelable.
+ */
+ public static final @android.annotation.NonNull Parcelable.Creator<EditorBoundsInfo> CREATOR
+ = new Parcelable.Creator<EditorBoundsInfo>() {
+ @Override
+ public EditorBoundsInfo createFromParcel(@NonNull Parcel source) {
+ return new EditorBoundsInfo(source);
+ }
+
+ @Override
+ public EditorBoundsInfo[] newArray(int size) {
+ return new EditorBoundsInfo[size];
+ }
+ };
+
+ /**
+ * Builder for {@link CursorAnchorInfo}.
+ */
+ public static final class Builder {
+ private RectF mEditorBounds = null;
+ private RectF mHandwritingBounds = null;
+
+ /**
+ * Sets the bounding box of the current editor.
+ *
+ * @param bounds {@link RectF} in local coordinates.
+ */
+ @NonNull
+ public EditorBoundsInfo.Builder setEditorBounds(@Nullable RectF bounds) {
+ mEditorBounds = bounds;
+ return this;
+ }
+
+ /**
+ * Sets the current editor's bounds with padding for handwriting.
+ *
+ * @param bounds {@link RectF} in local coordinates.
+ */
+ @NonNull
+ public EditorBoundsInfo.Builder setHandwritingBounds(@Nullable RectF bounds) {
+ mHandwritingBounds = bounds;
+ return this;
+ }
+
+ /**
+ * Returns {@link EditorBoundsInfo} using parameters in this
+ * {@link EditorBoundsInfo.Builder}.
+ */
+ @NonNull
+ public EditorBoundsInfo build() {
+ return new EditorBoundsInfo(this);
+ }
+ }
+
+ private EditorBoundsInfo(final EditorBoundsInfo.Builder builder) {
+ mEditorBounds = builder.mEditorBounds;
+ mHandwritingBounds = builder.mHandwritingBounds;
+
+ int hash = Objects.hashCode(mEditorBounds);
+ hash *= 31;
+ hash += Objects.hashCode(mHandwritingBounds);
+ mHashCode = hash;
+ }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 414a7f1..1d8e9a3 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2656,6 +2656,27 @@
}
}
+ /**
+ * Returns whether the selected child view (from the adapter's getView) is enabled.
+ *
+ * @return true if enabled
+ */
+ public boolean isSelectedChildViewEnabled() {
+ return mIsChildViewEnabled;
+ }
+
+ /**
+ * Set whether the selected child view (from the adapter's getView) is enabled.
+ *
+ * When refreshDrawableState is called, AbsListView will control the "enabled" state
+ * of the selector based on this.
+ *
+ * @param selectedChildViewEnabled true if enabled
+ */
+ public void setSelectedChildViewEnabled(boolean selectedChildViewEnabled) {
+ mIsChildViewEnabled = selectedChildViewEnabled;
+ }
+
@Override
protected void dispatchDraw(Canvas canvas) {
int saveCount = 0;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 6284bc2..ac28c31 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -115,6 +115,7 @@
import android.view.animation.LinearInterpolator;
import android.view.inputmethod.CorrectionInfo;
import android.view.inputmethod.CursorAnchorInfo;
+import android.view.inputmethod.EditorBoundsInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
@@ -4570,6 +4571,12 @@
mTextView.getLocationOnScreen(mTmpIntOffset);
mViewToScreenMatrix.postTranslate(mTmpIntOffset[0], mTmpIntOffset[1]);
builder.setMatrix(mViewToScreenMatrix);
+ final RectF bounds = new RectF();
+ mTextView.getBoundsOnScreen(bounds, false /* clipToParent */);
+ EditorBoundsInfo.Builder boundsBuilder = new EditorBoundsInfo.Builder();
+ //TODO(b/210039666): add Handwriting bounds once they're available.
+ builder.setEditorBoundsInfo(
+ boundsBuilder.setEditorBounds(bounds).build());
final float viewportToContentHorizontalOffset =
mTextView.viewportToContentHorizontalOffset();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1a808b2..0fe06be 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -79,6 +79,7 @@
import android.graphics.drawable.Drawable;
import android.graphics.fonts.FontStyle;
import android.graphics.fonts.FontVariationAxis;
+import android.graphics.text.LineBreakConfig;
import android.icu.text.DecimalFormatSymbols;
import android.os.AsyncTask;
import android.os.Build;
@@ -348,6 +349,7 @@
* @attr ref android.R.styleable#TextView_fontVariationSettings
* @attr ref android.R.styleable#TextView_breakStrategy
* @attr ref android.R.styleable#TextView_hyphenationFrequency
+ * @attr ref android.R.styleable#TextView_lineBreakStyle
* @attr ref android.R.styleable#TextView_autoSizeTextType
* @attr ref android.R.styleable#TextView_autoSizeMinTextSize
* @attr ref android.R.styleable#TextView_autoSizeMaxTextSize
@@ -775,6 +777,7 @@
private Layout mLayout;
private boolean mLocalesChanged = false;
private int mTextSizeUnit = -1;
+ private LineBreakConfig mLineBreakConfig = new LineBreakConfig();
// This is used to reflect the current user preference for changing font weight and making text
// more bold.
@@ -1442,6 +1445,11 @@
mHyphenationFrequency = a.getInt(attr, Layout.HYPHENATION_FREQUENCY_NONE);
break;
+ case com.android.internal.R.styleable.TextView_lineBreakStyle:
+ mLineBreakConfig.setLineBreakStyle(
+ a.getInt(attr, LineBreakConfig.LINE_BREAK_STYLE_NONE));
+ break;
+
case com.android.internal.R.styleable.TextView_autoSizeTextType:
mAutoSizeTextType = a.getInt(attr, AUTO_SIZE_TEXT_TYPE_NONE);
break;
@@ -4788,13 +4796,50 @@
}
/**
+ * Sets line break configuration indicates which strategy needs to be used when calculating the
+ * text wrapping. There are thee strategies for the line break style(lb):
+ * {@link LineBreakConfig#LINE_BREAK_STYLE_LOOSE},
+ * {@link LineBreakConfig#LINE_BREAK_STYLE_NORMAL} and
+ * {@link LineBreakConfig#LINE_BREAK_STYLE_STRICT}.
+ * The default value of the line break style is {@link LineBreakConfig#LINE_BREAK_STYLE_NONE},
+ * which means no line break style is specified.
+ * See <a href="https://drafts.csswg.org/css-text/#line-break-property">
+ * the line-break property</a>
+ *
+ * @param lineBreakConfig the line break config for text wrapping.
+ */
+ public void setLineBreakConfig(@NonNull LineBreakConfig lineBreakConfig) {
+ if (mLineBreakConfig.equals(lineBreakConfig)) {
+ return;
+ }
+ mLineBreakConfig.set(lineBreakConfig);
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
+ * Get the current line break configuration for text wrapping.
+ *
+ * @return the current line break configuration to be used for text wrapping.
+ */
+ public @NonNull LineBreakConfig getLineBreakConfig() {
+ LineBreakConfig lbConfig = new LineBreakConfig();
+ lbConfig.set(mLineBreakConfig);
+ return lbConfig;
+ }
+
+ /**
* Gets the parameters for text layout precomputation, for use with {@link PrecomputedText}.
*
* @return a current {@link PrecomputedText.Params}
* @see PrecomputedText
*/
public @NonNull PrecomputedText.Params getTextMetricsParams() {
- return new PrecomputedText.Params(new TextPaint(mTextPaint), getTextDirectionHeuristic(),
+ return new PrecomputedText.Params(new TextPaint(mTextPaint), mLineBreakConfig,
+ getTextDirectionHeuristic(),
mBreakStrategy, mHyphenationFrequency);
}
@@ -4810,6 +4855,7 @@
mTextDir = params.getTextDirection();
mBreakStrategy = params.getBreakStrategy();
mHyphenationFrequency = params.getHyphenationFrequency();
+ mLineBreakConfig.set(params.getLineBreakConfig());
if (mLayout != null) {
nullLayouts();
requestLayout();
@@ -6348,7 +6394,7 @@
}
final @PrecomputedText.Params.CheckResultUsableResult int checkResult =
precomputed.getParams().checkResultUsable(getPaint(), mTextDir, mBreakStrategy,
- mHyphenationFrequency);
+ mHyphenationFrequency, mLineBreakConfig);
switch (checkResult) {
case PrecomputedText.Params.UNUSABLE:
throw new IllegalArgumentException(
@@ -9244,7 +9290,8 @@
.setBreakStrategy(mBreakStrategy)
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
- .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+ .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
+ .setLineBreakConfig(mLineBreakConfig);
if (shouldEllipsize) {
builder.setEllipsize(mEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -9358,7 +9405,8 @@
.setBreakStrategy(mBreakStrategy)
.setHyphenationFrequency(mHyphenationFrequency)
.setJustificationMode(mJustificationMode)
- .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE);
+ .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
+ .setLineBreakConfig(mLineBreakConfig);
if (shouldEllipsize) {
builder.setEllipsize(effectiveEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -9725,7 +9773,8 @@
.setHyphenationFrequency(getHyphenationFrequency())
.setJustificationMode(getJustificationMode())
.setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
- .setTextDirection(getTextDirectionHeuristic());
+ .setTextDirection(getTextDirectionHeuristic())
+ .setLineBreakConfig(mLineBreakConfig);
final StaticLayout layout = layoutBuilder.build();
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index 915c8fb..fd1e848 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -36,6 +36,7 @@
import static android.view.WindowManager.TransitionType;
import static android.view.WindowManager.transitTypeToString;
+import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -366,6 +367,7 @@
private int mStartRotation = ROTATION_UNDEFINED;
private int mEndRotation = ROTATION_UNDEFINED;
private int mRotationAnimation = ROTATION_ANIMATION_UNSPECIFIED;
+ private @ColorInt int mBackgroundColor;
public Change(@Nullable WindowContainerToken container, @NonNull SurfaceControl leash) {
mContainer = container;
@@ -387,6 +389,7 @@
mStartRotation = in.readInt();
mEndRotation = in.readInt();
mRotationAnimation = in.readInt();
+ mBackgroundColor = in.readInt();
}
/** Sets the parent of this change's container. The parent must be a participant or null. */
@@ -446,6 +449,11 @@
mRotationAnimation = anim;
}
+ /** Sets the background color of this change's container. */
+ public void setBackgroundColor(@ColorInt int backgroundColor) {
+ mBackgroundColor = backgroundColor;
+ }
+
/** @return the container that is changing. May be null if non-remotable (eg. activity) */
@Nullable
public WindowContainerToken getContainer() {
@@ -526,6 +534,12 @@
return mRotationAnimation;
}
+ /** @return get the background color of this change's container. */
+ @ColorInt
+ public int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
/** @hide */
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -542,6 +556,7 @@
dest.writeInt(mStartRotation);
dest.writeInt(mEndRotation);
dest.writeInt(mRotationAnimation);
+ dest.writeInt(mBackgroundColor);
}
@NonNull
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index 29b31d3..b786526 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackagePartitions;
-import android.content.pm.parsing.ParsingPackageRead;
import android.os.Build;
import android.os.Trace;
import android.util.ArrayMap;
@@ -82,7 +81,22 @@
public interface PackageProvider {
/** Performs the given action for each package. */
- void forEachPackage(TriConsumer<ParsingPackageRead, Boolean, File> p);
+ void forEachPackage(TriConsumer<Package, Boolean, File> p);
+
+ interface Package {
+
+ String getBaseApkPath();
+
+ int getOverlayPriority();
+
+ String getOverlayTarget();
+
+ String getPackageName();
+
+ int getTargetSdkVersion();
+
+ boolean isOverlayIsStatic();
+ }
}
private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> {
@@ -304,7 +318,7 @@
private static Map<String, ParsedOverlayInfo> getOverlayPackageInfos(
@NonNull PackageProvider packageManager) {
final HashMap<String, ParsedOverlayInfo> overlays = new HashMap<>();
- packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem,
+ packageManager.forEachPackage((PackageProvider.Package p, Boolean isSystem,
@Nullable File preInstalledApexPath) -> {
if (p.getOverlayTarget() != null && isSystem) {
overlays.put(p.getPackageName(), new ParsedOverlayInfo(p.getPackageName(),
diff --git a/core/java/com/android/internal/content/om/OverlayScanner.java b/core/java/com/android/internal/content/om/OverlayScanner.java
index e4e0228..0fafd10 100644
--- a/core/java/com/android/internal/content/om/OverlayScanner.java
+++ b/core/java/com/android/internal/content/om/OverlayScanner.java
@@ -16,15 +16,13 @@
package com.android.internal.content.om;
-import static android.content.pm.parsing.ParsingPackageUtils.PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY;
-import static android.content.pm.parsing.ParsingPackageUtils.checkRequiredSystemProperties;
-
import static com.android.internal.content.om.OverlayConfig.TAG;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.parsing.ApkLite;
import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.text.TextUtils;
@@ -183,7 +181,8 @@
List<Pair<String, File>> outExcludedOverlayPackages) {
final ParseTypeImpl input = ParseTypeImpl.forParsingWithoutPlatformCompat();
final ParseResult<ApkLite> ret = ApkLiteParseUtils.parseApkLite(input.reset(),
- overlayApk, PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY);
+ overlayApk,
+ FrameworkParsingPackageUtils.PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY);
if (ret.isError()) {
Log.w(TAG, "Got exception loading overlay.", ret.getException());
return null;
@@ -196,7 +195,8 @@
final String propName = apkLite.getRequiredSystemPropertyName();
final String propValue = apkLite.getRequiredSystemPropertyValue();
if ((!TextUtils.isEmpty(propName) || !TextUtils.isEmpty(propValue))
- && !checkRequiredSystemProperties(propName, propValue)) {
+ && !FrameworkParsingPackageUtils.checkRequiredSystemProperties(propName,
+ propValue)) {
// The overlay package should be excluded. Adds it into the outExcludedOverlayPackages
// for overlay configuration parser to ignore it.
outExcludedOverlayPackages.add(Pair.create(apkLite.getPackageName(), overlayApk));
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9429c79..a4183ca 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/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index ce772cf..d91d526 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -48,6 +48,16 @@
jmethodID init;
} frameRateOverrideClassInfo;
+ struct {
+ jclass clazz;
+ jmethodID init;
+ } frameTimelineClassInfo;
+
+ struct {
+ jclass clazz;
+ jmethodID init;
+ } vsyncEventDataClassInfo;
+
} gDisplayEventReceiverClassInfo;
@@ -105,9 +115,38 @@
ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
if (receiverObj.get()) {
ALOGV("receiver %p ~ Invoking vsync handler.", this);
+
+ ScopedLocalRef<jobjectArray>
+ frameTimelineObjs(env,
+ env->NewObjectArray(vsyncEventData.frameTimelines.size(),
+ gDisplayEventReceiverClassInfo
+ .frameTimelineClassInfo.clazz,
+ /*initial element*/ NULL));
+ for (int i = 0; i < vsyncEventData.frameTimelines.size(); i++) {
+ VsyncEventData::FrameTimeline frameTimeline = vsyncEventData.frameTimelines[i];
+ ScopedLocalRef<jobject>
+ frameTimelineObj(env,
+ env->NewObject(gDisplayEventReceiverClassInfo
+ .frameTimelineClassInfo.clazz,
+ gDisplayEventReceiverClassInfo
+ .frameTimelineClassInfo.init,
+ frameTimeline.id,
+ frameTimeline.expectedPresentTime,
+ frameTimeline.deadlineTimestamp));
+ env->SetObjectArrayElement(frameTimelineObjs.get(), i, frameTimelineObj.get());
+ }
+ ScopedLocalRef<jobject>
+ vsyncEventDataJava(env,
+ env->NewObject(gDisplayEventReceiverClassInfo
+ .vsyncEventDataClassInfo.clazz,
+ gDisplayEventReceiverClassInfo
+ .vsyncEventDataClassInfo.init,
+ frameTimelineObjs.get(),
+ vsyncEventData.preferredFrameTimelineIndex,
+ vsyncEventData.frameInterval));
+
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
- timestamp, displayId.value, count, vsyncEventData.id,
- vsyncEventData.deadlineTimestamp, vsyncEventData.frameInterval);
+ timestamp, displayId.value, count, vsyncEventDataJava.get());
ALOGV("receiver %p ~ Returned from vsync handler.", this);
}
@@ -239,7 +278,7 @@
gDisplayEventReceiverClassInfo.dispatchVsync =
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync",
- "(JJIJJJ)V");
+ "(JJILandroid/view/DisplayEventReceiver$VsyncEventData;)V");
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
gDisplayEventReceiverClassInfo.dispatchModeChanged =
@@ -258,6 +297,24 @@
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameRateOverrideClassInfo.clazz,
"<init>", "(IF)V");
+ jclass frameTimelineClazz =
+ FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData$FrameTimeline");
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz =
+ MakeGlobalRefOrDie(env, frameTimelineClazz);
+ gDisplayEventReceiverClassInfo.frameTimelineClassInfo.init =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
+ "<init>", "(JJJ)V");
+
+ jclass vsyncEventDataClazz =
+ FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData");
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz =
+ MakeGlobalRefOrDie(env, vsyncEventDataClazz);
+ gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.init =
+ GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
+ "<init>",
+ "([Landroid/view/"
+ "DisplayEventReceiver$VsyncEventData$FrameTimeline;IJ)V");
+
return res;
}
diff --git a/core/res/Android.bp b/core/res/Android.bp
index 6063062..c42517d 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -37,7 +37,6 @@
visibility: [":__subpackages__"],
license_kinds: [
"SPDX-license-identifier-Apache-2.0",
- "SPDX-license-identifier-GPL",
],
license_text: [
"NOTICE",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d6bbe71..ae2052b 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 -->
@@ -3830,6 +3831,13 @@
<permission android:name="android.permission.GET_TOP_ACTIVITY_INFO"
android:protectionLevel="signature|recents" />
+ <!-- @SystemApi Allows an application to set the system audio caption and its UI
+ enabled state.
+ <p>Not for use by third-party applications.
+ @hide -->
+ <permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION"
+ android:protectionLevel="signature|role" />
+
<!-- Allows an application to retrieve the current state of keys and
switches.
<p>Not for use by third-party applications.
@@ -5602,13 +5610,6 @@
<permission android:name="android.permission.VIEW_INSTANT_APPS"
android:protectionLevel="signature|preinstalled" />
- <!-- Allows an application to interact with the currently active
- {@link com.android.server.communal.CommunalManagerService}.
- @hide
- @TestApi -->
- <permission android:name="android.permission.WRITE_COMMUNAL_STATE"
- android:protectionLevel="signature" />
-
<!-- Allows the holder to manage whether the system can bind to services
provided by instant apps. This permission is intended to protect
test/development fucntionality and should be used only in such cases.
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 74ac680..3bc0283 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Laat die program toe om Moenie Steur Nie-opstelling te lees en skryf."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"begin kyk van toestemminggebruik"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Laat die houer toe om die toestemminggebruik vir \'n program te begin. Behoort nooit vir normale programme nodig te wees nie."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"begin Bekyk Toestemmingbesluite"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Laat die houer toe om skerm te begin om toestemmingbesluite na te gaan. Behoort nooit vir normale programme nodig te wees nie."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"begin Bekyk Programkenmerke"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Laat die houer toe om die kenmerke-inligting vir \'n program te begin bekyk."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"kry toegang tot sensordata teen \'n hoë monsternemingkoers"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 3f5b5e0..fb52e6a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"መተግበሪያው የአትረብሽ ውቅረትን እንዲያነብብ እና እንዲጸፍ ይፈቅዳል።"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"የእይታ ፈቃድ መጠቀምን መጀመር"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ያዢው ለአንድ መተግበሪያ የፈቃድ አጠቃቀሙን እንዲያስጀምር ያስችለዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"የእይታ ፈቃድ ውሳኔዎችን ይጀምሩ"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ያዢው የፈቃድ ውሳኔዎችን ለመገምገም ማያ ገጽ እንዲጀምሩ ያስችላቸዋል። ለመደበኛ መተግበሪያዎች በጭራሽ ሊያስፈልግ አይገባም።"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"የመተግበሪያ ባህሪያትን ማየት መጀመር"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ያዢው የአንድ መተግበሪያ የባህሪያት መረጃን ማየት እንዲጀምር ያስችለዋል።"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"የዳሳሽ ውሂቡን በከፍተኛ የናሙና ብዛት ላይ ይድረሱበት"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 9dc59c0..12d1b83 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -745,10 +745,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"للسماح للتطبيق بقراءة إعداد \"عدم الإزعاج\" وكتابتها."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"بدء استخدام إذن العرض"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"للسماح للمالك ببدء استخدام الإذن لأحد التطبيقات. ولن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"بدء اتخاذ القرارات المتعلقة بالإذن بعرض البيانات"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"يمكنك السماح للمالك ببدء الشاشة لمراجعة القرارات المتعلقة بالأذونات. لا حاجة لذلك مع التطبيقات العادية."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"بدء عرض ميزات التطبيق"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"للسماح للمالك ببدء عرض معلومات عن ميزات التطبيق."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"الوصول إلى بيانات جهاز الاستشعار بمعدّل مرتفع للبيانات في الملف الصوتي"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index bd2b97d..f57e42b 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"অসুবিধা নিদিবৰ কনফিগাৰেশ্বনক পঢ়িবলৈ আৰু সালসলনি কৰিবলৈ এপটোক অনুমতি দিয়ে।"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"চোৱাৰ অনুমতিৰ ব্যৱহাৰ আৰম্ভ কৰক"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ধাৰকক কোনো এপৰ বাবে অনুমতিৰ ব্যৱহাৰ আৰম্ভ কৰিবলৈ দিয়ে। সাধাৰণ এপ্সমূহৰ বাবে কেতিয়াও প্ৰয়োজন হ’ব নালাগে।"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"অনুমতিৰ সিদ্ধান্তসমূহ চোৱা আৰম্ভ কৰক"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ধাৰকক অনুমতিৰ সিদ্ধান্তসমূহ পৰ্যালোচনা কৰিবলৈ স্ক্ৰীন আৰম্ভ কৰিবলৈ দিয়ে। সাধাৰণ এপ্সমূহৰ বাবে কেতিয়াও প্ৰয়োজন হ’ব নালাগে।"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"এপৰ সুবিধাসমূহৰ সম্পর্কীয় তথ্য চোৱাটো আৰম্ভ কৰক"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ধাৰকক কোনো এপৰ সুবিধাসমূহৰ সম্পর্কীয় তথ্য চোৱাটো আৰম্ভ কৰিবলৈ দিয়ে।"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"এটা উচ্চ ছেম্পলিঙৰ হাৰত ছেন্সৰৰ ডেটা এক্সেছ কৰে"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 3b0c6c8..76384f9 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Tətbiqə \"Narahat Etməyin\" konfiqurasiyasını oxumağa və yazmağa icazə verin."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"Baxış icazəsinin istifadəsinə başlayın"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Sahibinə tətbiqin icazədən istifadəsinə başlamağa imkan verir. Adi tətbiqlər üçün heç vaxt tələb edilmir."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"icazə qərarlarına baxışı başladın"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Sahibin icazə qərarlarını nəzərdən keçirmək üçün ekranı başlatmasına icazə verir. Normal tətbiqlər tərəfindən heç vaxt tələb edilmir."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"tətbiqin funksiyalarını görməyə başlamaq"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"İstifadəçinin tətbiqin funksiyaları barədə məlumatları görməyə başlamasına icazə verir."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"sensor datasına yüksək ölçmə sürəti ilə giriş etmək"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 96f8d7d..15e3aa0 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -736,10 +736,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Dozvoljava aplikaciji da čita i upisuje konfiguraciju podešavanja Ne uznemiravaj."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"početak korišćenja dozvole za pregled"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Dozvoljava vlasniku da započne korišćenje dozvole za aplikaciju. Nikada ne bi trebalo da bude potrebna za uobičajene aplikacije."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"pokretanje pregleda odluka o dozvolama"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Dozvoljava vlasniku da pokrene ekran za proveru odluka o dozvolama. Nikada ne bi trebalo da bude potrebno za obične aplikacije."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"pokretanje prikaza funkcija aplikacije"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Dozvoljava nosiocu dozvole da započne pregledanje informacija o funkcijama aplikacije."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pristup podacima senzora pri velikoj brzini uzorkovanja"</string>
@@ -1552,7 +1550,7 @@
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"Veza sa uvek uključenim VPN-om je prekinuta"</string>
<string name="vpn_lockdown_error" msgid="4453048646854247947">"Povezivanje na stalno uključeni VPN nije uspelo"</string>
<string name="vpn_lockdown_config" msgid="8331697329868252169">"Promenite podešavanja VPN-a"</string>
- <string name="upload_file" msgid="8651942222301634271">"Odaberi datoteku"</string>
+ <string name="upload_file" msgid="8651942222301634271">"Odaberi fajl"</string>
<string name="no_file_chosen" msgid="4146295695162318057">"Nije izabrana nijedna datoteka"</string>
<string name="reset" msgid="3865826612628171429">"Resetuj"</string>
<string name="submit" msgid="862795280643405865">"Pošalji"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index b444499..e182c28 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -739,10 +739,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Дазваляе праграме чытаць і выконваць запіс у канфігурацыю рэжыму «Не турбаваць»."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"запусціць выкарыстанне дазволаў на прагляд"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Дазваляе трымальніку запусціць выкарыстанне дазволаў праграмай. Не патрэбна для звычайных праграм."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"запускаць прагляд рашэнняў наконт дазволаў"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Дазваляе ўладальніку запускаць экран, на якім можна праглядаць рашэнні наконт дазволаў. Ніколі не павінна патрабавацца для звычайных праграм."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"запусціць прагляд функцый праграмы"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Дазваляе трымальніку запусціць прагляд інфармацыі пра функцыі для праграмы."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"атрымліваць даныя датчыка з высокай частатой дыскрэтызацыі"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index c3d8410..41aa9f7 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Предоставя на приложението достъп за четене и запис до конфигурацията на „Не безпокойте“."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"стартиране на прегледа на използваните разрешения"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Разрешава на притежателя да стартира прегледа на използваните разрешения за дадено приложение. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"стартиране на прегледа на решенията за разрешенията"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Дава възможност на притежателя да стартира екрана с цел преглед на решенията за разрешенията. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"стартиране на прегледа на функциите на приложението"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Разрешава на притежателя да стартира прегледа на информацията за функциите на дадено приложение."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"осъществяване на достъп до данните от сензорите при висока скорост на семплиране"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 6bcf9aa..7dac240d 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"অ্যাপটিকে \'বিরক্ত করবে না\' কনফিগারেশন পড়া এবং লেখার অনুমতি দেয়।"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"দেখার অনুমতি কাজে লাগানো শুরু করুন"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"কোনও অ্যাপের কোনও নির্দিষ্ট অনুমতির ব্যবহার শুরু করার ক্ষেত্রে হোল্ডারকে সাহায্য করে। সাধারণ অ্যাপের জন্য এটির পরিবর্তন হওয়ার কথা নয়।"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"অনুমতি সংক্রান্ত সিদ্ধান্ত দেখা শুরু করুন"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"অনুমতি সংক্রান্ত সিদ্ধান্ত পর্যালোচনা করার জন্য, হোল্ডারকে স্ক্রিন চালু করতে দেয়। সাধারণ অ্যাপের জন্য কখনই প্রয়োজন হওয়া উচিত নয়।"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"অ্যাপের ফিচার দেখা শুরু করুন"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"কোনও অ্যাপের ফিচার সম্পর্কিত তথ্য দেখা শুরু করতে অনুমতি দেয়।"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"হাই স্যাম্পলিং রেটে সেন্সর ডেটা অ্যাক্সেস করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c1823c9..28ca86d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -736,10 +736,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Omogućava aplikaciji da čita i upisuje konfiguraciju načina rada Ne ometaj."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"pokrenuti korištenje odobrenja za pregled"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Dozvoljava vlasniku da pokrene korištenje odobrenja za aplikaciju. Ne bi trebalo biti potrebno za obične aplikacije."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"prikažite odluke o odobrenjima"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Dozvoljava vlasniku da pokrene ekran radi pregleda odluka o odobrenju. Obično nije potrebno za obične aplikacije."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"pokretanje pregleda funkcija aplikacije"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Dozvoljava vlasniku da pokrene pregled informacija o funkcijama za aplikaciju."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pristup podacima senzora velikom brzinom uzorkovanja"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 325b620..be1b43c 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permet que l\'aplicació llegeixi la configuració No molestis i hi escrigui."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"comença a utilitzar el permís de visualització"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permet que un propietari comenci a utilitzar el permís amb una aplicació. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"inicia la visualització de les decisions sobre permisos"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permet que l\'aplicació en qüestió iniciï la pantalla per revisar les decisions sobre permisos. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"iniciar la visualització de les funcions d\'una aplicació"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permet que el propietari vegi la informació de les funcions d\'una aplicació."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"accedir a les dades del sensor a una freqüència de mostratge alta"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 68128a4..d038dfc 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -739,10 +739,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Umožňuje aplikaci číst a zapisovat konfiguraci režimu Nerušit."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"zahájení zobrazení využití oprávnění"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Umožňuje přístup zahájit využití oprávnění jiné aplikace. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"zobrazit rozhodnutí o oprávnění"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Umožňuje držiteli aktivovat obrazovku a zkontrolovat rozhodnutí o oprávnění. Běžné aplikace by toto oprávnění neměly nikdy potřebovat."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"zobrazení informací o funkcích aplikace"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Umožňuje držiteli zobrazit informace o funkcích aplikace."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"přístup k datům ze senzorů s vyšší vzorkovací frekvencí"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 9134c57..afe1175 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Giver appen tilladelse til at læse og redigere konfigurationen af Forstyr ikke."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"start brugen at tilladelsesvisning"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Tillader, at brugeren kan bruge en tilladelse for en app. Dette bør aldrig være nødvendigt for almindelige apps."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"starte visningen af beslutninger om tilladelser"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Giver modtageren mulighed for at åbne skærmen til gennemgang af beslutninger om tilladelser. Dette bør aldrig være nødvendigt for standardapps."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"se appfunktioner"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Giver den app, som har tilladelsen, mulighed for at se oplysninger om en apps funktioner."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"få adgang til sensordata ved høj samplingfrekvens"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index ed2a92a..ecaa63c 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Ermöglicht der App Lese- und Schreibzugriff auf die „Bitte nicht stören“-Konfiguration"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"Mit der Verwendung der Anzeigeberechtigung beginnen"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Ermöglicht dem Inhaber, die Berechtigungsnutzung für eine App zu beginnen. Sollte für normale Apps nie benötigt werden."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"Entscheidungen zu Leseberechtigung starten"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Ermöglicht dem Inhaber, das Display zu starten, um Berechtigungsentscheidungen anzusehen. Sollte für normale Apps nie benötigt werden."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"App-Funktionen ansehen"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Ermöglicht der App, die Informationen über die Funktionen einer anderen App anzusehen."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Sensordaten mit hoher Frequenz auslesen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index ef23640..44fe426 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Επιτρέπει στην εφαρμογή την εγγραφή και τη σύνταξη διαμόρφωσης για τη λειτουργία \"Μην ενοχλείτε\"."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"έναρξη χρήσης άδειας προβολής"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Επιτρέπει στον κάτοχο να ξεκινήσει τη χρήση της άδειας για μια εφαρμογή. Δεν απαιτείται ποτέ για κανονικές εφαρμογές."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"έναρξη προβολής αποφάσεων για άδειες"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Επιτρέπει στον κάτοχο να ξεκινήσει την προβολή για τον έλεγχο των αποφάσεων για τις άδειες. Δεν χρειάζεται ποτέ για κανονικές εφαρμογές."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"έναρξη προβολής λειτουργιών εφαρμογής"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Επιτρέπει στον κάτοχο να ξεκινήσει την προβολή των πληροφοριών για τις λειτουργίες μιας εφαρμογής."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"πρόσβαση σε δεδομένα αισθητήρα με υψηλό ρυθμό δειγματοληψίας"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index a5cb421..fad71eb7 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permite que la aplicación lea y modifique la configuración de la función No interrumpir."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"iniciar uso de permiso de vista"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite que el propietario inicie el uso de permisos para una app. No debería requerirse para apps normales."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"iniciar vista de las decisiones sobre permisos"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permite que el propietario vea la pantalla a fin de revisar las decisiones que tomó sobre los permisos. Las apps normales no deberían necesitar este permiso."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"iniciar vista de funciones de la app"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que el propietario vea la información de las funciones de una app."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Acceder a los datos de sensores a una tasa de muestreo alta"</string>
@@ -779,7 +777,7 @@
<string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Evita el uso de algunas funciones de bloqueo de pantalla."</string>
<string-array name="phoneTypes">
<item msgid="8996339953292723951">"Casa"</item>
- <item msgid="7740243458912727194">"Móvil"</item>
+ <item msgid="7740243458912727194">"Celular"</item>
<item msgid="8526146065496663766">"Trabajo"</item>
<item msgid="8150904584178569699">"Fax laboral"</item>
<item msgid="4537253139152229577">"Fax residencial"</item>
@@ -822,7 +820,7 @@
</string-array>
<string name="phoneTypeCustom" msgid="5120365721260686814">"Personalizado"</string>
<string name="phoneTypeHome" msgid="3880132427643623588">"Casa"</string>
- <string name="phoneTypeMobile" msgid="1178852541462086735">"Móvil"</string>
+ <string name="phoneTypeMobile" msgid="1178852541462086735">"Celular"</string>
<string name="phoneTypeWork" msgid="6604967163358864607">"Trabajo"</string>
<string name="phoneTypeFaxWork" msgid="6757519896109439123">"Fax laboral"</string>
<string name="phoneTypeFaxHome" msgid="6678559953115904345">"Fax personal"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 21910b9..669e914 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permite que la aplicación lea y modifique la configuración de No molestar."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"iniciar uso de permiso de visualización"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite que el titular inicie el uso de permisos de una aplicación. Las aplicaciones normales no deberían necesitar nunca este permiso."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"iniciar la revisión de decisiones sobre los permisos"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permite que el titular inicie la revisión de las decisiones sobre los permisos. Las aplicaciones normales no deberían necesitar nunca este permiso."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ver funciones de una aplicación"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que el titular vea la información de las funciones de una aplicación."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"acceder a datos de sensores a una frecuencia de muestreo alta"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 118d605..e4d33a7 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Võimaldab rakendusel lugeda ja kirjutada funktsiooni Mitte segada seadistusi."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"vaatamisloa kasutamise alustamine"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Võimaldab omanikul rakenduse puhul alustada loa kasutamist. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"Alustada lubade otsuste vaatamist."</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Võimaldab omanikul ekraani käivitada, et lubade otsused üle vaadata. Tavaliste rakenduste puhul ei tohiks seda kunagi vaja minna."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"rakenduse funktsioonide vaatamise alustamine"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Võimaldab omanikul alustada rakenduse funktsioonide teabe vaatamist."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"juurdepääs anduri andmetele kõrgel diskreetimissagedusel"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 2c3bdfb..a3766b76 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -562,7 +562,7 @@
<string name="permlab_useBiometric" msgid="6314741124749633786">"erabili hardware biometrikoa"</string>
<string name="permdesc_useBiometric" msgid="7502858732677143410">"Autentifikatzeko hardware biometrikoa erabiltzeko baimena ematen die aplikazioei."</string>
<string name="permlab_manageFingerprint" msgid="7432667156322821178">"kudeatu hatz-marken hardwarea"</string>
- <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Erreferentzia-gako digitalen txantiloiak gehitzeko eta ezabatzeko metodoei dei egitea baimentzen die aplikazioei."</string>
+ <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Aztarna digitalaren txantiloiak gehitzeko eta ezabatzeko metodoei dei egitea baimentzen die aplikazioei."</string>
<string name="permlab_useFingerprint" msgid="1001421069766751922">"erabili hatz-marken hardwarea"</string>
<string name="permdesc_useFingerprint" msgid="412463055059323742">"Autentifikatzeko hatz-marken hardwarea erabiltzeko baimena ematen die aplikazioei."</string>
<string name="permlab_audioWrite" msgid="8501705294265669405">"musika-bilduma aldatu"</string>
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Ez molestatzeko moduaren konfigurazioa irakurtzeko eta bertan idazteko baimena ematen die aplikazioei."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"hasi ikusteko baimena erabiltzen"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Aplikazioaren baimena erabiltzen hasteko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"hasi baimenen inguruko erabakiak ikusten"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Baimenen inguruko erabakiak berrikusteko pantaila ikusten hasteko baimena ematen die titularrei. Aplikazio normalek ez lukete beharko."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"hasi aplikazioaren eginbideak ikusten"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Aplikazio baten eginbideei buruzko informazioa ikusten hasteko baimena ematen die titularrei."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"atzitu sentsoreen datuen laginak abiadura handian"</string>
@@ -1635,8 +1633,8 @@
<string name="expires_on" msgid="1623640879705103121">"Iraungitze-data:"</string>
<string name="serial_number" msgid="3479576915806623429">"Serie-zenbakia:"</string>
<string name="fingerprints" msgid="148690767172613723">"Erreferentzia-fitxategiak:"</string>
- <string name="sha256_fingerprint" msgid="7103976380961964600">"SHA-256 erreferentzia-gako digitala:"</string>
- <string name="sha1_fingerprint" msgid="2339915142825390774">"SHA-1 erreferentzia-gako digitala:"</string>
+ <string name="sha256_fingerprint" msgid="7103976380961964600">"SHA-256 aztarna digitala:"</string>
+ <string name="sha1_fingerprint" msgid="2339915142825390774">"SHA-1 aztarna digitala:"</string>
<string name="activity_chooser_view_see_all" msgid="3917045206812726099">"Ikusi guztiak"</string>
<string name="activity_chooser_view_dialog_title_default" msgid="8880731437191978314">"Aukeratu jarduera"</string>
<string name="share_action_provider_share_with" msgid="1904096863622941880">"Partekatu hauekin:"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 050580c..c9dedf9 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"به برنامه امکان میدهد پیکربندی «مزاحم نشوید» را بخواند و بنویسد."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"شروع مشاهده استفاده از مجوز"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"به دارنده اجازه شروع استفاده از مجوز را برای برنامه میدهد. هرگز برای برنامههای معمول نیاز نیست."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"شروع مشاهده تصمیمهای مربوط به اجازهها"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"به دارنده امکان میدهد صفحه را برای مرور تصمیمهای مربوط به اجازهها شروع کند. هرگز نباید برای برنامههای عادی لازم باشد."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"مشاهده ویژگیهای برنامه"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"به دارنده اجازه میدهد اطلاعات مربوط به ویژگیهای برنامه را مشاهده کند."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"دسترسی به دادههای حسگر با نرخ نمونهبرداری بالا"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index d511e28..b7234be 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Sallii sovelluksen lukea ja muokata Älä häiritse -tilan asetuksia."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"aloita katseluoikeuksien käyttö"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Antaa luvanhaltijan käynnistää sovelluksen käyttöoikeuksien käytön. Ei tavallisten sovelluksien käyttöön."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"aloita lupapäätösten tarkistaminen"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Antaa luvanhaltijan käynnistää näytön lupapäätösten tarkistamiseksi. Ei tavallisten sovellusten käyttöön."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"aloittaa sovellusominaisuuksien katselun"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Antaa luvanhaltijan aloittaa sovelluksen ominaisuustietojen katselun."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"saada pääsyn anturidataan suuremmalla näytteenottotaajuudella"</string>
@@ -1647,7 +1645,7 @@
<string name="activity_resolver_use_once" msgid="948462794469672658">"Vain kerran"</string>
<string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s ei tue työprofiilia"</string>
<string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Tabletti"</string>
- <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Televisio"</string>
+ <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string>
<string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Puhelin"</string>
<string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Telineen kaiuttimet"</string>
<string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 2723a6d..6a08237 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permet à l\'application de consulter et de modifier la configuration du mode Ne pas déranger."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"démarrer l\'affichage de l\'usage des autorisations"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permet au détenteur de démarrer l\'usage des autorisations pour une application. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"démarrer les décisions d\'autorisation de lecture"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permet au détenteur de démarrer l\'écran pour revoir les décisions d\'autorisation. Ne devrait pas être requis pour les applications standards."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"démarrer l\'affichage des fonctionnalités de l\'application"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permet au détenteur de commencer à afficher les renseignements sur les fonctionnalités d\'une application."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"accéder aux données des capteurs à un taux d’échantillonnage élevé"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 365b68f..c606ed3 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permet à l\'application de consulter et de modifier la configuration du mode Ne pas déranger."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"activer l\'utilisation de l\'autorisation d\'affichage"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permet à l\'application autorisée d\'activer l\'utilisation de l\'autorisation pour une application. Cette fonctionnalité ne devrait pas être nécessaire pour les applications standards."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"activer l\'affichage des décisions liées aux autorisations"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permet à l\'appli autorisée de lancer un écran pour examiner les décisions liées aux autorisations. Ne devrait jamais être nécessaire pour les applis standards."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"commencer à voir les fonctionnalités d\'une appli"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permet à l\'appli autorisée de commencer à voir les infos sur les fonctionnalités d\'une appli."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"accéder aux données des capteurs à un taux d\'échantillonnage élevé"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 9c0d33a..24287d9 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permite á aplicación ler e escribir a configuración do modo Non molestar."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"iniciar uso de permiso de vista"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite ao propietario iniciar o uso de permisos dunha aplicación. As aplicacións normais non deberían precisalo nunca."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"iniciar vista das decisións sobre os permisos"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permite que a persoa propietaria acceda a unha pantalla onde poderá examinar as decisións relativas aos permisos. Esta opción nunca debería ser necesaria para as aplicacións normais."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"comezar a ver as funcións da aplicación"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite que o propietario comece a ver a información das funcións dunha aplicación."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"acceder aos datos dos sensores usando unha taxa de mostraxe alta"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 2996cc3..5ca2c39 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"એપ્લિકેશનને ખલેલ પાડશો નહીં ગોઠવણી વાંચવા અને લખવાની મંજૂરી આપે છે."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"પરવાનગી વપરાશ જુઓને શરૂ કરો"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"કોઈ ઍપ માટે પરવાનગી વપરાશ શરૂ કરવાની ધારકને મંજૂરી આપે છે. સામાન્ય ઍપ માટે ક્યારેય જરૂર પડી ન શકે."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"પરવાનગી સંબંધિત નિર્ણયો જોવાનું શરૂ કરો"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ધારકને પરવાનગી સંબંધિત નિર્ણયોનો રિવ્યૂ કરવા માટે સ્ક્રીન શરૂ કરવાની મંજૂરી આપે છે. સામાન્ય ઍપ માટે ક્યારેય જરૂરી હોવું જોઈએ નહીં."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ઍપની સુવિધાઓ જોવા માટેની પરવાનગી ચાલુ કરો"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ધારકને ઍપ માટેની સુવિધાઓની માહિતી જોવાનું શરૂ કરવાની મંજૂરી આપે છે."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ઉચ્ચ સેમ્પ્લિંગ રેટ પર સેન્સરનો ડેટા ઍક્સેસ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 5c6eaeb..b846ff8 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ऐप को परेशान न करें कॉन्फ़िगरेशन पढ़ने और लिखने देती है."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"देखने की अनुमतियां चालू करें"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"इस्तेमाल करने वाले को किसी ऐप्लिकेशन के लिए अनुमतियों का इस्तेमाल शुरू करने देता है. सामान्य ऐप्लिकेशन के लिए इसकी ज़रूरत कभी नहीं पड़ती."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"अनुमतियों को देखना चालू करना"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ऐप्लिकेशन को स्क्रीन शुरू करने की अनुमति मिलती है, ताकि अनुमतियों की समीक्षा की जा सके. सामान्य ऐप्लिकेशन के लिए, इसकी ज़रूरत कभी नहीं पड़ती."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ऐप्लिकेशन की सुविधाओं को देखना शुरू करें"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ऐप्लिकेशन को, किसी ऐप्लिकेशन की सुविधाओं की जानकारी देखने की अनुमति देता है."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"सेंसर डेटा को, नमूने लेने की तेज़ दर पर ऐक्सेस करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 15f59dc..e88b331 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -736,10 +736,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Omogućuje aplikaciji čitanje i pisanje konfiguracije opcije Ne uznemiravaj."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"pokrenuti upotrebu dopuštenja za pregled"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Dopušta nositelju pokretanje upotrebe dopuštenja za aplikaciju. Ne bi smjelo biti potrebno za uobičajene aplikacije."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"pokrenuti odluke o dopuštenju za pregled"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Dopušta nositelju pokretanje zaslona za pregled odluka o dopuštenjima. Ne bi trebalo biti potrebno za uobičajene aplikacije."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"pokretanje prikaza značajki aplikacije"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Dopušta nositelju pokretanje prikaza informacija o značajkama aplikacije."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pristup podacima senzora pri višoj brzini uzorkovanja"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index b7e35cf2..46fcc2a 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Az alkalmazás olvashatja és szerkesztheti a „Ne zavarjanak” funkció beállításait."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"engedélyhasználat megtekintésének elindítása"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Lehetővé teszi a felhasználó számára, hogy elindítsa az alkalmazás engedélyhasználatát. A normál alkalmazásoknak erre soha nincs szükségük."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"engedélyezési döntések megtekintésének elindítása"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Lehetővé teszi az alkalmazás számára, hogy elindítsa a képernyőt az engedélyezési döntések felülvizsgálata érdekében. A normál alkalmazások esetében erre nincs szükség."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"alkalmazásfunkciók megtekintésének megkezdése"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Engedélyezi az alkalmazás számára, hogy megkezdje az alkalmazások funkcióira vonatkozó adatok megtekintését."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"hozzáférés a szenzoradatokhoz nagy mintavételezési gyakorisággal"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 13d8780..b60f08b 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Թույլ է տալիս հավելվածին փոփոխել «Չանհանգստացնել» գործառույթի կազմաձևումը:"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"թույլտվությունների մասին տվյալների հասանելիություն"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Հավելվածին հասանելի կդառնան թույլտվությունների մասին տվյալները։ Այս թույլտվությունն անհրաժեշտ չէ սովորական հավելվածներին։"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"սկսել թույլտվությունների հետ գործողությունների դիտումը"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Թույլ է տալիս դիտել թույլտվությունների հետ գործողությունները։ Սովորական հավելվածների համար երբևէ չպետք է անհրաժեշտ լինի։"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"հավելվածի գործառույթների դիտում"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Թույլ է տալիս դիտել հավելվածի գործառույթների մասին տեղեկությունները։"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"օգտագործել սենսորների տվյալները բարձր հաճախականության վրա"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 997b25e..7925b3f 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Mengizinkan aplikasi membaca dan menulis konfigurasi status Jangan Ganggu."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"mulai melihat penggunaan izin"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Memungkinkan pemegang memulai penggunaan izin untuk aplikasi. Tidak diperlukan untuk aplikasi normal."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"mulai melihat keputusan izin"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Mengizinkan pemegang memulai layar untuk meninjau keputusan izin. Tidak pernah dibutuhkan untuk aplikasi normal."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"mulai lihat fitur aplikasi"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Memungkinkan pemegang mulai melihat info fitur untuk aplikasi."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"mengakses data sensor pada frekuensi pengambilan sampel yang tinggi"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 99e4d1a..c758de5 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Leyfir forriti að lesa og skrifa í grunnstillingu „Ónáðið ekki“."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"heimildanotkun upphafsyfirlits"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Leyfir handhafa að byrja heimildanotkun fyrir forrit. Ætti aldrei að þurfa fyrir venjuleg forrit."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"opna ákvarðanir um skoðunarheimildir"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Gerir notandanum kleift að opna skjá til að fara yfir ákvarðanir um heimildir. Þetta ætti aldrei að þurfa fyrir venjuleg forrit."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"byrja að skoða eiginleika forrits"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Leyfir handhafa að skoða upplýsingar um eiginleika tiltekins forrits."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"aðgangur að skynjaragögnum með hárri upptökutíðni"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 4b3f305..c5683fa 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Consente all\'app di leggere e modificare la configurazione della funzione Non disturbare."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"avvio dell\'uso dell\'autorizzazione di visualizzazione"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Consente al titolare di avviare l\'uso delle autorizzazioni per un\'app. Non dovrebbe essere mai necessaria per le normali applicazioni."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"Inizio della visualizzazione delle decisioni relative all\'autorizzazione"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Consente all\'app che ha questa autorizzazione di avviare lo schermo per esaminare le decisioni relative all\'autorizzazione. Non dovrebbe mai essere necessaria per le normali app."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"Inizio della visualizzazione di funzionalità delle app"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Consente all\'app che ha questa autorizzazione di iniziare a visualizzare le informazioni relative alle funzionalità di un\'app."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Accesso ai dati dei sensori a una frequenza di campionamento elevata"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index bdc87fe..9da03ea 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -739,10 +739,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"מאפשרת לאפליקציה לקרוא ולכתוב את התצורה של התכונה \'נא לא להפריע\'."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"התחלת צפייה בהרשאות השימוש"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"מאפשרת לבעלים להפעיל את השימוש בהרשאות עבור אפליקציה מסוימת. הרשאה זו אף פעם לא נדרשת עבור אפליקציות רגילות."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ההחלטות לגבי ההרשאות להפעלת התצוגה"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"בעלי ההרשאה יוכלו להפעיל את המסך כדי לעיין בהחלטות לגבי הרשאות. ההרשאה לא נחוצה לאפליקציות רגילות בדרך כלל."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"התחלת צפייה בהרשאות של אפליקציות"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"בעלי ההרשאה יוכלו להתחיל לצפות בפרטי התכונות של אפליקציות."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"גישה לנתוני חיישנים בתדירות דגימה גבוהה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e6e2ed8..76d248c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"サイレント モード設定の読み取りと書き込みをアプリに許可します。"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"表示権限の使用の開始"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"アプリの権限使用の開始を所有者に許可します。通常のアプリでは不要です。"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"閲覧権限の許可 / 拒否の開始"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"権限の許可 / 拒否を確認するための画面の開始を所有者に許可します。通常のアプリでは不要です。"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"アプリ機能の表示の開始"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"アプリの機能情報の表示の開始を所有者に許可します。"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"高サンプリング レートでセンサーデータにアクセスする"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 16f3fe0..91144c6 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"საშუალებას აძლევს აპს, წაიკითხოს და დაწეროს კონფიგურაცია „არ შემაწუხოთ“."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"ნახვის ნებართვის გამოყენების დაწყება"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"მფლობელს საშუალებას აძლევს, დაიწყოს აპის ნებართვის გამოყენება. ჩვეულებრივი აპებისთვის არასოდეს უნდა იყოს საჭირო."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ნებართვის შესახებ გადაწყვეტილებების ნახვის დაწყება"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"მფლობელს საშუალებას აძლევს, გაუშვას ეკრანი ნებართვის შესახებ გადაწყვეტილებების სანახავად. ჩვეულებრივი აპებისთვის არასოდეს უნდა იყოს საჭირო."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"აპის ფუნქციების ნახვის დაწყება"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"მფლობელს საშუალებას აძლევს, დაიწყოს აპის ფუნქციების ინფორმაციის ნახვა."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"სენსორის მონაცემებზე წვდომა სემპლინგის მაღალი სიხშირით"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 155a77a..3f75495 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Қолданбаға «Мазаламау» конфигурациясын оқу және жазу мүмкіндігін береді."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"рұқсаттарды пайдалану туралы деректерді көру"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Пайдаланушы қолданбаға берілетін рұқсаттарды басқара алады. Ондай рұқсаттар әдеттегі қолданбаларға керек емес."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"Рұқсаттары бар әрекеттерді көру"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Қолданбаға рұқсаттары бар әрекеттерді көруге мүмкіндік береді. Әдеттегі қолданбаларға қажет емес."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"қолданба функцияларын көре бастау"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Қолданбаға функциялар туралы ақпаратты көре бастауды кідіртуге мүмкіндік береді."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"жоғары дискретизация жиілігіндегі датчик деректерін пайдалану"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 8021330..ecae41a 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"អនុញ្ញាតឲ្យកម្មវិធីអាន និងសរសេរការកំណត់រចនាសម្ព័ន្ធមុខងារ កុំរំខាន។"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"ចាប់ផ្ដើមមើលការប្រើប្រាស់ការអនុញ្ញាត"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"អនុញ្ញាតឱ្យម្ចាស់ចាប់ផ្ដើមការប្រើប្រាស់ការអនុញ្ញាតសម្រាប់កម្មវិធី។ មិនគួរចាំបាច់សម្រាប់កម្មវិធីធម្មតាទេ។"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ចាប់ផ្ដើមមើលការសម្រេចលើការអនុញ្ញាត"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"អនុញ្ញាតឱ្យកម្មវិធីចាប់ផ្ដើមត្រួតពិនិត្យ ដើម្បីពិនិត្យមើលការសម្រេចលើការអនុញ្ញាត។ មិនចាំបាច់ទេសម្រាប់កម្មវិធីធម្មតា។"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ចាប់ផ្ដើមមើលមុខងារកម្មវិធី"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"អនុញ្ញាតឱ្យកម្មវិធីចាប់ផ្ដើមមើលព័ត៌មានមុខងារសម្រាប់កម្មវិធី។"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ចូលប្រើទិន្នន័យឧបករណ៍ចាប់សញ្ញានៅអត្រាសំណាកខ្ពស់"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 4c8871a..a24166c 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಕಾನ್ಫಿಗರೇಶನ್ ಅನ್ನು ಓದಲು ಮತ್ತು ಬರೆಯಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"ವೀಕ್ಷಣಾ ಅನುಮತಿಯ ಬಳಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸಿ"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ಆ್ಯಪ್ಗಾಗಿ ಅನುಮತಿ ಬಳಕೆಯನ್ನು ಪ್ರಾರಂಭಿಸಲು ಹೊಂದಿರುವವರಿಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಸಾಮಾನ್ಯ ಆ್ಯಪ್ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ಅನುಮತಿಯ ನಿರ್ಧಾರಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಪ್ರಾರಂಭಿಸಿ"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ಅನುಮತಿಯ ನಿರ್ಧಾರಗಳನ್ನು ಪರಿಶೀಲಿಸುವುದಕ್ಕಾಗಿ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಲು ಬಳಕೆದಾರರನ್ನು ಅನುಮತಿಸುತ್ತದೆ. ಸಾಮಾನ್ಯ ಆ್ಯಪ್ಗಳಿಗೆ ಎಂದಿಗೂ ಅಗತ್ಯವಿರುವುದಿಲ್ಲ."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ಆ್ಯಪ್ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಪ್ರಾರಂಭಿಸಿ"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ಆ್ಯಪ್ನ ವೈಶಿಷ್ಟ್ಯಗಳ ಮಾಹಿತಿಯನ್ನು ವೀಕ್ಷಿಸಲು ಬಳಕೆದಾರರನ್ನು ಅನುಮತಿಸುತ್ತದೆ."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ಹೆಚ್ಚಿನ ನಮೂನೆ ದರದಲ್ಲಿ ಸೆನ್ಸಾರ್ ಡೇಟಾ ಪ್ರವೇಶಿಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1f71f0f..8920be2 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"앱에서 방해 금지 모드 설정을 읽고 작성하도록 허용합니다."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"권한 사용 보기 시작"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"앱의 권한 사용을 시작하려면 보유자를 허용하세요. 일반 앱에는 필요하지 않습니다."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"권한 결정 보기 시작"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"권한 결정 검토를 위해 기기 보유자가 화면을 시작할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"앱 기능 보기"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"권한을 보유한 앱에서 앱의 기능 정보를 보도록 허용합니다."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"더 높은 샘플링 레이트로 센서 데이터 액세스"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index ca703f4..50c9393 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Колдонмого \"Тынчымды алба\" режиминин конфигурациясын окуу жана жазуу мүмкүнчүлүгүн берет."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"уруксаттын колдонулушун көрүп баштоо"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Колдонмонун пайдаланылышына уруксат берүүгө мүмкүнчүлүк берет. Кадимки колдонмолорго эч качан талап кылынбашы керек."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"уруксаттар боюнча кабыл алынган чечимдерди карап чыгуу"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Ээсине уруксаттар боюнча кабыл алынган чечимдерди карап чыгуу үчүн экранды иштетүү мүмкүнчүлүгүн берет. Кадимки колдонмолорго эч качан талап кылынбашы керек."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"колдонмонун функцияларын көрүп баштоо"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Колдонуучуга функциялары тууралуу маалыматты көрүп баштоо мүмкүнчүлүгүн берет."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"үлгүнү жаздыруу ылдамдыгы жогору болгон сенсор дайындарынын үлгүсүнө мүмкүнчүлүк алуу"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 20df320..398b6b3 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ອະນຸຍາດໃຫ້ແອັບອ່ານ ແລະຂຽນການກນຳດຄ່າ ບໍ່ລົບກວນ."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"ເລີ່ມການໃຊ້ສິດອະນຸຍາດການເບິ່ງ"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ອະນຸຍາດໃຫ້ຜູ້ຖືເລີ່ມການໃຊ້ສິດອະນຸຍາດສຳລັບແອັບໃດໜຶ່ງໄດ້. ແອັບປົກກະຕິບໍ່ຄວນຕ້ອງໃຊ້."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ເລີ່ມເບິ່ງການຕັດສິນໃຈການອະນຸຍາດ"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ອະນຸຍາດໃຫ້ຜູ້ຖືເລີ່ມໜ້າຈໍເພື່ອກວດສອບການຕັດສິນໃຈການອະນຸຍາດ. ແອັບປົກກະຕິບໍ່ຄວນຈຳເປັນຕ້ອງໃຊ້."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ເລີ່ມເບິ່ງຄຸນສົມບັດແອັບ"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ອະນຸຍາດໃຫ້ຜູ້ຖືເລີ່ມການເບິ່ງຂໍ້ມູນຄຸນສົມບັດສຳລັບແອັບໃດໜຶ່ງ."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ເຂົ້າເຖິງຂໍ້ມູນເຊັນເຊີໃນອັດຕາຕົວຢ່າງສູງ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f307213..de36cb6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -739,10 +739,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Leidžiama programai skaityti ir rašyti „Do Not Disturb“ konfigūraciją."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"pradėti peržiūrėti leidimo naudojimą"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Leidžia savininkui pradėti naudoti programos leidimą. Įprastoms programoms to neturėtų prireikti."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"pradėti sprendimų dėl leidimų peržiūrą"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Savininkui leidžiama atidaryti ekraną ir peržiūrėti sprendimus dėl leidimų. Neturėtų prireikti naudojant įprastas programas."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"pradėti programos funkcijų peržiūrą"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Savininkui leidžiama pradėti programos funkcijų informacijos peržiūrą."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"pasiekti jutiklių duomenis dideliu skaitmeninimo dažniu"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index ee3ba28..93414e0 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -736,10 +736,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Ļauj lietotnei lasīt un rakstīt režīma “Netraucēt” konfigurāciju."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"Datu skatīšana par izmantojamajām atļaujām"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Ļauj atļaujas īpašniekam sākt lietotnes atļauju izmantošanu. Parastām lietotnēm tas nekad nav nepieciešams."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"Skatīt darbības ar atļaujām"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Lietotne ar šo atļauju var pārskatīt darbības ar atļaujām. Parastām lietotnēm šīs atļauja nekad nav nepieciešama."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"Skatīt lietotnes funkcijas"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Lietotne ar šo atļauju var skatīt informāciju par citas lietotnes funkcijām."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"piekļuve sensoru datiem, izmantojot augstu iztveršanas frekvenci"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 2c460ab..d4f099f 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Дозволува апликацијата да чита и пишува конфигурација Не вознемирувај."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"започнете со користење на дозволата за приказ"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Дозволува сопственикот да почне со користење на дозволата за апликација. Не треба да се користи за стандардни апликации."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"да го стартува приказот за одлуки за дозволи"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Му дозволува на сопственикот да го стартува екранот за прегледување одлуки за дозволи. Не треба да се користи за стандардни апликации."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"да почне со прегледување на функциите на апликацијата"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"му дозволува на сопственикот да почне со прегледување на податоците за функциите за некоја апликација"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"пристапува до податоците со висока фреквенција на семпл"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index a0698a7..1c98f25 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"\'ശല്യപ്പെടുത്തരുത്\' കോൺഫിഗറേഷൻ വായിക്കുന്നതിനും എഴുതുന്നതിനും ആപ്പിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"അനുമതി ഉപയോഗം കാണാൻ ആരംഭിക്കുക"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ഒരു ആപ്പിനുള്ള അനുമതി ഉപയോഗം ആരംഭിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"അനുമതിയുമായി ബന്ധപ്പെട്ട തീരുമാനങ്ങൾ കാണാൻ ആരംഭിക്കുക"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"അനുമതിയുമായി ബന്ധപ്പെട്ട തീരുമാനങ്ങൾ അവലോകനം ചെയ്യുന്നതിന് സ്ക്രീൻ ആരംഭിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു. സാധാരണ ആപ്പുകൾക്ക് ഒരിക്കലും ആവശ്യമില്ല."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ആപ്പ് ഫീച്ചറുകൾ കാണാൻ ആരംഭിക്കുക"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ആപ്പിനുള്ള ഫീച്ചറുകളുടെ വിവരങ്ങൾ കാണാൻ ആരംഭിക്കാൻ ഹോൾഡറിനെ അനുവദിക്കുന്നു."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ഉയർന്ന സാംപ്ലിംഗ് റേറ്റിൽ സെൻസർ ഡാറ്റ ആക്സസ് ചെയ്യുക"</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index f86c875..db67e90 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Апп-д Бүү саад бол тохируулгыг уншиж, бичихийг зөвшөөрөх"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"зөвшөөрлийн ашиглалтыг харж эхлэх"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Эзэмшигчид аппын зөвшөөрлөө ашиглаж эхлэхийг зөвшөөрдөг. Энгийн аппуудад шаардлагагүй."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"зөвшөөрлийн шийдвэрийг хянах дэлгэцийг эхлүүлэх"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Эзэмшигчид зөвшөөрлийн шийдвэрийг хянах дэлгэцийг эхлүүлэх боломжийг олгоно. Энгийн аппуудад хэзээ ч шаардагдахгүй."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"аппын онцлогуудыг үзэж эхлэх"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Аппын онцлогуудын мэдээллийг үзэж эхлэхийг эзэмшигчид зөвшөөрдөг."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"түүврийн өндөр хувиар мэдрэгчийн өгөгдөлд хандах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index a244a2f..1385dcd 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"व्यत्यय आणू नका कॉंफिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी ॲपला अनुमती देते."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"व्ह्यू परवानगी वापर सुरू करा"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"धारकास अॅपसाठी परवानगी वापरणे सुरू करण्याची अनुमती देते. सामान्य अॅप्ससाठी कधीही आवश्यकता नसते."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"परवानगीशी संबंधित निर्णय पाहणे सुरू करा"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"होल्डरला परवानगीशी संबंधित निर्णयांचे पुनरावलोकन करण्यासाठी स्क्रीन सुरू करण्याची अनुमती देते. सामान्य ॲप्ससाठी कधीही आवश्यक नसते."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ॲप वैशिष्ट्ये पाहणे सुरू करा"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"होल्डरला ॲपसाठी वैशिष्ट्यांची माहिती पाहण्यास सुरू करण्याची अनुमती देते."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"उच्च नमुना दराने सेन्सर डेटा अॅक्सेस करते"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 12cd501..43847fe 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Membenarkan apl membaca dan menulis konfigurasi Jangan Ganggu."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"mulakan lihat penggunaan kebenaran"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Membenarkan pemegang memulakan penggunaan kebenaran untuk apl. Tidak sekali-kali diperlukan untuk apl biasa."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"mula melihat keputusan kebenaran"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Membenarkan pemegang memulakan skrin untuk menyemak keputusan kebenaran. Tidak diperlukan untuk apl biasa."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"mula melihat ciri apl"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Membenarkan pemegang mula melihat maklumat ciri untuk apl."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"akses data penderia pada data pensampelan yang tinggi"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 59505a5..f509906 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"မနှောင့်ယှက်ရန် ချိန်ညှိမှုကို အပ်ဖ်များ ဖတ်ခြင်း ပြင်ခြင်းပြုလုပ်နိုင်ရန် ခွင့်ပြုမည်။"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"အစမြင်ကွင်း ခွင့်ပြုချက် အသုံးပြုမှု"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"အက်ပ်တစ်ခုအတွက် ခွင့်ပြုချက်စတင်အသုံးပြုမှုကို ကိုင်ဆောင်သူအား ခွင့်ပြုသည်။ ပုံမှန်အက်ပ်များအတွက် ဘယ်သောအခါမျှ မလိုအပ်ပါ။"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ခွင့်ပြုသည့် ဆုံးဖြတ်ချက်များကို စတင်ကြည့်ခြင်း"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ခွင့်ပြုထားသည့်အက်ပ်အား ခွင့်ပြုသည့်ဆုံးဖြတ်ချက်များကို ကြည့်နိုင်ရန်အတွက် စခရင်စတင်ရန် ခွင့်ပြုနိုင်သည်။ သာမန်အက်ပ်များအတွက် မည်သည့်အခါမျှ မလိုအပ်နိုင်ပါ။"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"အက်ပ်ဝန်ဆောင်မှုများကို စတင်ကြည့်ခြင်း"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ဝန်ဆောင်မှုအချက်အလက်ကိုများကို ခွင့်ပြုချက်ရထားသည့် အက်ပ်အား စတင်ကြည့်နိုင်ရန် ခွင့်ပြုသည်။"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"နမူနာနှုန်းမြင့်သော အာရုံခံစနစ်ဒေတာကို သုံးပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index f12287f..2ddd45d 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Lar appen lese og skrive konfigurasjon av Ikke forstyrr."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"start visning av bruk av tillatelser"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Lar innehaveren starte bruk av tillatelser for en app. Dette skal aldri være nødvendig for vanlige apper."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"starte visning av avgjørelser om tillatelser"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Lar innehaveren starte skjermen for å gjennomgå avgjørelser om tillatelser. Dette skal aldri være nødvendig for vanlige apper."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"starte visning av appfunksjoner"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Lar innehaveren se informasjon om funksjonene for en app."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"tilgang til sensordata ved høy samplingfrekvens"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index bf8499e..d4828b6 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"बाधा नपुर्याउँनुहोस् कन्फिगरेसन पढ्न र लेख्नको लागि एपलाई अनुमति दिनुहोस्।"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"हेर्ने अनुमतिको प्रयोग सुरु गर्नुहोस्"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"वाहकलाई कुनै एपसम्बन्धी अनुमतिको प्रयोग सुरु गर्न दिन्छ। साधारण एपहरूलाई कहिल्यै आवश्यक नपर्नु पर्ने हो।"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"अनुमतिसम्बन्धी निर्णयहरू हेर्न सुरु गर्नुहोस्"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"होल्डरलाई अनुमतिसम्बन्धी निर्णयहरू समीक्षा गर्ने स्क्रिन सुरु गर्न दिन्छ। सामान्य एपहरूलाई कहिल्यै पनि नचाहिनु पर्ने हो।"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"एपका सुविधासम्बन्धी जानकारी हेर्न थाल्नुहोस्"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"होल्डरलाई एपका सुविधासम्बन्धी जानकारी हेर्न दिन्छ।"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"नमुना लिने उच्च दरमा सेन्सरसम्बन्धी डेटा प्रयोग गर्ने"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1dac982..3b6db06 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Hiermee kan de app configuratie voor Niet storen lezen en schrijven."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"rechtengebruik starten"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Hiermee kan de houder het rechtengebruik voor een app starten. Nooit vereist voor normale apps."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"bekijken van rechtenbeslissingen starten"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Hiermee kan de houder het scherm starten om rechtenbeslissingen te bekijken. Nooit vereist voor normale apps."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"app-functies bekijken"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Hiermee kan de houder informatie over functies bekijken voor een app."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"toegang krijgen tot sensorgegevens met een hoge samplingsnelheid"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index e825c2c..0220ce3 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"\"ବିରକ୍ତ କରନ୍ତୁ ନାହିଁ\" କନଫିଗରେଶନ୍ ପଢ଼ିବା ତଥା ଲେଖିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"ଅନୁମତି ବ୍ୟବହାର ଦେଖିବା ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ଏକ ଆପ୍ ପାଇଁ ଅନୁମତିର ବ୍ୟବହାର ଆରମ୍ଭ କରିବାକୁ ଧାରକକୁ ଅନୁମତି ଦେଇଥାଏ। ସାଧାରଣ ଆପ୍ଗୁଡ଼ିକ ପାଇଁ ଏହା ଆବଶ୍ୟକ ନୁହେଁ।"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ଅନୁମତି ନିଷ୍ପତ୍ତିଗୁଡ଼ିକ ଦେଖିବା ଆରମ୍ଭ କରନ୍ତୁ"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ଅନୁମତି ନିଷ୍ପତ୍ତିଗୁଡ଼ିକର ସମୀକ୍ଷା କରିବାକୁ ସ୍କ୍ରିନ ଚାଲୁ କରିବା ପାଇଁ ହୋଲଡରଙ୍କୁ ଅନୁମତି ଦିଏ। ସାଧାରଣ ଆପଗୁଡ଼ିକ ପାଇଁ ଏହା କେବେ ବି ଆବଶ୍ୟକ ହେବ ନାହିଁ।"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ଆପର ଫିଚରଗୁଡ଼ିକୁ ଦେଖିବା ଆରମ୍ଭ କରନ୍ତୁ"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"କୌଣସି ଆପ ପାଇଁ ଫିଚରଗୁଡ଼ିକ ବିଷୟରେ ସୂଚନା ଦେଖିବା ଆରମ୍ଭ କରିବାକୁ ହୋଲଡରଙ୍କୁ ଅନୁମତି ଦିଏ।"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ଏକ ଉଚ୍ଚ ନମୁନାକରଣ ରେଟରେ ସେନ୍ସର୍ ଡାଟାକୁ ଆକ୍ସେସ୍ କରନ୍ତୁ"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index fd822a3..7a3bc33 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -174,7 +174,7 @@
<string name="httpErrorTooManyRequests" msgid="2149677715552037198">"ਬਹੁਤ ਜ਼ਿਆਦਾ ਬੇਨਤੀਆਂ ਦੀ ਪ੍ਰਕਿਰਿਆ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ। ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="notification_title" msgid="5783748077084481121">"<xliff:g id="ACCOUNT">%1$s</xliff:g> ਲਈ ਸਾਈਨਇਨ ਅਸ਼ੁੱਧੀ"</string>
<string name="contentServiceSync" msgid="2341041749565687871">"ਸਿੰਕ ਕਰੋ"</string>
- <string name="contentServiceSyncNotificationTitle" msgid="5766411446676388623">"ਸਮਕਾਲੀਕਿਰਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
+ <string name="contentServiceSyncNotificationTitle" msgid="5766411446676388623">"ਸਿੰਕ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="4562226280528716090">"ਬਹੁਤ ਸਾਰੀਆਂ <xliff:g id="CONTENT_TYPE">%s</xliff:g> ਨੂੰ ਮਿਟਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕੀਤੀ ਗਈ।"</string>
<string name="low_memory" product="tablet" msgid="5557552311566179924">"ਟੈਬਲੈੱਟ ਸਟੋਰੇਜ ਪੂਰੀ ਭਰੀ ਹੈ। ਜਗ੍ਹਾ ਖਾਲੀ ਕਰਨ ਲਈ ਕੁਝ ਫ਼ਾਈਲਾਂ ਮਿਟਾਓ।"</string>
<string name="low_memory" product="watch" msgid="3479447988234030194">"ਘੜੀ ਸਟੋਰੇਜ ਪੂਰੀ ਭਰੀ ਹੈ। ਜਗ੍ਹਾ ਖਾਲੀ ਕਰਨ ਲਈ ਕੁਝ ਫ਼ਾਈਲਾਂ ਮਿਟਾਓ।"</string>
@@ -676,11 +676,11 @@
<string name="face_error_vendor_unknown" msgid="7387005932083302070">"ਕੋਈ ਗੜਬੜ ਹੋ ਗਈ। ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="face_icon_content_description" msgid="465030547475916280">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ਸਿੰਕ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹੋ"</string>
- <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ਐਪ ਨੂੰ ਕਿਸੇ ਖਾਤੇ ਲਈ ਸਮਕਾਲੀਕਰਨ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਹ ਪਤਾ ਕਰ ਸਕਦਾ ਹੈ ਕਿ People ਐਪ ਦਾ ਕਿਸੇ ਖਾਤੇ ਨਾਲ ਸਮਕਾਲੀਕਿਰਤ ਕੀਤਾ ਗਿਆ ਹੈ ਜਾਂ ਨਹੀਂ।"</string>
- <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"ਸਮਕਾਲੀਕਰਨ ਚਾਲੂ ਅਤੇ ਬੰਦ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
- <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"ਐਪ ਨੂੰ ਇੱਕ ਖਾਤੇ ਲਈ ਸਮਕਾਲੀਕਰਨ ਸੈਟਿੰਗਾਂ ਸੋਧਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸਦੀ ਵਰਤੋਂ ਕਿਸੇ ਖਾਤੇ ਨਾਲ People ਐਪ ਦਾ ਸਮਕਾਲੀਕਰਨ ਚਾਲੂ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ।"</string>
+ <string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ਐਪ ਨੂੰ ਕਿਸੇ ਖਾਤੇ ਲਈ ਸਿੰਕ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਹ ਪਤਾ ਕਰ ਸਕਦਾ ਹੈ ਕਿ People ਐਪ ਨੂੰ ਕਿਸੇ ਖਾਤੇ ਨਾਲ ਸਿੰਕ ਕੀਤਾ ਗਿਆ ਹੈ ਜਾਂ ਨਹੀਂ।"</string>
+ <string name="permlab_writeSyncSettings" msgid="6583154300780427399">"ਸਿੰਕ ਚਾਲੂ ਅਤੇ ਬੰਦ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
+ <string name="permdesc_writeSyncSettings" msgid="6029151549667182687">"ਐਪ ਨੂੰ ਇੱਕ ਖਾਤੇ ਲਈ ਸਿੰਕ ਸੈਟਿੰਗਾਂ ਸੋਧਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸਦੀ ਵਰਤੋਂ ਕਿਸੇ ਖਾਤੇ ਨਾਲ People ਐਪ ਦਾ ਸਿੰਕ ਚਾਲੂ ਕਰਨ ਲਈ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ।"</string>
<string name="permlab_readSyncStats" msgid="3747407238320105332">"ਸਿੰਕ ਅੰਕੜੇ ਪੜ੍ਹੋ"</string>
- <string name="permdesc_readSyncStats" msgid="3867809926567379434">"ਐਪ ਨੂੰ ਇੱਕ ਖਾਤੇ ਲਈ ਸਮਕਾਲੀਕਰਨ ਸਥਿਤੀ ਪੜ੍ਹਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ, ਇਸ ਵਿੱਚ ਸਮਕਾਲੀਕਰਨ ਵਰਤਾਰਿਆਂ ਦਾ ਇਤਿਹਾਸ ਅਤੇ ਕਿੰਨੇ ਡਾਟਾ ਦਾ ਸਮਕਾਲੀਕਿਰਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਵੀ ਸ਼ਾਮਲ ਹੈ।"</string>
+ <string name="permdesc_readSyncStats" msgid="3867809926567379434">"ਐਪ ਨੂੰ ਇੱਕ ਖਾਤੇ ਲਈ ਸਿੰਕ ਸਥਿਤੀ ਪੜ੍ਹਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ, ਇਸ ਵਿੱਚ ਸਿੰਕ ਇਵੈਂਟਾਂ ਦਾ ਇਤਿਹਾਸ ਅਤੇ ਕਿੰਨਾ ਡਾਟਾ ਸਿੰਕ ਕੀਤਾ ਜਾਂਦਾ ਹੈ, ਇਹ ਵੀ ਸ਼ਾਮਲ ਹੈ।"</string>
<string name="permlab_sdcardRead" msgid="5791467020950064920">"ਸਮੱਗਰੀਆਂ ਪੜ੍ਹੋ"</string>
<string name="permdesc_sdcardRead" msgid="6872973242228240382">"ਐਪ ਨੂੰ ਸਮੱਗਰੀਆਂ ਪੜ੍ਹਨ ਦਿੰਦੀ ਹੈ।"</string>
<string name="permlab_sdcardWrite" msgid="4863021819671416668">"ਸਮੱਗਰੀਆਂ ਦਾ ਸੰਸ਼ੋਧਨ ਕਰੋ ਜਾਂ ਮਿਟਾਓ"</string>
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ਐਪ ਨੂੰ ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ ਕੌਂਫਿਗਰੇਸ਼ਨ ਨੂੰ ਪੜ੍ਹਨ ਅਤੇ ਲਿਖਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"ਇਜਾਜ਼ਤ ਵਰਤੋਂ ਦੇਖਣਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ਧਾਰਕ ਨੂੰ ਕਿਸੇ ਹੋਰ ਐਪ ਲਈ ਇਜਾਜ਼ਤ ਵਰਤੋਂ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਦਿੰਦਾ ਹੈ। ਸਧਾਰਨ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦਾ ਨਹੀਂ ਹੋਵੇਗਾ।"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"ਇਜਾਜ਼ਤ ਸੰਬੰਧੀ ਫ਼ੈਸਲਿਆਂ ਨੂੰ ਦੇਖਣਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ਇਜਾਜ਼ਤ ਸੰਬੰਧੀ ਫ਼ੈਸਲਿਆਂ ਦੀ ਸਮੀਖਿਆ ਕਰਨ ਲਈ ਹੋਲਡਰ ਨੂੰ ਸਕ੍ਰੀਨ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ। ਸਧਾਰਨ ਐਪਾਂ ਲਈ ਕਦੇ ਵੀ ਲੋੜੀਂਦੀ ਨਹੀਂ ਹੋਵੇਗੀ।"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ਐਪ ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਦੇਖਣਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ਇਸ ਨਾਲ ਹੋਲਡਰ ਨੂੰ ਕਿਸੇ ਐਪ ਦੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਬਾਰੇ ਜਾਣਕਾਰੀ ਦੇਖਣ ਦੀ ਆਗਿਆ ਮਿਲਦੀ ਹੈ।"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ਉੱਚ ਸੈਂਪਲਿੰਗ ਰੇਟ \'ਤੇ ਸੈਂਸਰ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index c2e8663..bbc1867 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -739,10 +739,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Pozwala aplikacji na odczyt i zmianę konfiguracji trybu Nie przeszkadzać."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"rozpocząć wyświetlanie użycia uprawnień"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Umożliwia rozpoczęcie korzystania z uprawnienia dotyczącego danej aplikacji jego posiadaczowi. Zwykłe aplikacje nie powinny potrzebować tego uprawnienia."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"rozpoczęcie wyświetlania decyzji dotyczących uprawnień"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Umożliwia posiadaczowi uruchomienie ekranu w celu przeglądania decyzji dotyczących uprawnień. Zwykłe aplikacje nie powinny tego potrzebować."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"rozpoczęcie wyświetlania funkcji aplikacji"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Umożliwia posiadaczowi rozpoczęcie przeglądania informacji o funkcjach aplikacji."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"dostęp do danych czujnika z wysoką częstotliwością"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 2f89483..4469a67 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -736,10 +736,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Permite aplicației să citească și să scrie configurația Nu deranja."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"porniți folosirea permisiunii de vizualizare"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Permite proprietarului să pornească folosirea permisiunii pentru o aplicație. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"să înceapă să examineze deciziile privind permisiunile"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Permite proprietarului să deschidă ecranul pentru a examina deciziile privind permisiunile. Nu ar trebui să fie necesară pentru aplicațiile obișnuite."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"începeți să vedeți funcțiile aplicației"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Permite proprietarului să înceapă să vadă informațiile despre funcții pentru o aplicație."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"să acceseze date de la senzori la o rată de eșantionare mare"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e4d6527..6b874b9 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -739,10 +739,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Открывает приложению доступ к настройкам режима \"Не беспокоить\" и позволяет изменять их."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"Просмотр данных об используемых разрешениях"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Приложение получит доступ к данным об используемых разрешениях. Это разрешение не требуется обычным приложениям."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"Просмотр действий с разрешениями"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Позволяет просматривать действия с разрешениями. Не используется обычными приложениями."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"Просмотр функций приложения"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Позволяет просматривать информацию о функциях приложения."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"Доступ к данным датчиков при высокой частоте дискретизации"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 027fcd2..3443681 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"බාධා නොකරන්න වින්යාස කිරීම කියවීමට සහ ලිවීමට යෙදුමට ඉඩ දෙයි."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"අවසර භාවිතය බැලීමට ආරම්භ කරන්න"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"තබා සිටින්නාට යෙදුමක් සඳහා අවසර භාවිතය ආරම්භ කිරීමට ඉඩ දෙයි. සාමාන්ය යෙදුම් සඳහා කිසි විටෙක අවශ්ය නොවිය යුතු ය."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"නව අවසර තීරණ ආරම්භ කරන්න"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"අවසර තීරණ සමාලෝචනය කිරීමට තිරය ආරම්භ කිරීමට දරන්නාට ඉඩ දෙයි. සාමාන්ය යෙදුම් සඳහා කිසිදා අවශ්ය නොවිය යුතුය."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"යෙදුම බලන්න විශේෂාංග ආරම්භ කරන්න"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"යෙදුමක් සඳහා විශේෂාංග තොරතුරු බැලීම ආරම්භ කිරීමට දරන්නාට ඉඩ දෙන්න."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"ඉහළ නියැදි කිරීමේ වේගයකින් සංවේදක දත්ත වෙත පිවිසෙන්න"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index eab7f73..0737100 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Lejon aplikacionin të lexojë dhe shkruajë konfigurimin e \"Mos shqetëso\"."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"nis përdorimin e lejes për shikimin"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Lejon që mbajtësi të nisë përdorimin e lejeve për një aplikacion. Nuk duhet të nevojitet asnjëherë për aplikacionet normale."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"nisë shikimin e vendimeve për lejet"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Lejon që zotëruesi të nisë ekranin për shqyrtimin e vendimeve për lejet. Nuk duhet të nevojitet asnjëherë për aplikacionet normale."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"fillojë shikimin e veçorive të aplikacionit"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Lejon që zotëruesi të fillojë të shikojë informacionin e veçorive për një aplikacion."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"qasu te të dhënat e sensorit me një shpejtësi kampionimi më të lartë"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 8d49f2a..e117bda 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -736,10 +736,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Дозвољава апликацији да чита и уписује конфигурацију подешавања Не узнемиравај."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"почетак коришћења дозволе за преглед"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Дозвољава власнику да започне коришћење дозволе за апликацију. Никада не би требало да буде потребна за уобичајене апликације."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"покретање прегледа одлука о дозволама"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Дозвољава власнику да покрене екран за проверу одлука о дозволама. Никада не би требало да буде потребно за обичне апликације."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"покретање приказа функција апликације"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Дозвољава носиоцу дозволе да започне прегледање информација о функцијама апликације."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"приступ подацима сензора при великој брзини узорковања"</string>
@@ -1552,7 +1550,7 @@
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"Веза са увек укљученим VPN-ом је прекинута"</string>
<string name="vpn_lockdown_error" msgid="4453048646854247947">"Повезивање на стално укључени VPN није успело"</string>
<string name="vpn_lockdown_config" msgid="8331697329868252169">"Промените подешавања VPN-а"</string>
- <string name="upload_file" msgid="8651942222301634271">"Одабери датотеку"</string>
+ <string name="upload_file" msgid="8651942222301634271">"Одабери фајл"</string>
<string name="no_file_chosen" msgid="4146295695162318057">"Није изабрана ниједна датотека"</string>
<string name="reset" msgid="3865826612628171429">"Ресетуј"</string>
<string name="submit" msgid="862795280643405865">"Пошаљи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index af3586b..90de245 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Ger appen läs- och skrivbehörighet till konfigurationen för Stör ej."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"börja visa behörighetsanvändningen"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Gör att innehavaren kan öppna behörighetsanvändning för en app. Ska inte behövas för vanliga appar."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"börja visa behörighetsbeslut"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Tillåter att innehavaren öppnar skärmen för att granska behörighetsbeslut. Detta ska inte behövas för vanliga appar."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"börja visa appfunktioner"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Tillåter att innehavaren börjar visa information om funktioner för en app."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"åtkomst till sensordata med en hög samplingsfrekvens"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index f70bfcd..ec24102 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Inaruhusu programu kusoma na kuandika usanidi wa kipengee cha Usinisumbue."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"anzisha kipengele cha kuona matumizi ya ruhusa"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Huruhusu kishikiliaji kuanzisha matumizi ya ruhusa ya programu. Haipaswi kuhitajika kwa ajili ya programu za kawaida."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"kuanzisha uamuzi wa ruhusa za kuangalia"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Humruhusu mmiliki kuanzisha skrini ili kukagua uamuzi wa ruhusa. Haipaswi kuhitajika kwenye programu za kawaida."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"anzisha kipengele cha kuangalia vipengele vya programu"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Huruhusu mmiliki kuanza kuangalia maelezo ya vipengele vya programu."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"fikia data ya vitambuzi kwa kasi ya juu ya sampuli"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 1114bf1..e7ea59d 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"தொந்தரவு செய்ய வேண்டாம் உள்ளமைவைப் படிக்கவும் எழுதவும், ஆப்ஸை அனுமதிக்கிறது."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"அனுமதி உபயோகத்தை அணுகுதல்"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"ஆப்ஸிற்கான அனுமதி உபயோகத்தை ஹோல்டருக்கு வழங்கும். இயல்பான ஆப்ஸிற்கு இது எப்போதுமே தேவைப்படாது."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"அனுமதி முடிவுகளைப் பார்க்கத் தொடங்குதல்"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"அனுமதி தொடர்பான முடிவுகளை மதிப்பாய்வு செய்ய, திரையைத் தொடங்குவதற்கான அனுமதியை ஹோல்டருக்கு வழங்கும். இயல்பான ஆப்ஸிற்கு இது எப்போதுமே தேவைப்படாது."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ஆப்ஸின் அம்சங்களைப் பார்க்கத் தொடங்குதல்"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ஆப்ஸின் அம்சங்கள் குறித்த தகவல்களைப் பார்ப்பதற்கான அனுமதியை ஹோல்டருக்கு வழங்கும்."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"அதிகளவிலான சாம்பிளிங் ரேட்டில் சென்சார் தரவை அணுகுதல்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 0d9cb8b..176d845 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"అంతరాయం కలిగించవద్దు ఎంపిక కాన్ఫిగరేషన్ చదవడానికి మరియు రాయడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"వీక్షణ అనుమతి వినియోగాన్ని ప్రారంభించండి"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"యాప్నకు అనుమతి వినియోగాన్ని ప్రారంభించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ యాప్లకు ఎప్పటికీ ఇటువంటి అనుమతి అవసరం ఉండదు."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"వీక్షణ అనుమతి నిర్ణయాలను ప్రారంభించండి"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"అనుమతి నిర్ణయాలను రివ్యూ చేయడానికి స్క్రీన్ను ప్రారంభించడానికి హోల్డర్ను అనుమతిస్తుంది. సాధారణ యాప్లకు ఎప్పటికీ అవసరం ఉండదు."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"యాప్ ఫీచర్లను చూడటాన్ని ప్రారంభించండి"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"యాప్ ఫీచర్ల సమాచారాన్ని చూడటాన్ని ప్రారంభించడానికి హోల్డర్ను అనుమతిస్తుంది."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"అధిక శాంపిల్ రేటు వద్ద సెన్సార్ డేటాను యాక్సెస్ చేయండి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index b6b0345..30b3d0b 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"อนุญาตให้แอปอ่านและเขียนการกำหนดค่าโหมดห้ามรบกวน"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"เริ่มการใช้สิทธิ์การดู"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"อนุญาตให้เจ้าของเริ่มการใช้สิทธิ์ของแอป ไม่จำเป็นสำหรับแอปทั่วไป"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"เริ่มดูสิทธิ์ที่เลือกไว้"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"อนุญาตให้แอปเริ่มหน้าจอเพื่อดูสิทธิ์ที่เลือกไว้ แอปทั่วไปไม่จำเป็นต้องใช้"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"เริ่มดูฟีเจอร์ของแอป"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"อนุญาตให้เจ้าของเริ่มดูข้อมูลฟีเจอร์สำหรับแอป"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"เข้าถึงข้อมูลเซ็นเซอร์ที่อัตราการสุ่มตัวอย่างสูง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index fa73788..c0bbc69 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Nagbibigay-daan sa app na basahin at isulat ang configuration ng Huwag Istorbohin."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"simulan ang paggamit sa pahintulot sa pagtingin"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Binibigyang-daan ang may hawak na simulan ang paggamit ng pahintulot para sa isang app. Hindi dapat kailanganin kailanman para sa mga normal na app."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"simulan ang mga desisyon sa pahintulot na tumingin"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Nagbibigay-daan sa may hawak na simulan ang screen para masuri ang mga desisyon sa pahintulot. Hindi dapat kailanman kailanganin para sa mga karaniwang app."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"simulang tingnan ang mga feature ng app"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Nagbibigay-daan sa may hawak na simulang tingnan ang impormasyon ng mga feature para sa isang app."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"mag-access ng data ng sensor sa mataas na rate ng pag-sample"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index adf96e0..8a86227 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Uygulamaya, Rahatsız Etmeyin yapılandırmasını okuma ve yazma izni verir."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"izin kullanımı görüntülemeye başlama"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"İzin sahibinin bir uygulama için izin kullanımı başlatmasına olanak tanır. Normal uygulamalar için hiçbir zaman kullanılmamalıdır."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"izin kararlarını görüntülemeye başlama"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"İzin sahibinin, izin kararlarını incelemek için ekranı başlatmasına izin verir. Normal uygulamalarda hiçbir zaman gerek duyulmaz."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"uygulama özelliklerini görüntülemeye başlama"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"İzin sahibinin, bir uygulamanın özellik bilgilerini görüntülemeye başlamasına izin verir."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"sensör verilerine daha yüksek örnekleme hızında eriş"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index b86402a..f4fb575 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -739,10 +739,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Додаток зможе переглядати та змінювати конфігурацію режиму \"Не турбувати\"."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"перегляньте дані про використання дозволів"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Власник зможе використовувати дозволи для цього додатка. Цей дозвіл не потрібен для звичайних додатків."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"почати перегляд рішень щодо дозволів"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"У додатку може відкриватися екран для перегляду рішень щодо дозволів. Звичайні додатки ніколи не використовують цей дозвіл."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"почати перегляд функцій додатка"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Дозволяє додатку почати перегляд інформації про функції іншого додатка."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"доступ до даних датчиків із високою частотою дикретизації"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 65fe847..2c712f4 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"ایپ کو ڈسٹرب نہ کریں کنفیگریشن لکھنے اور پڑھنے کے قابل کرتا ہے۔"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"اجازت کی استعمال کا ملاحظہ شروع کریں"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"حامل کو ایپ کی اجازت کے استعمال کو شروع کرنے کی اجازت دیتا ہے۔ عام ایپس کے لیے کبھی بھی درکار نہیں ہونا چاہیے۔"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"اجازت کے فیصلوں کو دیکھنا شروع کریں"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"ہولڈر کو اجازت کے فیصلوں کے جائزے کے لیے اسکرین شروع کرنے کی اجازت دیتا ہے۔ عام ایپس کے لیے کبھی بھی اس کی ضرورت نہيں ہونی چاہیے۔"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"ایپ کی خصوصیات کا ملاحظہ شروع کریں"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"ہولڈر کو ایپ کے لیے خصوصیات کی معلومات دیکھنے کی اجازت دیتا ہے۔"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"نمونہ کاری کی اعلی شرح پر سینسر کے ڈیٹا تک رسائی حاصل کریں"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index bbfadf6..05899ed 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Cho phép ứng dụng đọc và ghi cấu hình Không làm phiền."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"cấp quyền xem"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Cho phép chủ sở hữu cấp quyền cho một ứng dụng. Các ứng dụng thông thường sẽ không bao giờ cần quyền này."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"bắt đầu xem các quyết định cấp quyền"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Cho phép chủ sở hữu bắt đầu kiểm tra để xem xét các quyết định cấp quyền. Việc này hoàn toàn không cần thiết đối với các ứng dụng thông thường."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"bắt đầu xem các tính năng của ứng dụng"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Cho phép chủ sở hữu bắt đầu xem thông tin về tính năng của một ứng dụng."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"truy cập vào dữ liệu cảm biến ở tốc độ lấy mẫu cao"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b7e1972..6acd3e0 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"允许此应用读取和写入“勿扰”模式配置。"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"授权使用“查看权限”"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"允许该应用开始查看应用的权限使用情况(普通应用绝不需要此权限)。"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"开始查看权限决策"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"允许具有该权限的应用启动屏幕以查看权限决策。普通应用绝不需要此权限。"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"开始查看应用功能"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"允许具有该权限的应用开始查看某个应用的功能信息。"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"以高采样率访问传感器数据"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 86de22f..bf51c1a 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"允許應用程式讀取和寫入「請勿騷擾」設定。"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"開始查看權限使用情況"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"允許應用程式開始查看應用程式的權限使用情況 (一般應用程式並不需要)。"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"開始檢視權限決定"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"允許擁有者啟用螢幕以查看權限決定。不建議一般應用程式使用。"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"開始查看應用程式功能"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"允許擁有者開始查看應用程式的功能資料。"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"以高取樣率存取感應器資料"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index a4e6fbb..bd0b9a2 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"允許應用程式讀取及寫入「零打擾」設定。"</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"啟動檢視權限用途"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"允許應用程式開始使用其他應用程式 (一般應用程式並不需要)。"</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"開始檢視權限決定"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"允許應用程式啟動檢視權限決定的畫面 (一般應用程式並不需要)。"</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"開始查看應用程式功能"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"允許具有這項權限的應用程式開始查看其他應用程式的功能資訊。"</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"以高取樣率存取感應器資料"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 4e8cfd4..bf024528 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -733,10 +733,8 @@
<string name="permdesc_access_notification_policy" msgid="8538374112403845013">"Ivumela izinhlelo zokusebenza ukufunda nokubhala ukulungiswa kokuthi Ungaphazamisi."</string>
<string name="permlab_startViewPermissionUsage" msgid="1504564328641112341">"qala ukusetshenziswa kokubuka imvume"</string>
<string name="permdesc_startViewPermissionUsage" msgid="2820325605959586538">"Ivumela umphathi ukuthi aqale ukusetshenziswa kwemvume kohlelo lokusebenza. Akumele idingelwe izinhlelo zokusebenza ezijwayelekile."</string>
- <!-- no translation found for permlab_startReviewPermissionDecisions (8690578688476599284) -->
- <skip />
- <!-- no translation found for permdesc_startReviewPermissionDecisions (2775556853503004236) -->
- <skip />
+ <string name="permlab_startReviewPermissionDecisions" msgid="8690578688476599284">"qala ukubuka izinqumo zemvume"</string>
+ <string name="permdesc_startReviewPermissionDecisions" msgid="2775556853503004236">"Ivumela obambile ukuthi aqale isikrini ukuze abuyekeze izinqumo zemvume. Akufanele idingeke ngama-app avamile."</string>
<string name="permlab_startViewAppFeatures" msgid="7955084203185903001">"qala ukubuka izakhi ze-app"</string>
<string name="permdesc_startViewAppFeatures" msgid="7207240860165206107">"Vumela isibambi ukuthi siqale ukubuka ulwazi lwezakhi lwe-app."</string>
<string name="permlab_highSamplingRateSensors" msgid="3941068435726317070">"finyelela idatha yenzwa ngenani eliphezulu lokwenza isampuli"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d2dc600..e232d85 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5417,6 +5417,17 @@
ignores some hyphen character related typographic features, e.g. kerning. -->
<enum name="fullFast" value="4" />
</attr>
+ <!-- Indicates the line break strategies can be used when calculating the text wrapping. -->
+ <attr name="lineBreakStyle">
+ <!-- No line break style specific. -->
+ <enum name="none" value="0" />
+ <!-- Use the least restrictive rule for line-breaking. -->
+ <enum name="loose" value="1" />
+ <!-- Indicate breaking text with the most comment set of line-breaking rules. -->
+ <enum name="normal" value="2" />
+ <!-- ndicates breaking text with the most strictest line-breaking rules. -->
+ <enum name="strict" value="3" />
+ </attr>
<!-- Specify the type of auto-size. Note that this feature is not supported by EditText,
works only for TextView. -->
<attr name="autoSizeTextType" format="enum">
@@ -6884,6 +6895,9 @@
<!-- Special option for window animations: whether window should have rounded corners.
@see ScreenDecorationsUtils#getWindowCornerRadius(Resources) -->
<attr name="hasRoundedCorners" format="boolean" />
+ <!-- Special option for window animations: whether the window's background should be used as
+ a background to the animation. -->
+ <attr name="showBackground" format="boolean" />
</declare-styleable>
<declare-styleable name="AnimationSet">
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/res/res/values/public.xml b/core/res/res/values/public.xml
index dfeeccf..e83f4a6 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3211,6 +3211,7 @@
</staging-public-group-final>
<public type="attr" name="shouldUseDefaultUnfoldTransition" id="0x0101064c" />
+ <public type="attr" name="lineBreakStyle" id="0x0101064d" />
<staging-public-group-final type="id" first-id="0x01fe0000">
<public name="accessibilityActionDragStart" />
@@ -3254,6 +3255,7 @@
<!-- @hide @SystemApi -->
<public name="gameSessionService" />
<public name="localeConfig" />
+ <public name="showBackground" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">
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/Android.bp b/core/tests/coretests/Android.bp
index c18a70c..c1f3c4f 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -93,33 +93,9 @@
java_genrule {
name: "FrameworksCoreTests_apks_as_resources",
srcs: [
- ":FrameworksCoreTests_install",
- ":FrameworksCoreTests_install_bad_dex",
- ":FrameworksCoreTests_install_complete_package_info",
- ":FrameworksCoreTests_install_decl_perm",
":FrameworksCoreTests_install_jni_lib_open_from_apk",
- ":FrameworksCoreTests_install_loc_auto",
- ":FrameworksCoreTests_install_loc_internal",
- ":FrameworksCoreTests_install_loc_sdcard",
- ":FrameworksCoreTests_install_loc_unspecified",
- ":FrameworksCoreTests_install_use_perm_good",
- ":FrameworksCoreTests_install_uses_feature",
":FrameworksCoreTests_install_verifier_bad",
":FrameworksCoreTests_install_verifier_good",
- ":FrameworksCoreTests_keyset_permdef_sa_unone",
- ":FrameworksCoreTests_keyset_permuse_sa_ua_ub",
- ":FrameworksCoreTests_keyset_permuse_sb_ua_ub",
- ":FrameworksCoreTests_keyset_sab_ua",
- ":FrameworksCoreTests_keyset_sa_ua",
- ":FrameworksCoreTests_keyset_sa_uab",
- ":FrameworksCoreTests_keyset_sa_ua_ub",
- ":FrameworksCoreTests_keyset_sa_ub",
- ":FrameworksCoreTests_keyset_sa_unone",
- ":FrameworksCoreTests_keyset_sau_ub",
- ":FrameworksCoreTests_keyset_sb_ua",
- ":FrameworksCoreTests_keyset_sb_ub",
- ":FrameworksCoreTests_keyset_splata_api",
- ":FrameworksCoreTests_keyset_splat_api",
":FrameworksCoreTests_locales",
":FrameworksCoreTests_overlay_config",
":FrameworksCoreTests_version_1",
@@ -173,4 +149,4 @@
"framework",
"framework-res",
],
-}
\ No newline at end of file
+}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 14a3a01..f2b35c7 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -1670,11 +1670,4 @@
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.coretests"
android:label="Frameworks Core Tests" />
- <key-sets>
- <key-set android:name="A" >
- <public-key android:name="keyA"
- android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsMpNthdOxud7roPDZMMomOqXgJJdRfIWpkKEqmC61Mv+Nf6QY3TorEwJeghjSmqj7IbBKrtvfQq4E2XJO1HuspmQO4Ng2gvn+r+6EwNfKc9k55d6s+27SR867jKurBbHNtZMG+tjL1yH4r+tNzcuJCsgyAFqLmxFdcxEwzNvREyRpoYc5RDR0mmTwkMCUhJ6CId1EYEKiCEdNzxv+fWPEb21u+/MWpleGCILs8kglRVb2q/WOzAAvGr4FY5plfaE6N+lr7+UschQ+aMi1+uqewo2o0qPFVmZP5hnwj55K4UMzu/NhhDqQQsX4cSGES1KgHo5MTqRqZjN/I7emw5pFQIDAQAB"/>
- </key-set>
- <upgrade-key-set android:name="A"/>
- </key-sets>
</manifest>
diff --git a/core/tests/coretests/apks/install_complete_package_info/Android.bp b/core/tests/coretests/apks/install_complete_package_info/Android.bp
deleted file mode 100644
index 3fee0c6..0000000
--- a/core/tests/coretests/apks/install_complete_package_info/Android.bp
+++ /dev/null
@@ -1,15 +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_helper_app {
- name: "FrameworksCoreTests_install_complete_package_info",
- defaults: ["FrameworksCoreTests_apks_defaults"],
-
- srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_decl_perm/Android.bp b/core/tests/coretests/apks/install_decl_perm/Android.bp
deleted file mode 100644
index bf1f0de..0000000
--- a/core/tests/coretests/apks/install_decl_perm/Android.bp
+++ /dev/null
@@ -1,15 +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_helper_app {
- name: "FrameworksCoreTests_install_decl_perm",
- defaults: ["FrameworksCoreTests_apks_defaults"],
-
- srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_loc_auto/Android.bp b/core/tests/coretests/apks/install_loc_auto/Android.bp
deleted file mode 100644
index 37daf76..0000000
--- a/core/tests/coretests/apks/install_loc_auto/Android.bp
+++ /dev/null
@@ -1,15 +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_helper_app {
- name: "FrameworksCoreTests_install_loc_auto",
- defaults: ["FrameworksCoreTests_apks_defaults"],
-
- srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_loc_internal/Android.bp b/core/tests/coretests/apks/install_loc_internal/Android.bp
deleted file mode 100644
index 3e23313..0000000
--- a/core/tests/coretests/apks/install_loc_internal/Android.bp
+++ /dev/null
@@ -1,15 +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_helper_app {
- name: "FrameworksCoreTests_install_loc_internal",
- defaults: ["FrameworksCoreTests_apks_defaults"],
-
- srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_loc_sdcard/Android.bp b/core/tests/coretests/apks/install_loc_sdcard/Android.bp
deleted file mode 100644
index 708e655..0000000
--- a/core/tests/coretests/apks/install_loc_sdcard/Android.bp
+++ /dev/null
@@ -1,15 +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_helper_app {
- name: "FrameworksCoreTests_install_loc_sdcard",
- defaults: ["FrameworksCoreTests_apks_defaults"],
-
- srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/install_uses_feature/Android.bp b/core/tests/coretests/apks/install_uses_feature/Android.bp
deleted file mode 100644
index 913a96a..0000000
--- a/core/tests/coretests/apks/install_uses_feature/Android.bp
+++ /dev/null
@@ -1,15 +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_helper_app {
- name: "FrameworksCoreTests_install_uses_feature",
- defaults: ["FrameworksCoreTests_apks_defaults"],
-
- srcs: ["**/*.java"],
-}
diff --git a/core/tests/coretests/apks/keyset/Android.bp b/core/tests/coretests/apks/keyset/Android.bp
deleted file mode 100644
index 93c3b1f..0000000
--- a/core/tests/coretests/apks/keyset/Android.bp
+++ /dev/null
@@ -1,129 +0,0 @@
-//apks signed by keyset_A
-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_helper_app {
- name: "FrameworksCoreTests_keyset_sa_unone",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- manifest: "uNone/AndroidManifest.xml",
-}
-
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_sa_ua",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- manifest: "uA/AndroidManifest.xml",
-}
-
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_sa_ub",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- manifest: "uB/AndroidManifest.xml",
-}
-
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_sa_uab",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- manifest: "uAB/AndroidManifest.xml",
-}
-
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_sa_ua_ub",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- manifest: "uAuB/AndroidManifest.xml",
-}
-
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_permdef_sa_unone",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- manifest: "permDef/AndroidManifest.xml",
-}
-
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_permuse_sa_ua_ub",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- manifest: "permUse/AndroidManifest.xml",
-}
-
-//apks signed by keyset_B
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_sb_ua",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_B_cert",
- manifest: "uA/AndroidManifest.xml",
-}
-
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_sb_ub",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_B_cert",
- manifest: "uB/AndroidManifest.xml",
-}
-
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_permuse_sb_ua_ub",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_B_cert",
- manifest: "permUse/AndroidManifest.xml",
-}
-
-//apks signed by keyset_A and keyset_B
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_sab_ua",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- additional_certificates: [":FrameworksCoreTests_keyset_B_cert"],
- manifest: "uA/AndroidManifest.xml",
-}
-
-//apks signed by keyset_A and unit_test
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_sau_ub",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: ":FrameworksCoreTests_keyset_A_cert",
- additional_certificates: [":FrameworksCoreTests_keyset_B_cert"],
- manifest: "uB/AndroidManifest.xml",
-}
-
-//apks signed by platform only
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_splat_api",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: "platform",
- manifest: "api_test/AndroidManifest.xml",
-}
-
-//apks signed by platform and keyset_A
-android_test_helper_app {
- name: "FrameworksCoreTests_keyset_splata_api",
- defaults: ["FrameworksCoreTests_apks_defaults"],
- srcs: ["**/*.java"],
- certificate: "platform",
- additional_certificates: [":FrameworksCoreTests_keyset_A_cert"],
- manifest: "api_test/AndroidManifest.xml",
-}
diff --git a/core/tests/coretests/certs/Android.bp b/core/tests/coretests/certs/Android.bp
index 8411183..8d4ecf4 100644
--- a/core/tests/coretests/certs/Android.bp
+++ b/core/tests/coretests/certs/Android.bp
@@ -10,16 +10,6 @@
}
android_app_certificate {
- name: "FrameworksCoreTests_keyset_A_cert",
- certificate: "keyset_A",
-}
-
-android_app_certificate {
- name: "FrameworksCoreTests_keyset_B_cert",
- certificate: "keyset_B",
-}
-
-android_app_certificate {
name: "FrameworksCoreTests_unit_test_cert",
certificate: "unit_test",
}
diff --git a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
index fd3079f..d3e8bb0 100644
--- a/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
+++ b/core/tests/coretests/src/android/app/PropertyInvalidatedCacheTests.java
@@ -17,6 +17,8 @@
package android.app;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
import androidx.test.filters.SmallTest;
@@ -25,7 +27,9 @@
/**
* Test for verifying the behavior of {@link PropertyInvalidatedCache}. This test does
- * not use any actual binder calls - it is entirely self-contained.
+ * not use any actual binder calls - it is entirely self-contained. This test also relies
+ * on the test mode of {@link PropertyInvalidatedCache} because Android SELinux rules do
+ * not grant test processes the permission to set system properties.
* <p>
* Build/Install/Run:
* atest FrameworksCoreTests:PropertyInvalidatedCacheTests
@@ -33,6 +37,8 @@
@SmallTest
public class PropertyInvalidatedCacheTests {
+ // This property is never set. The test process does not have permission to set any
+ // properties.
static final String CACHE_PROPERTY = "cache_key.cache_test_a";
// This class is a proxy for binder calls. It contains a counter that increments
@@ -58,7 +64,8 @@
}
}
- // Clear the test mode after every test, in case this process is used for other tests.
+ // Clear the test mode after every test, in case this process is used for other
+ // tests. This also resets the test property map.
@After
public void tearDown() throws Exception {
PropertyInvalidatedCache.setTestMode(false);
@@ -176,5 +183,161 @@
}
};
assertEquals(true, cache1.getDisabledState());
+
+ // Remove the record of caches being locally disabled. This is a clean-up step.
+ cache1.clearDisableLocal();
+ assertEquals(true, cache1.getDisabledState());
+ assertEquals(true, cache2.getDisabledState());
+ assertEquals(false, cache3.getDisabledState());
+
+ // Create a new cache1. Verify that the new instance is not disabled.
+ cache1 = new PropertyInvalidatedCache<>(4, CACHE_PROPERTY) {
+ @Override
+ public Boolean recompute(Integer x) {
+ return tester.query(x);
+ }
+ };
+ assertEquals(false, cache1.getDisabledState());
+ }
+
+ private static final String UNSET_KEY = "Aiw7woh6ie4toh7W";
+
+ private static class TestCache extends PropertyInvalidatedCache<Integer, String> {
+ TestCache() {
+ this(CACHE_PROPERTY);
+ }
+
+ TestCache(String key) {
+ super(4, key);
+ setTestMode(true);
+ testPropertyName(key);
+ }
+
+ @Override
+ public String recompute(Integer qv) {
+ mRecomputeCount += 1;
+ return "foo" + qv.toString();
+ }
+
+ int getRecomputeCount() {
+ return mRecomputeCount;
+ }
+
+ private int mRecomputeCount = 0;
+ }
+
+ @Test
+ public void testCacheRecompute() {
+ TestCache cache = new TestCache();
+ cache.invalidateCache();
+ assertEquals(cache.isDisabledLocal(), false);
+ assertEquals("foo5", cache.query(5));
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals("foo5", cache.query(5));
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals("foo6", cache.query(6));
+ assertEquals(2, cache.getRecomputeCount());
+ cache.invalidateCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(3, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testCacheInitialState() {
+ TestCache cache = new TestCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(2, cache.getRecomputeCount());
+ cache.invalidateCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(3, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testCachePropertyUnset() {
+ TestCache cache = new TestCache(UNSET_KEY);
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(2, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testCacheDisableState() {
+ TestCache cache = new TestCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(2, cache.getRecomputeCount());
+ cache.invalidateCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(3, cache.getRecomputeCount());
+ cache.disableSystemWide();
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(5, cache.getRecomputeCount());
+ cache.invalidateCache(); // Should not reenable
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(7, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testRefreshSameObject() {
+ int[] refreshCount = new int[1];
+ TestCache cache = new TestCache() {
+ @Override
+ public String refresh(String oldResult, Integer query) {
+ refreshCount[0] += 1;
+ return oldResult;
+ }
+ };
+ cache.invalidateCache();
+ String result1 = cache.query(5);
+ assertEquals("foo5", result1);
+ String result2 = cache.query(5);
+ assertSame(result1, result2);
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals(1, refreshCount[0]);
+ assertEquals("foo5", cache.query(5));
+ assertEquals(2, refreshCount[0]);
+ }
+
+ @Test
+ public void testRefreshInvalidateRace() {
+ int[] refreshCount = new int[1];
+ TestCache cache = new TestCache() {
+ @Override
+ public String refresh(String oldResult, Integer query) {
+ refreshCount[0] += 1;
+ invalidateCache();
+ return new String(oldResult);
+ }
+ };
+ cache.invalidateCache();
+ String result1 = cache.query(5);
+ assertEquals("foo5", result1);
+ String result2 = cache.query(5);
+ assertEquals(result1, result2);
+ assertNotSame(result1, result2);
+ assertEquals(2, cache.getRecomputeCount());
+ }
+
+ @Test
+ public void testLocalProcessDisable() {
+ TestCache cache = new TestCache();
+ assertEquals(cache.isDisabledLocal(), false);
+ cache.invalidateCache();
+ assertEquals("foo5", cache.query(5));
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals("foo5", cache.query(5));
+ assertEquals(1, cache.getRecomputeCount());
+ assertEquals(cache.isDisabledLocal(), false);
+ cache.disableLocal();
+ assertEquals(cache.isDisabledLocal(), true);
+ assertEquals("foo5", cache.query(5));
+ assertEquals("foo5", cache.query(5));
+ assertEquals(3, cache.getRecomputeCount());
}
}
diff --git a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
index d6a7682..045e746 100644
--- a/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
+++ b/core/tests/coretests/src/android/text/MeasuredParagraphTest.java
@@ -136,8 +136,8 @@
MeasuredParagraph mt = null;
mt = MeasuredParagraph.buildForStaticLayout(
- PAINT, "XXX", 0, 3, LTR, MeasuredText.Builder.HYPHENATION_MODE_NONE, false,
- null /* no hint */, null);
+ PAINT, null /* line break config */, "XXX", 0, 3, LTR,
+ MeasuredText.Builder.HYPHENATION_MODE_NONE, false, null /* no hint */, null);
assertNotNull(mt);
assertNotNull(mt.getChars());
assertEquals("XXX", charsToString(mt.getChars()));
@@ -152,8 +152,8 @@
// Recycle it
MeasuredParagraph mt2 = MeasuredParagraph.buildForStaticLayout(
- PAINT, "_VVV_", 1, 4, RTL, MeasuredText.Builder.HYPHENATION_MODE_NONE, false,
- null /* no hint */, mt);
+ PAINT, null /* line break config */, "_VVV_", 1, 4, RTL,
+ MeasuredText.Builder.HYPHENATION_MODE_NONE, false, null /* no hint */, mt);
assertEquals(mt2, mt);
assertNotNull(mt2.getChars());
assertEquals("VVV", charsToString(mt.getChars()));
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
index 2c31b08..187803c 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java
@@ -20,8 +20,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
-import android.content.pm.parsing.ParsingPackageRead;
-import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
import android.os.Build;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -80,7 +79,7 @@
}
public boolean isMatchRequiredSystemProperty() {
- return ParsingPackageUtils.checkRequiredSystemProperties(
+ return FrameworkParsingPackageUtils.checkRequiredSystemProperties(
requiredSystemPropertyName, requiredSystemPropertyValue);
}
}
@@ -174,11 +173,12 @@
mIteration = Iteration.SYSTEM_SERVER;
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
- final TriConsumer<ParsingPackageRead, Boolean, File> f =
- (TriConsumer<ParsingPackageRead, Boolean, File>) args[0];
+ final TriConsumer<PackageProvider.Package, Boolean, File> f =
+ (TriConsumer<PackageProvider.Package, Boolean, File>) args[0];
for (Map.Entry<File, TestOverlayInfo> overlay :
mTestOverlayInfos.entrySet()) {
- final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class);
+ final PackageProvider.Package a =
+ Mockito.mock(PackageProvider.Package.class);
final TestOverlayInfo info = overlay.getValue();
if ((!TextUtils.isEmpty(info.requiredSystemPropertyName)
|| !TextUtils.isEmpty(info.requiredSystemPropertyValue))
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/core/tests/systemproperties/src/android/os/PropertyInvalidatedCacheTest.java b/core/tests/systemproperties/src/android/os/PropertyInvalidatedCacheTest.java
deleted file mode 100644
index 182bf6d..0000000
--- a/core/tests/systemproperties/src/android/os/PropertyInvalidatedCacheTest.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 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.os;
-
-import android.app.PropertyInvalidatedCache;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.TestCase;
-
-public class PropertyInvalidatedCacheTest extends TestCase {
- private static final String KEY = "sys.testkey";
- private static final String UNSET_KEY = "Aiw7woh6ie4toh7W";
-
- private static class TestCache extends PropertyInvalidatedCache<Integer, String> {
- TestCache() {
- this(KEY);
- }
-
- TestCache(String key) {
- super(4, key);
- }
-
- @Override
- public String recompute(Integer qv) {
- mRecomputeCount += 1;
- return "foo" + qv.toString();
- }
-
- int getRecomputeCount() {
- return mRecomputeCount;
- }
-
- private int mRecomputeCount = 0;
- }
-
- @Override
- protected void setUp() {
- SystemProperties.set(KEY, "");
- }
-
- @SmallTest
- public void testCacheRecompute() throws Exception {
- TestCache cache = new TestCache();
- cache.invalidateCache();
- assertEquals("foo5", cache.query(5));
- assertEquals(1, cache.getRecomputeCount());
- assertEquals("foo5", cache.query(5));
- assertEquals(1, cache.getRecomputeCount());
- assertEquals("foo6", cache.query(6));
- assertEquals(2, cache.getRecomputeCount());
- cache.invalidateCache();
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(3, cache.getRecomputeCount());
- }
-
- @SmallTest
- public void testCacheInitialState() throws Exception {
- TestCache cache = new TestCache();
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(2, cache.getRecomputeCount());
- cache.invalidateCache();
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(3, cache.getRecomputeCount());
- }
-
- @SmallTest
- public void testCachePropertyUnset() throws Exception {
- TestCache cache = new TestCache(UNSET_KEY);
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(2, cache.getRecomputeCount());
- }
-
- @SmallTest
- public void testCacheDisableState() throws Exception {
- TestCache cache = new TestCache();
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(2, cache.getRecomputeCount());
- cache.invalidateCache();
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(3, cache.getRecomputeCount());
- cache.disableSystemWide();
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(5, cache.getRecomputeCount());
- cache.invalidateCache(); // Should not reenable
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(7, cache.getRecomputeCount());
- }
-
- @SmallTest
- public void testRefreshSameObject() throws Exception {
- int[] refreshCount = new int[1];
- TestCache cache = new TestCache() {
- @Override
- protected String refresh(String oldResult, Integer query) {
- refreshCount[0] += 1;
- return oldResult;
- }
- };
- cache.invalidateCache();
- String result1 = cache.query(5);
- assertEquals("foo5", result1);
- String result2 = cache.query(5);
- assertSame(result1, result2);
- assertEquals(1, cache.getRecomputeCount());
- assertEquals(1, refreshCount[0]);
- assertEquals("foo5", cache.query(5));
- assertEquals(2, refreshCount[0]);
- }
-
- @SmallTest
- public void testRefreshInvalidateRace() throws Exception {
- int[] refreshCount = new int[1];
- TestCache cache = new TestCache() {
- @Override
- protected String refresh(String oldResult, Integer query) {
- refreshCount[0] += 1;
- invalidateCache();
- return new String(oldResult);
- }
- };
- cache.invalidateCache();
- String result1 = cache.query(5);
- assertEquals("foo5", result1);
- String result2 = cache.query(5);
- assertEquals(result1, result2);
- assertNotSame(result1, result2);
- assertEquals(2, cache.getRecomputeCount());
- }
-
- @SmallTest
- public void testLocalProcessDisable() throws Exception {
- TestCache cache = new TestCache();
- cache.invalidateCache();
- assertEquals("foo5", cache.query(5));
- assertEquals(1, cache.getRecomputeCount());
- assertEquals("foo5", cache.query(5));
- assertEquals(1, cache.getRecomputeCount());
- assertEquals(cache.isDisabledLocal(), false);
- cache.disableLocal();
- assertEquals(cache.isDisabledLocal(), true);
- assertEquals("foo5", cache.query(5));
- assertEquals("foo5", cache.query(5));
- assertEquals(3, cache.getRecomputeCount());
- }
-
-}
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/graphics/java/android/graphics/text/LineBreakConfig.java b/graphics/java/android/graphics/text/LineBreakConfig.java
new file mode 100644
index 0000000..4d81858
--- /dev/null
+++ b/graphics/java/android/graphics/text/LineBreakConfig.java
@@ -0,0 +1,110 @@
+/*
+ * 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.graphics.text;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/**
+ * Indicates the strategies can be used when calculating the text wrapping.
+ *
+ * See <a href="https://drafts.csswg.org/css-text/#line-break-property">the line-break property</a>
+ */
+public final class LineBreakConfig {
+
+ /**
+ * No line break style specified.
+ */
+ public static final int LINE_BREAK_STYLE_NONE = 0;
+
+ /**
+ * Use the least restrictive rule for line-breaking. This is usually used for short lines.
+ */
+ public static final int LINE_BREAK_STYLE_LOOSE = 1;
+
+ /**
+ * Indicate breaking text with the most comment set of line-breaking rules.
+ */
+ public static final int LINE_BREAK_STYLE_NORMAL = 2;
+
+ /**
+ * Indicates breaking text with the most strictest line-breaking rules.
+ */
+ public static final int LINE_BREAK_STYLE_STRICT = 3;
+
+ /** @hide */
+ @IntDef(prefix = { "LINE_BREAK_STYLE_" }, value = {
+ LINE_BREAK_STYLE_NONE, LINE_BREAK_STYLE_LOOSE, LINE_BREAK_STYLE_NORMAL,
+ LINE_BREAK_STYLE_STRICT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface LineBreakStyle {}
+
+ private @LineBreakStyle int mLineBreakStyle = LINE_BREAK_STYLE_NONE;
+
+ public LineBreakConfig() {
+ }
+
+ /**
+ * Set the line break configuration.
+ *
+ * @param config the new line break configuration.
+ */
+ public void set(@Nullable LineBreakConfig config) {
+ if (config != null) {
+ mLineBreakStyle = config.getLineBreakStyle();
+ } else {
+ mLineBreakStyle = LineBreakConfig.LINE_BREAK_STYLE_NONE;
+ }
+ }
+
+ /**
+ * Get the line break style.
+ *
+ * @return The current line break style to be used for the text wrapping.
+ */
+ public @LineBreakStyle int getLineBreakStyle() {
+ return mLineBreakStyle;
+ }
+
+ /**
+ * Set the line break style.
+ *
+ * @param lineBreakStyle the new line break style.
+ */
+ public void setLineBreakStyle(@LineBreakStyle int lineBreakStyle) {
+ mLineBreakStyle = lineBreakStyle;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == null) return false;
+ if (this == o) return true;
+ if (!(o instanceof LineBreakConfig)) return false;
+ LineBreakConfig that = (LineBreakConfig) o;
+ return mLineBreakStyle == that.mLineBreakStyle;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mLineBreakStyle);
+ }
+}
diff --git a/graphics/java/android/graphics/text/MeasuredText.java b/graphics/java/android/graphics/text/MeasuredText.java
index a34d0ab..5f4afb7 100644
--- a/graphics/java/android/graphics/text/MeasuredText.java
+++ b/graphics/java/android/graphics/text/MeasuredText.java
@@ -239,11 +239,33 @@
*/
public @NonNull Builder appendStyleRun(@NonNull Paint paint, @IntRange(from = 0) int length,
boolean isRtl) {
+ return appendStyleRun(paint, null, length, isRtl);
+ }
+
+ /**
+ * Apply styles to the given length.
+ *
+ * Keeps an internal offset which increases at every append. The initial value for this
+ * offset is zero. After the style is applied the internal offset is moved to {@code offset
+ * + length}, and next call will start from this new position.
+ *
+ * @param paint a paint
+ * @param lineBreakConfig a line break configuration.
+ * @param length a length to be applied with a given paint, can not exceed the length of the
+ * text
+ * @param isRtl true if the text is in RTL context, otherwise false.
+ */
+ public @NonNull Builder appendStyleRun(@NonNull Paint paint,
+ @Nullable LineBreakConfig lineBreakConfig, @IntRange(from = 0) int length,
+ boolean isRtl) {
Preconditions.checkNotNull(paint);
Preconditions.checkArgument(length > 0, "length can not be negative");
final int end = mCurrentOffset + length;
Preconditions.checkArgument(end <= mText.length, "Style exceeds the text length");
- nAddStyleRun(mNativePtr, paint.getNativeInstance(), mCurrentOffset, end, isRtl);
+ int lbStyle = (lineBreakConfig != null) ? lineBreakConfig.getLineBreakStyle() :
+ LineBreakConfig.LINE_BREAK_STYLE_NONE;
+ nAddStyleRun(mNativePtr, paint.getNativeInstance(), lbStyle, mCurrentOffset, end,
+ isRtl);
mCurrentOffset = end;
return this;
}
@@ -423,12 +445,14 @@
*
* @param nativeBuilderPtr The native MeasuredParagraph builder pointer.
* @param paintPtr The native paint pointer to be applied.
+ * @param lineBreakStyle The line break style of the text.
* @param start The start offset in the copied buffer.
* @param end The end offset in the copied buffer.
* @param isRtl True if the text is RTL.
*/
private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr,
/* Non Zero */ long paintPtr,
+ int lineBreakStyle,
@IntRange(from = 0) int start,
@IntRange(from = 0) int end,
boolean isRtl);
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 919a93b..05fb4c3 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
+import android.security.keystore.KeyProperties;
import android.security.maintenance.IKeystoreMaintenance;
import android.system.keystore2.Domain;
import android.system.keystore2.KeyDescriptor;
@@ -157,6 +158,11 @@
* Migrates a key given by the source descriptor to the location designated by the destination
* descriptor.
*
+ * If Domain::APP is selected in either source or destination, nspace must be set to
+ * {@link KeyProperties#NAMESPACE_APPLICATION}, implying the caller's UID.
+ * If the caller has the MIGRATE_ANY_KEY permission, Domain::APP may be used with
+ * other nspace values which then indicates the UID of a different application.
+ *
* @param source - The key to migrate may be specified by Domain.APP, Domain.SELINUX, or
* Domain.KEY_ID. The caller needs the permissions use, delete, and grant for the
* source namespace.
@@ -183,4 +189,20 @@
return SYSTEM_ERROR;
}
}
+
+ /**
+ * @see IKeystoreMaintenance#listEntries(int, long)
+ */
+ @Nullable
+ public static KeyDescriptor[] listEntries(int domain, long nspace) {
+ try {
+ return getService().listEntries(domain, nspace);
+ } catch (ServiceSpecificException e) {
+ Log.e(TAG, "listEntries failed", e);
+ return null;
+ } catch (Exception e) {
+ Log.e(TAG, "Can not connect to keystore", e);
+ return null;
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 0aa8d7e..8664d9b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -44,6 +44,7 @@
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
+import android.window.WindowContainerTransactionCallback;
import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
@@ -66,28 +67,26 @@
DismissTransition mPendingDismiss = null;
IBinder mPendingEnter = null;
+ IBinder mPendingRecent = null;
private IBinder mAnimatingTransition = null;
private OneShotRemoteHandler mRemoteHandler = null;
- private Transitions.TransitionFinishCallback mRemoteFinishCB = (wct, wctCB) -> {
- if (wct != null || wctCB != null) {
- throw new UnsupportedOperationException("finish transactions not supported yet.");
- }
- onFinish();
- };
+ private final Transitions.TransitionFinishCallback mRemoteFinishCB = this::onFinish;
/** Keeps track of currently running animations */
private final ArrayList<Animator> mAnimations = new ArrayList<>();
+ private final StageCoordinator mStageCoordinator;
private Transitions.TransitionFinishCallback mFinishCallback = null;
private SurfaceControl.Transaction mFinishTransaction;
SplitScreenTransitions(@NonNull TransactionPool pool, @NonNull Transitions transitions,
- @NonNull Runnable onFinishCallback) {
+ @NonNull Runnable onFinishCallback, StageCoordinator stageCoordinator) {
mTransactionPool = pool;
mTransitions = transitions;
mOnFinish = onFinishCallback;
+ mStageCoordinator = stageCoordinator;
}
void playAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@@ -166,7 +165,7 @@
}
}
t.apply();
- onFinish();
+ onFinish(null /* wct */, null /* wctCB */);
}
/** Starts a transition to enter split with a remote transition animator. */
@@ -203,7 +202,26 @@
return transition;
}
- void onFinish() {
+ IBinder startRecentTransition(@Nullable IBinder transition, WindowContainerTransaction wct,
+ Transitions.TransitionHandler handler, @Nullable RemoteTransition remoteTransition) {
+ if (transition == null) {
+ transition = mTransitions.startTransition(TRANSIT_OPEN, wct, handler);
+ }
+ mPendingRecent = transition;
+
+ if (remoteTransition != null) {
+ // Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
+ mRemoteHandler = new OneShotRemoteHandler(
+ mTransitions.getMainExecutor(), remoteTransition);
+ mRemoteHandler.setTransition(transition);
+ }
+
+ ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " splitTransition "
+ + " deduced Enter recent panel");
+ return transition;
+ }
+
+ void onFinish(WindowContainerTransaction wct, WindowContainerTransactionCallback wctCB) {
if (!mAnimations.isEmpty()) return;
mOnFinish.run();
if (mFinishTransaction != null) {
@@ -211,14 +229,23 @@
mTransactionPool.release(mFinishTransaction);
mFinishTransaction = null;
}
- mFinishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
- mFinishCallback = null;
+ if (mFinishCallback != null) {
+ mFinishCallback.onTransitionFinished(wct /* wct */, wctCB /* wctCB */);
+ mFinishCallback = null;
+ }
if (mAnimatingTransition == mPendingEnter) {
mPendingEnter = null;
}
if (mPendingDismiss != null && mPendingDismiss.mTransition == mAnimatingTransition) {
mPendingDismiss = null;
}
+ if (mAnimatingTransition == mPendingRecent) {
+ // If the wct is not null while finishing recent transition, it indicates it's not
+ // returning to home and hence needing the wct to reorder tasks.
+ final boolean toHome = wct == null;
+ mStageCoordinator.finishRecentAnimation(toHome);
+ mPendingRecent = null;
+ }
mAnimatingTransition = null;
}
@@ -240,7 +267,7 @@
mTransactionPool.release(transaction);
mTransitions.getMainExecutor().execute(() -> {
mAnimations.remove(va);
- onFinish();
+ onFinish(null /* wct */, null /* wctCB */);
});
};
va.addListener(new Animator.AnimatorListener() {
@@ -288,7 +315,7 @@
mTransactionPool.release(transaction);
mTransitions.getMainExecutor().execute(() -> {
mAnimations.remove(va);
- onFinish();
+ onFinish(null /* wct */, null /* wctCB */);
});
};
va.addListener(new AnimatorListenerAdapter() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 83830ec..c812050 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -20,6 +20,7 @@
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -236,7 +237,7 @@
deviceStateManager.registerCallback(taskOrganizer.getExecutor(),
new DeviceStateManager.FoldStateListener(mContext, this::onFoldedStateChanged));
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
- mOnTransitionAnimationComplete);
+ mOnTransitionAnimationComplete, this);
mDisplayController.addDisplayWindowListener(this);
mDisplayLayout = new DisplayLayout(displayController.getDisplayLayout(displayId));
transitions.addHandler(this);
@@ -266,7 +267,7 @@
mRootTDAOrganizer.registerListener(displayId, this);
mSplitLayout = splitLayout;
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
- mOnTransitionAnimationComplete);
+ mOnTransitionAnimationComplete, this);
mMainUnfoldController = unfoldControllerProvider.get().orElse(null);
mSideUnfoldController = unfoldControllerProvider.get().orElse(null);
mLogger = logger;
@@ -1271,13 +1272,16 @@
final int activityType = triggerTask.getActivityType();
if (activityType == ACTIVITY_TYPE_ASSISTANT) {
// We don't want assistant panel to dismiss split screen, so do nothing.
+ } else if (activityType == ACTIVITY_TYPE_HOME
+ || activityType == ACTIVITY_TYPE_RECENTS) {
+ // Enter overview panel, so start recent transition.
+ mSplitTransitions.startRecentTransition(transition, out, this,
+ request.getRemoteTransition());
} else {
- // Going home or occluded by the other fullscreen task, so dismiss both.
+ // Occluded by the other fullscreen task, so dismiss both.
prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, out);
- final int exitReason = activityType == ACTIVITY_TYPE_HOME
- ? EXIT_REASON_RETURN_HOME : EXIT_REASON_UNKNOWN;
mSplitTransitions.startDismissTransition(transition, out, this,
- STAGE_TYPE_UNDEFINED, exitReason);
+ STAGE_TYPE_UNDEFINED, EXIT_REASON_UNKNOWN);
}
}
} else {
@@ -1307,13 +1311,14 @@
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- if (transition != mSplitTransitions.mPendingEnter && (
- mSplitTransitions.mPendingDismiss == null
+ if (transition != mSplitTransitions.mPendingEnter
+ && transition != mSplitTransitions.mPendingRecent
+ && (mSplitTransitions.mPendingDismiss == null
|| mSplitTransitions.mPendingDismiss.mTransition != transition)) {
// Not entering or exiting, so just do some house-keeping and validation.
// If we're not in split-mode, just abort so something else can handle it.
- if (!isSplitScreenVisible()) return false;
+ if (!mMainStage.isActive()) return false;
for (int iC = 0; iC < info.getChanges().size(); ++iC) {
final TransitionInfo.Change change = info.getChanges().get(iC);
@@ -1356,6 +1361,8 @@
boolean shouldAnimate = true;
if (mSplitTransitions.mPendingEnter == transition) {
shouldAnimate = startPendingEnterAnimation(transition, info, startTransaction);
+ } else if (mSplitTransitions.mPendingRecent == transition) {
+ shouldAnimate = startPendingRecentAnimation(transition, info, startTransaction);
} else if (mSplitTransitions.mPendingDismiss != null
&& mSplitTransitions.mPendingDismiss.mTransition == transition) {
shouldAnimate = startPendingDismissAnimation(
@@ -1500,6 +1507,23 @@
return true;
}
+ private boolean startPendingRecentAnimation(@NonNull IBinder transition,
+ @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction t) {
+ setDividerVisibility(false, t);
+ return true;
+ }
+
+ void finishRecentAnimation(boolean toHome) {
+ if (toHome) {
+ final WindowContainerTransaction wct = new WindowContainerTransaction();
+ prepareExitSplitScreen(STAGE_TYPE_UNDEFINED, wct);
+ mSplitTransitions.startDismissTransition(null /* transition */, wct, this,
+ STAGE_TYPE_UNDEFINED, EXIT_REASON_RETURN_HOME);
+ } else {
+ setDividerVisibility(true, null /* t */);
+ }
+ }
+
private void addDividerBarToTransition(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, boolean show) {
final SurfaceControl leash = mSplitLayout.getDividerLeash();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
index 11b2387..5054e60 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultTransitionHandler.java
@@ -291,8 +291,7 @@
finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
};
- boolean requireBackgroundForTransition = false;
-
+ @ColorInt int backgroundColorForTransition = 0;
final int wallpaperTransit = getWallpaperTransitType(info);
for (int i = info.getChanges().size() - 1; i >= 0; --i) {
final TransitionInfo.Change change = info.getChanges().get(i);
@@ -352,8 +351,19 @@
Animation a = loadAnimation(info, change, wallpaperTransit);
if (a != null) {
- if (changeRequiresBackground(info, change)) {
- requireBackgroundForTransition = true;
+ if (isTask) {
+ final @TransitionType int type = info.getType();
+ final boolean isOpenOrCloseTransition = type == TRANSIT_OPEN
+ || type == TRANSIT_CLOSE
+ || type == TRANSIT_TO_FRONT
+ || type == TRANSIT_TO_BACK;
+ if (isOpenOrCloseTransition) {
+ // Use the overview background as the background for the animation
+ final Context uiContext = ActivityThread.currentActivityThread()
+ .getSystemUiContext();
+ backgroundColorForTransition =
+ uiContext.getColor(R.color.overview_background);
+ }
}
float cornerRadius = 0;
@@ -365,6 +375,15 @@
ScreenDecorationsUtils.getWindowCornerRadius(displayContext);
}
+ if (a.getShowBackground()) {
+ // use the window's background color if provided as the background color for the
+ // animation - the top most window with a valid background color and
+ // showBackground set takes precedence.
+ if (change.getBackgroundColor() != 0) {
+ backgroundColorForTransition = change.getBackgroundColor();
+ }
+ }
+
startSurfaceAnimation(animations, a, change.getLeash(), onAnimFinish,
mTransactionPool, mMainExecutor, mAnimExecutor, null /* position */,
cornerRadius, change.getEndAbsBounds());
@@ -376,8 +395,9 @@
}
}
- if (requireBackgroundForTransition) {
- addBackgroundToTransition(info.getRootLeash(), startTransaction, finishTransaction);
+ if (backgroundColorForTransition != 0) {
+ addBackgroundToTransition(info.getRootLeash(), backgroundColorForTransition,
+ startTransaction, finishTransaction);
}
startTransaction.apply();
@@ -388,24 +408,13 @@
return true;
}
- private boolean changeRequiresBackground(TransitionInfo info,
- TransitionInfo.Change change) {
- final boolean isTask = change.getTaskInfo() != null;
- final @TransitionType int type = info.getType();
- final boolean isOpenOrCloseTransition = type == TRANSIT_OPEN || type == TRANSIT_CLOSE
- || type == TRANSIT_TO_FRONT || type == TRANSIT_TO_BACK;
- return isTask && isOpenOrCloseTransition;
- }
-
private void addBackgroundToTransition(
@NonNull SurfaceControl rootLeash,
+ @ColorInt int color,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction
) {
- final Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();
- final @ColorInt int overviewBackgroundColor =
- uiContext.getColor(R.color.overview_background);
- final Color bgColor = Color.valueOf(overviewBackgroundColor);
+ final Color bgColor = Color.valueOf(color);
final float[] colorArray = new float[] { bgColor.red(), bgColor.green(), bgColor.blue() };
final SurfaceControl animationBackgroundSurface = new SurfaceControl.Builder()
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/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index ea94cf0..59c377a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -251,7 +251,7 @@
}
@Test
- public void testDismissToHome() {
+ public void testEnterRecents() {
enterSplit();
ActivityManager.RunningTaskInfo homeTask = new TestRunningTaskInfoBuilder()
@@ -264,7 +264,7 @@
IBinder transition = mock(IBinder.class);
WindowContainerTransaction result = mStageCoordinator.handleRequest(transition, request);
- assertTrue(containsSplitExit(result));
+ assertTrue(result.isEmpty());
// make sure we haven't made any local changes yet (need to wait until transition is ready)
assertTrue(mStageCoordinator.isSplitScreenVisible());
@@ -284,7 +284,7 @@
mock(SurfaceControl.Transaction.class),
mock(SurfaceControl.Transaction.class),
mock(Transitions.TransitionFinishCallback.class));
- assertFalse(mStageCoordinator.isSplitScreenVisible());
+ assertTrue(mStageCoordinator.isSplitScreenVisible());
}
@Test
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/libs/hwui/jni/text/MeasuredText.cpp b/libs/hwui/jni/text/MeasuredText.cpp
index bd9bd71..09539ec 100644
--- a/libs/hwui/jni/text/MeasuredText.cpp
+++ b/libs/hwui/jni/text/MeasuredText.cpp
@@ -65,11 +65,11 @@
// Regular JNI
static void nAddStyleRun(JNIEnv* /* unused */, jclass /* unused */, jlong builderPtr,
- jlong paintPtr, jint start, jint end, jboolean isRtl) {
+ jlong paintPtr, jint lbStyle, jint start, jint end, jboolean isRtl) {
Paint* paint = toPaint(paintPtr);
const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
- toBuilder(builderPtr)->addStyleRun(start, end, std::move(minikinPaint), isRtl);
+ toBuilder(builderPtr)->addStyleRun(start, end, std::move(minikinPaint), lbStyle, isRtl);
}
// Regular JNI
@@ -144,7 +144,7 @@
static const JNINativeMethod gMTBuilderMethods[] = {
// MeasuredParagraphBuilder native functions.
{"nInitBuilder", "()J", (void*)nInitBuilder},
- {"nAddStyleRun", "(JJIIZ)V", (void*)nAddStyleRun},
+ {"nAddStyleRun", "(JJIIIZ)V", (void*)nAddStyleRun},
{"nAddReplacementRun", "(JJIIF)V", (void*)nAddReplacementRun},
{"nBuildMeasuredText", "(JJ[CZZZ)J", (void*)nBuildMeasuredText},
{"nFreeBuilder", "(J)V", (void*)nFreeBuilder},
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 55f932d..6c0fd5f 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -55,6 +55,7 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-Wthread-safety",
],
}
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index f43586f..1dc74e5 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -18,11 +18,13 @@
//#define LOG_NDEBUG 0
#include "PointerController.h"
-#include "PointerControllerContext.h"
#include <SkBlendMode.h>
#include <SkCanvas.h>
#include <SkColor.h>
+#include <android-base/thread_annotations.h>
+
+#include "PointerControllerContext.h"
namespace android {
@@ -36,8 +38,18 @@
void PointerController::DisplayInfoListener::onWindowInfosChanged(
const std::vector<android::gui::WindowInfo>&,
- const std::vector<android::gui::DisplayInfo>& displayInfo) {
- mPointerController.onDisplayInfosChanged(displayInfo);
+ const std::vector<android::gui::DisplayInfo>& displayInfos) {
+ std::scoped_lock lock(mLock);
+ if (mPointerController == nullptr) return;
+
+ // PointerController uses DisplayInfoListener's lock.
+ base::ScopedLockAssertion assumeLocked(mPointerController->getLock());
+ mPointerController->onDisplayInfosChangedLocked(displayInfos);
+}
+
+void PointerController::DisplayInfoListener::onPointerControllerDestroyed() {
+ std::scoped_lock lock(mLock);
+ mPointerController = nullptr;
}
// --- PointerController ---
@@ -68,16 +80,36 @@
PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
const sp<Looper>& looper,
const sp<SpriteController>& spriteController)
+ : PointerController(
+ policy, looper, spriteController,
+ [](const sp<android::gui::WindowInfosListener>& listener) {
+ SurfaceComposerClient::getDefault()->addWindowInfosListener(listener);
+ },
+ [](const sp<android::gui::WindowInfosListener>& listener) {
+ SurfaceComposerClient::getDefault()->removeWindowInfosListener(listener);
+ }) {}
+
+PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy,
+ const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController,
+ WindowListenerConsumer registerListener,
+ WindowListenerConsumer unregisterListener)
: mContext(policy, looper, spriteController, *this),
mCursorController(mContext),
- mDisplayInfoListener(new DisplayInfoListener(*this)) {
- std::scoped_lock lock(mLock);
+ mDisplayInfoListener(new DisplayInfoListener(this)),
+ mUnregisterWindowInfosListener(std::move(unregisterListener)) {
+ std::scoped_lock lock(getLock());
mLocked.presentation = Presentation::SPOT;
- SurfaceComposerClient::getDefault()->addWindowInfosListener(mDisplayInfoListener);
+ registerListener(mDisplayInfoListener);
}
PointerController::~PointerController() {
- SurfaceComposerClient::getDefault()->removeWindowInfosListener(mDisplayInfoListener);
+ mDisplayInfoListener->onPointerControllerDestroyed();
+ mUnregisterWindowInfosListener(mDisplayInfoListener);
+}
+
+std::mutex& PointerController::getLock() const {
+ return mDisplayInfoListener->mLock;
}
bool PointerController::getBounds(float* outMinX, float* outMinY, float* outMaxX,
@@ -89,7 +121,7 @@
const int32_t displayId = mCursorController.getDisplayId();
vec2 transformed;
{
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
const auto& transform = getTransformForDisplayLocked(displayId);
transformed = transformWithoutTranslation(transform, {deltaX, deltaY});
}
@@ -108,7 +140,7 @@
const int32_t displayId = mCursorController.getDisplayId();
vec2 transformed;
{
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
const auto& transform = getTransformForDisplayLocked(displayId);
transformed = transform.transform(x, y);
}
@@ -119,7 +151,7 @@
const int32_t displayId = mCursorController.getDisplayId();
mCursorController.getPosition(outX, outY);
{
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
const auto& transform = getTransformForDisplayLocked(displayId);
const auto xy = transform.inverse().transform(*outX, *outY);
*outX = xy.x;
@@ -132,17 +164,17 @@
}
void PointerController::fade(Transition transition) {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
mCursorController.fade(transition);
}
void PointerController::unfade(Transition transition) {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
mCursorController.unfade(transition);
}
void PointerController::setPresentation(Presentation presentation) {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
if (mLocked.presentation == presentation) {
return;
@@ -162,7 +194,7 @@
void PointerController::setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex,
BitSet32 spotIdBits, int32_t displayId) {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
std::array<PointerCoords, MAX_POINTERS> outSpotCoords{};
const ui::Transform& transform = getTransformForDisplayLocked(displayId);
@@ -185,11 +217,11 @@
}
void PointerController::clearSpots() {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
clearSpotsLocked();
}
-void PointerController::clearSpotsLocked() REQUIRES(mLock) {
+void PointerController::clearSpotsLocked() {
for (auto& [displayID, spotController] : mLocked.spotControllers) {
spotController.clearSpots();
}
@@ -200,7 +232,7 @@
}
void PointerController::reloadPointerResources() {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
for (auto& [displayID, spotController] : mLocked.spotControllers) {
spotController.reloadSpotResources();
@@ -216,7 +248,7 @@
}
void PointerController::setDisplayViewport(const DisplayViewport& viewport) {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
bool getAdditionalMouseResources = false;
if (mLocked.presentation == PointerController::Presentation::POINTER) {
@@ -226,12 +258,12 @@
}
void PointerController::updatePointerIcon(int32_t iconId) {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
mCursorController.updatePointerIcon(iconId);
}
void PointerController::setCustomPointerIcon(const SpriteIcon& icon) {
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
mCursorController.setCustomPointerIcon(icon);
}
@@ -245,7 +277,7 @@
displayIdSet.insert(viewport.displayId);
}
- std::scoped_lock lock(mLock);
+ std::scoped_lock lock(getLock());
for (auto it = mLocked.spotControllers.begin(); it != mLocked.spotControllers.end();) {
int32_t displayID = it->first;
if (!displayIdSet.count(displayID)) {
@@ -261,8 +293,8 @@
}
}
-void PointerController::onDisplayInfosChanged(const std::vector<gui::DisplayInfo>& displayInfo) {
- std::scoped_lock lock(mLock);
+void PointerController::onDisplayInfosChangedLocked(
+ const std::vector<gui::DisplayInfo>& displayInfo) {
mLocked.mDisplayInfos = displayInfo;
}
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 796077f..2e6e851 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -72,13 +72,31 @@
void reloadPointerResources();
void onDisplayViewportsUpdated(std::vector<DisplayViewport>& viewports);
- void onDisplayInfosChanged(const std::vector<gui::DisplayInfo>& displayInfos);
+ void onDisplayInfosChangedLocked(const std::vector<gui::DisplayInfo>& displayInfos)
+ REQUIRES(getLock());
+
+protected:
+ using WindowListenerConsumer =
+ std::function<void(const sp<android::gui::WindowInfosListener>&)>;
+
+ // Constructor used to test WindowInfosListener registration.
+ PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController,
+ WindowListenerConsumer registerListener,
+ WindowListenerConsumer unregisterListener);
private:
+ PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController);
+
friend PointerControllerContext::LooperCallback;
friend PointerControllerContext::MessageHandler;
- mutable std::mutex mLock;
+ // PointerController's DisplayInfoListener can outlive the PointerController because when the
+ // listener is registered, a strong pointer to the listener (which can extend its lifecycle)
+ // is given away. To avoid the small overhead of using two separate locks in these two objects,
+ // we use the DisplayInfoListener's lock in PointerController.
+ std::mutex& getLock() const;
PointerControllerContext mContext;
@@ -89,24 +107,28 @@
std::vector<gui::DisplayInfo> mDisplayInfos;
std::unordered_map<int32_t /* displayId */, TouchSpotController> spotControllers;
- } mLocked GUARDED_BY(mLock);
+ } mLocked GUARDED_BY(getLock());
class DisplayInfoListener : public gui::WindowInfosListener {
public:
- explicit DisplayInfoListener(PointerController& pc) : mPointerController(pc){};
+ explicit DisplayInfoListener(PointerController* pc) : mPointerController(pc){};
void onWindowInfosChanged(const std::vector<android::gui::WindowInfo>&,
const std::vector<android::gui::DisplayInfo>&) override;
+ void onPointerControllerDestroyed();
+
+ // This lock is also used by PointerController. See PointerController::getLock().
+ std::mutex mLock;
private:
- PointerController& mPointerController;
+ PointerController* mPointerController GUARDED_BY(mLock);
};
+
sp<DisplayInfoListener> mDisplayInfoListener;
+ const WindowListenerConsumer mUnregisterWindowInfosListener;
- const ui::Transform& getTransformForDisplayLocked(int displayId) const REQUIRES(mLock);
+ const ui::Transform& getTransformForDisplayLocked(int displayId) const REQUIRES(getLock());
- PointerController(const sp<PointerControllerPolicyInterface>& policy, const sp<Looper>& looper,
- const sp<SpriteController>& spriteController);
- void clearSpotsLocked();
+ void clearSpotsLocked() REQUIRES(getLock());
};
} // namespace android
diff --git a/libs/input/tests/PointerController_test.cpp b/libs/input/tests/PointerController_test.cpp
index b67088a..dae1fcc 100644
--- a/libs/input/tests/PointerController_test.cpp
+++ b/libs/input/tests/PointerController_test.cpp
@@ -255,4 +255,36 @@
ensureDisplayViewportIsSet();
}
+class PointerControllerWindowInfoListenerTest : public Test {};
+
+class TestPointerController : public PointerController {
+public:
+ TestPointerController(sp<android::gui::WindowInfosListener>& registeredListener,
+ const sp<Looper>& looper)
+ : PointerController(
+ new MockPointerControllerPolicyInterface(), looper,
+ new NiceMock<MockSpriteController>(looper),
+ [®isteredListener](const sp<android::gui::WindowInfosListener>& listener) {
+ // Register listener
+ registeredListener = listener;
+ },
+ [®isteredListener](const sp<android::gui::WindowInfosListener>& listener) {
+ // Unregister listener
+ if (registeredListener == listener) registeredListener = nullptr;
+ }) {}
+};
+
+TEST_F(PointerControllerWindowInfoListenerTest,
+ doesNotCrashIfListenerCalledAfterPointerControllerDestroyed) {
+ sp<android::gui::WindowInfosListener> registeredListener;
+ sp<android::gui::WindowInfosListener> localListenerCopy;
+ {
+ TestPointerController pointerController(registeredListener, new Looper(false));
+ ASSERT_NE(nullptr, registeredListener) << "WindowInfosListener was not registered";
+ localListenerCopy = registeredListener;
+ }
+ EXPECT_EQ(nullptr, registeredListener) << "WindowInfosListener was not unregistered";
+ localListenerCopy->onWindowInfosChanged({}, {});
+}
+
} // namespace android
diff --git a/libs/usb/tests/accessorytest/f_accessory.h b/libs/usb/tests/accessorytest/f_accessory.h
index 312f4ba..75e017c 100644
--- a/libs/usb/tests/accessorytest/f_accessory.h
+++ b/libs/usb/tests/accessorytest/f_accessory.h
@@ -1,148 +1,53 @@
-/*
- * Gadget Function Driver for Android USB accessories
- *
- * Copyright (C) 2011 Google, Inc.
- * Author: Mike Lockwood <lockwood@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef __LINUX_USB_F_ACCESSORY_H
-#define __LINUX_USB_F_ACCESSORY_H
-
-/* Use Google Vendor ID when in accessory mode */
+/****************************************************************************
+ ****************************************************************************
+ ***
+ *** This header was automatically generated from a Linux kernel header
+ *** of the same name, to make information necessary for userspace to
+ *** call into the kernel available to libc. It contains only constants,
+ *** structures, and macros generated from the original header, and thus,
+ *** contains no copyrightable information.
+ ***
+ *** To edit the content of this header, modify the corresponding
+ *** source file (e.g. under external/kernel-headers/original/) then
+ *** run bionic/libc/kernel/tools/update_all.py
+ ***
+ *** Any manual change here will be lost the next time this script will
+ *** be run. You've been warned!
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _UAPI_LINUX_USB_F_ACCESSORY_H
+#define _UAPI_LINUX_USB_F_ACCESSORY_H
#define USB_ACCESSORY_VENDOR_ID 0x18D1
-
-
-/* Product ID to use when in accessory mode */
#define USB_ACCESSORY_PRODUCT_ID 0x2D00
-
-/* Product ID to use when in accessory mode and adb is enabled */
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
#define USB_ACCESSORY_ADB_PRODUCT_ID 0x2D01
-
-/* Indexes for strings sent by the host via ACCESSORY_SEND_STRING */
-#define ACCESSORY_STRING_MANUFACTURER 0
-#define ACCESSORY_STRING_MODEL 1
-#define ACCESSORY_STRING_DESCRIPTION 2
-#define ACCESSORY_STRING_VERSION 3
-#define ACCESSORY_STRING_URI 4
-#define ACCESSORY_STRING_SERIAL 5
-
-/* Control request for retrieving device's protocol version
- *
- * requestType: USB_DIR_IN | USB_TYPE_VENDOR
- * request: ACCESSORY_GET_PROTOCOL
- * value: 0
- * index: 0
- * data version number (16 bits little endian)
- * 1 for original accessory support
- * 2 adds audio and HID support
- */
-#define ACCESSORY_GET_PROTOCOL 51
-
-/* Control request for host to send a string to the device
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_SEND_STRING
- * value: 0
- * index: string ID
- * data zero terminated UTF8 string
- *
- * The device can later retrieve these strings via the
- * ACCESSORY_GET_STRING_* ioctls
- */
-#define ACCESSORY_SEND_STRING 52
-
-/* Control request for starting device in accessory mode.
- * The host sends this after setting all its strings to the device.
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_START
- * value: 0
- * index: 0
- * data none
- */
-#define ACCESSORY_START 53
-
-/* Control request for registering a HID device.
- * Upon registering, a unique ID is sent by the accessory in the
- * value parameter. This ID will be used for future commands for
- * the device
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_REGISTER_HID_DEVICE
- * value: Accessory assigned ID for the HID device
- * index: total length of the HID report descriptor
- * data none
- */
-#define ACCESSORY_REGISTER_HID 54
-
-/* Control request for unregistering a HID device.
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_REGISTER_HID
- * value: Accessory assigned ID for the HID device
- * index: 0
- * data none
- */
-#define ACCESSORY_UNREGISTER_HID 55
-
-/* Control request for sending the HID report descriptor.
- * If the HID descriptor is longer than the endpoint zero max packet size,
- * the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
- * commands. The data for the descriptor must be sent sequentially
- * if multiple packets are needed.
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_SET_HID_REPORT_DESC
- * value: Accessory assigned ID for the HID device
- * index: offset of data in descriptor
- * (needed when HID descriptor is too big for one packet)
- * data the HID report descriptor
- */
-#define ACCESSORY_SET_HID_REPORT_DESC 56
-
-/* Control request for sending HID events.
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_SEND_HID_EVENT
- * value: Accessory assigned ID for the HID device
- * index: 0
- * data the HID report for the event
- */
-#define ACCESSORY_SEND_HID_EVENT 57
-
-/* Control request for setting the audio mode.
- *
- * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
- * request: ACCESSORY_SET_AUDIO_MODE
- * value: 0 - no audio
- * 1 - device to host, 44100 16-bit stereo PCM
- * index: 0
- * data the HID report for the event
- */
-#define ACCESSORY_SET_AUDIO_MODE 58
-
-
-
-/* ioctls for retrieving strings set by the host */
-#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256])
-#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256])
-#define ACCESSORY_GET_STRING_DESCRIPTION _IOW('M', 3, char[256])
-#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256])
-#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[256])
-#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256])
-/* returns 1 if there is a start request pending */
-#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
-/* returns audio mode (set via the ACCESSORY_SET_AUDIO_MODE control request) */
-#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8)
-
-#endif /* __LINUX_USB_F_ACCESSORY_H */
+#define ACCESSORY_STRING_MANUFACTURER 0
+#define ACCESSORY_STRING_MODEL 1
+#define ACCESSORY_STRING_DESCRIPTION 2
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ACCESSORY_STRING_VERSION 3
+#define ACCESSORY_STRING_URI 4
+#define ACCESSORY_STRING_SERIAL 5
+#define ACCESSORY_GET_PROTOCOL 51
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ACCESSORY_SEND_STRING 52
+#define ACCESSORY_START 53
+#define ACCESSORY_REGISTER_HID 54
+#define ACCESSORY_UNREGISTER_HID 55
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ACCESSORY_SET_HID_REPORT_DESC 56
+#define ACCESSORY_SEND_HID_EVENT 57
+#define ACCESSORY_SET_AUDIO_MODE 58
+#define ACCESSORY_GET_STRING_MANUFACTURER _IOW('M', 1, char[256])
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ACCESSORY_GET_STRING_MODEL _IOW('M', 2, char[256])
+#define ACCESSORY_GET_STRING_DESCRIPTION _IOW('M', 3, char[256])
+#define ACCESSORY_GET_STRING_VERSION _IOW('M', 4, char[256])
+#define ACCESSORY_GET_STRING_URI _IOW('M', 5, char[256])
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
+#define ACCESSORY_GET_STRING_SERIAL _IOW('M', 6, char[256])
+#define ACCESSORY_IS_START_REQUESTED _IO('M', 7)
+#define ACCESSORY_GET_AUDIO_MODE _IO('M', 8)
+#endif
+/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */
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/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
index 032bc3f..1af32bf 100644
--- a/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
+++ b/packages/ConnectivityT/framework-t/src/android/net/TrafficStats.java
@@ -282,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/PrintSpooler/Android.bp b/packages/PrintSpooler/Android.bp
index 772c69f..6af3c66 100644
--- a/packages/PrintSpooler/Android.bp
+++ b/packages/PrintSpooler/Android.bp
@@ -34,18 +34,23 @@
android_app {
name: "PrintSpooler",
defaults: ["platform_app_defaults"],
+ resource_dirs: [],
+ platform_apis: true,
+ jni_libs: ["libprintspooler_jni"],
+ static_libs: [
+ "PrintSpoolerLib",
+ ],
+}
+android_library {
+ name: "PrintSpoolerLib",
resource_dirs: ["res"],
-
srcs: [
"src/**/*.java",
"src/com/android/printspooler/renderer/IPdfRenderer.aidl",
"src/com/android/printspooler/renderer/IPdfEditor.aidl",
],
-
platform_apis: true,
-
- jni_libs: ["libprintspooler_jni"],
static_libs: [
"android-support-v7-recyclerview",
"android-support-compat",
@@ -55,4 +60,5 @@
"android-support-fragment",
"android-support-annotations",
],
+ manifest: "AndroidManifest.xml",
}
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
index cf73aac..0c4cb8e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java
@@ -314,16 +314,15 @@
@Override
public boolean onContextItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.string.print_select_printer: {
- PrinterInfo printer = item.getIntent().getParcelableExtra(EXTRA_PRINTER);
- onPrinterSelected(printer);
- } return true;
-
- case R.string.print_forget_printer: {
- PrinterId printerId = item.getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
- mPrinterRegistry.forgetFavoritePrinter(printerId);
- } return true;
+ final int itemId = item.getItemId();
+ if (itemId == R.string.print_select_printer) {
+ PrinterInfo printer = item.getIntent().getParcelableExtra(EXTRA_PRINTER);
+ onPrinterSelected(printer);
+ return true;
+ } else if (itemId == R.string.print_forget_printer) {
+ PrinterId printerId = item.getIntent().getParcelableExtra(EXTRA_PRINTER_ID);
+ mPrinterRegistry.forgetFavoritePrinter(printerId);
+ return true;
}
return false;
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 47b0744..f9ac01d 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1271,10 +1271,13 @@
<string name="wifi_status_mac_randomized">MAC is randomized</string>
<!-- Summary to show how many devices are connected in wifi hotspot [CHAR LIMIT=NONE] -->
- <plurals name="wifi_tether_connected_summary">
- <item quantity="one">%1$d device connected</item>
- <item quantity="other">%1$d devices connected</item>
- </plurals>
+ <string name="wifi_tether_connected_summary">
+ {count, plural,
+ =0 {0 device connected}
+ =1 {1 device connected}
+ other {# devices connected}
+ }
+ </string>
<!-- Content description of zen mode time condition plus button (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_manual_zen_more_time">More time.</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
index 56454e9..4ab6542 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.icu.text.MessageFormat;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
@@ -33,6 +34,8 @@
import com.android.settingslib.R;
+import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
public class WifiUtils {
@@ -333,4 +336,20 @@
intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, bundle);
return intent;
}
+
+ /**
+ * Returns the string of Wi-Fi tethering summary for connected devices.
+ *
+ * @param context The application context
+ * @param connectedDevices The count of connected devices
+ */
+ public static String getWifiTetherSummaryForConnectedDevices(Context context,
+ int connectedDevices) {
+ MessageFormat msgFormat = new MessageFormat(
+ context.getResources().getString(R.string.wifi_tether_connected_summary),
+ Locale.getDefault());
+ Map<String, Object> arguments = new HashMap<>();
+ arguments.put("count", connectedDevices);
+ return msgFormat.format(arguments);
+ }
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8546b16..c1a812f 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -623,6 +623,13 @@
<!-- Permission required for CTS test - Notification test suite -->
<uses-permission android:name="android.permission.REVOKE_POST_NOTIFICATIONS_WITHOUT_KILL" />
+ <!-- Permission required for CTS test - CommunalManagerTest -->
+ <uses-permission android:name="android.permission.WRITE_COMMUNAL_STATE" />
+ <uses-permission android:name="android.permission.READ_COMMUNAL_STATE" />
+
+ <!-- Permission required for CTS test - CaptioningManagerTest -->
+ <uses-permission android:name="android.permission.SET_SYSTEM_AUDIO_CAPTION" />
+
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e9e85f1..92ae92e 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -150,9 +150,6 @@
<uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
<uses-permission android:name="android.permission.GET_RUNTIME_PERMISSIONS" />
- <!-- Communal mode -->
- <uses-permission android:name="android.permission.WRITE_COMMUNAL_STATE" />
-
<!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index e69582f..f72a8dc 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -378,7 +378,8 @@
android:clickable="true"/>
</LinearLayout>
</LinearLayout>
- <FrameLayout
+
+ <LinearLayout
android:id="@+id/button_layout"
android:orientation="horizontal"
android:layout_width="match_parent"
@@ -390,9 +391,10 @@
android:clickable="false"
android:focusable="false">
- <FrameLayout
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:layout_gravity="start|center_vertical"
android:orientation="vertical">
<Button
@@ -401,12 +403,13 @@
android:layout_height="wrap_content"
android:text="@string/turn_off_airplane_mode"
android:ellipsize="end"
+ android:maxLines="1"
style="@style/Widget.Dialog.Button.BorderButton"
android:clickable="true"
android:focusable="true"/>
- </FrameLayout>
+ </LinearLayout>
- <FrameLayout
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
@@ -417,10 +420,13 @@
android:layout_height="wrap_content"
android:text="@string/inline_done_button"
style="@style/Widget.Dialog.Button"
+ android:maxLines="1"
+ android:ellipsize="end"
android:clickable="true"
android:focusable="true"/>
- </FrameLayout>
- </FrameLayout>
+ </LinearLayout>
+ </LinearLayout>
+
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 9c35fea..65f22b8 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -738,4 +738,6 @@
<!-- Class for the communal source connector to be used -->
<string name="config_communalSourceConnector" translatable="false"></string>
+ <!-- How often in milliseconds to jitter the dream overlay in order to avoid burn-in. -->
+ <integer name="config_dreamOverlayBurnInProtectionUpdateIntervalMillis">500</integer>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 1b52811..ff5699b 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -976,8 +976,9 @@
</style>
<style name="InternetDialog.NetworkSummary">
- <item name="android:layout_marginEnd">34dp</item>
+ <item name="android:layout_marginEnd">7dp</item>
<item name="android:ellipsize">end</item>
+ <item name="android:maxLines">2</item>
<item name="android:textAppearance">@style/TextAppearance.InternetDialog.Secondary</item>
</style>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 72e3e18..4d0c443 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -17,7 +17,6 @@
package com.android.systemui.shared.system;
import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
-import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_BACK;
@@ -140,22 +139,11 @@
// changes should be ordered top-to-bottom in z
final int mode = change.getMode();
- // Don't move anything that isn't independent within its parents
- if (!TransitionInfo.isIndependent(change, info)) {
- if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT || mode == TRANSIT_CHANGE) {
- t.show(leash);
- t.setPosition(leash, change.getEndRelOffset().x, change.getEndRelOffset().y);
- }
- return;
- }
+ // Launcher animates leaf tasks directly, so always reparent all task leashes to root leash.
+ t.reparent(leash, info.getRootLeash());
+ t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
+ change.getStartAbsBounds().top - info.getRootOffset().y);
- boolean hasParent = change.getParent() != null;
-
- if (!hasParent) {
- t.reparent(leash, info.getRootLeash());
- t.setPosition(leash, change.getStartAbsBounds().left - info.getRootOffset().x,
- change.getStartAbsBounds().top - info.getRootOffset().y);
- }
t.show(leash);
// Put all the OPEN/SHOW on top
if (mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT) {
@@ -266,14 +254,15 @@
SurfaceControl.Transaction t, ArrayMap<SurfaceControl, SurfaceControl> leashMap) {
final ArrayList<RemoteAnimationTargetCompat> out = new ArrayList<>();
for (int i = 0; i < info.getChanges().size(); i++) {
- boolean changeIsWallpaper =
- (info.getChanges().get(i).getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ final boolean changeIsWallpaper =
+ (change.getFlags() & TransitionInfo.FLAG_IS_WALLPAPER) != 0;
if (wallpapers != changeIsWallpaper) continue;
- out.add(new RemoteAnimationTargetCompat(info.getChanges().get(i),
- info.getChanges().size() - i, info, t));
- if (leashMap == null) continue;
- leashMap.put(info.getChanges().get(i).getLeash(),
- out.get(out.size() - 1).leash);
+
+ out.add(new RemoteAnimationTargetCompat(change, info.getChanges().size() - i, info, t));
+ if (leashMap != null) {
+ leashMap.put(change.getLeash(), out.get(out.size() - 1).leash);
+ }
}
return out.toArray(new RemoteAnimationTargetCompat[out.size()]);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 5276679..a348b42 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -3294,11 +3294,19 @@
}
public void clearBiometricRecognized() {
+ clearBiometricRecognized(UserHandle.USER_NULL);
+ }
+
+ public void clearBiometricRecognizedWhenKeyguardDone(int unlockedUser) {
+ clearBiometricRecognized(unlockedUser);
+ }
+
+ private void clearBiometricRecognized(int unlockedUser) {
Assert.isMainThread();
mUserFingerprintAuthenticated.clear();
mUserFaceAuthenticated.clear();
- mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT);
- mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE);
+ mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT, unlockedUser);
+ mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, unlockedUser);
for (int i = 0; i < mCallbacks.size(); i++) {
KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalManagerUpdater.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalManagerUpdater.java
deleted file mode 100644
index ebe804a..0000000
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalManagerUpdater.java
+++ /dev/null
@@ -1,67 +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.systemui.communal;
-
-import android.app.communal.CommunalManager;
-import android.content.Context;
-import android.util.Log;
-
-import com.android.systemui.CoreStartable;
-import com.android.systemui.dagger.SysUISingleton;
-
-import java.lang.ref.WeakReference;
-
-import javax.inject.Inject;
-
-/**
- * The {@link CommunalManagerUpdater} is responsible for forwarding state from SystemUI to
- * the {@link CommunalManager} system service.
- */
-@SysUISingleton
-public class CommunalManagerUpdater extends CoreStartable {
- private static final String TAG = "CommunalManagerUpdater";
-
- private final CommunalManager mCommunalManager;
- private final CommunalSourceMonitor mMonitor;
-
- private final CommunalSourceMonitor.Callback mSourceCallback =
- new CommunalSourceMonitor.Callback() {
- @Override
- public void onSourceAvailable(WeakReference<CommunalSource> source) {
- try {
- mCommunalManager.setCommunalViewShowing(
- source != null && source.get() != null);
- } catch (RuntimeException e) {
- Log.e(TAG, "Error updating communal manager service state", e);
- }
- }
- };
-
- @Inject
- public CommunalManagerUpdater(Context context, CommunalSourceMonitor monitor) {
- super(context);
- mCommunalManager = context.getSystemService(CommunalManager.class);
- mMonitor = monitor;
- }
-
- @Override
- public void start() {
- if (mCommunalManager != null) {
- mMonitor.addCallback(mSourceCallback);
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
index 00491da..154f6fa 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIBinder.java
@@ -25,7 +25,6 @@
import com.android.systemui.accessibility.WindowMagnification;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.clipboardoverlay.ClipboardListener;
-import com.android.systemui.communal.CommunalManagerUpdater;
import com.android.systemui.dreams.DreamOverlayRegistrant;
import com.android.systemui.dreams.appwidgets.ComplicationPrimer;
import com.android.systemui.globalactions.GlobalActionsComponent;
@@ -220,11 +219,4 @@
@ClassKey(ComplicationPrimer.class)
public abstract CoreStartable bindAppWidgetOverlayPrimer(
ComplicationPrimer complicationPrimer);
-
- /** Inject into CommunalManagerUpdater. */
- @Binds
- @IntoMap
- @ClassKey(CommunalManagerUpdater.class)
- public abstract CoreStartable bindCommunalManagerUpdater(
- CommunalManagerUpdater communalManagerUpdater);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
index 572bb44..5b46079 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayContainerViewController.java
@@ -16,8 +16,11 @@
package com.android.systemui.dreams;
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
+
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
@@ -26,6 +29,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
+import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
import com.android.systemui.util.ViewController;
@@ -47,6 +51,15 @@
// the space into which widgets are placed.
private final ViewGroup mDreamOverlayContentView;
+ // The maximum translation offset to apply to the overlay container to avoid screen burn-in.
+ private final int mMaxBurnInOffset;
+
+ // The interval in milliseconds between burn-in protection updates.
+ private final long mBurnInProtectionUpdateInterval;
+
+ // Main thread handler used to schedule periodic tasks (e.g. burn-in protection updates).
+ private final Handler mHandler;
+
// A hook into the internal inset calculation where we declare the overlays as the only
// touchable regions.
private final ViewTreeObserver.OnComputeInternalInsetsListener
@@ -81,13 +94,21 @@
public DreamOverlayContainerViewController(
DreamOverlayContainerView containerView,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
- DreamOverlayStatusBarViewController statusBarViewController) {
+ DreamOverlayStatusBarViewController statusBarViewController,
+ @Main Handler handler,
+ @Named(DreamOverlayModule.MAX_BURN_IN_OFFSET) int maxBurnInOffset,
+ @Named(DreamOverlayModule.BURN_IN_PROTECTION_UPDATE_INTERVAL) long
+ burnInProtectionUpdateInterval) {
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
mDreamOverlayNotificationsDragAreaHeight =
mView.getResources().getDimensionPixelSize(
R.dimen.dream_overlay_notifications_drag_area_height);
+
+ mHandler = handler;
+ mMaxBurnInOffset = maxBurnInOffset;
+ mBurnInProtectionUpdateInterval = burnInProtectionUpdateInterval;
}
@Override
@@ -99,10 +120,12 @@
protected void onViewAttached() {
mView.getViewTreeObserver()
.addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
+ mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
}
@Override
protected void onViewDetached() {
+ mHandler.removeCallbacks(this::updateBurnInOffsets);
mView.getViewTreeObserver()
.removeOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
@@ -123,4 +146,15 @@
int getDreamOverlayNotificationsDragAreaHeight() {
return mDreamOverlayNotificationsDragAreaHeight;
}
+
+ private void updateBurnInOffsets() {
+ // These translation values change slowly, and the set translation methods are idempotent,
+ // so no translation occurs when the values don't change.
+ mView.setTranslationX(getBurnInOffset(mMaxBurnInOffset * 2, true)
+ - mMaxBurnInOffset);
+ mView.setTranslationY(getBurnInOffset(mMaxBurnInOffset * 2, false)
+ - mMaxBurnInOffset);
+
+ mHandler.postDelayed(this::updateBurnInOffsets, mBurnInProtectionUpdateInterval);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
index 5b588a9..d291203 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/dagger/DreamOverlayModule.java
@@ -17,6 +17,7 @@
package com.android.systemui.dreams.dagger;
import android.content.ContentResolver;
+import android.content.res.Resources;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -45,6 +46,9 @@
public static final String DREAM_OVERLAY_BATTERY_CONTROLLER =
"dream_overlay_battery_controller";
public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
+ public static final String MAX_BURN_IN_OFFSET = "max_burn_in_offset";
+ public static final String BURN_IN_PROTECTION_UPDATE_INTERVAL =
+ "burn_in_protection_update_interval";
/** */
@Provides
@@ -104,4 +108,20 @@
contentResolver,
batteryController);
}
+
+ /** */
+ @Provides
+ @DreamOverlayComponent.DreamOverlayScope
+ @Named(MAX_BURN_IN_OFFSET)
+ static int providesMaxBurnInOffset(@Main Resources resources) {
+ return resources.getDimensionPixelSize(R.dimen.default_burn_in_prevention_offset);
+ }
+
+ /** */
+ @Provides
+ @Named(BURN_IN_PROTECTION_UPDATE_INTERVAL)
+ static long providesBurnInProtectionUpdateInterval(@Main Resources resources) {
+ return resources.getInteger(
+ R.integer.config_dreamOverlayBurnInProtectionUpdateIntervalMillis);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
index d73d9cd..0ad2807 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardIndicationRotateTextViewController.java
@@ -119,14 +119,13 @@
return;
}
long minShowDuration = getMinVisibilityMillis(mIndicationMessages.get(mCurrIndicationType));
- final boolean hasPreviousIndication = mIndicationMessages.get(type) != null
- && !TextUtils.isEmpty(mIndicationMessages.get(type).getMessage());
- final boolean hasNewIndication = newIndication != null;
+ final boolean hasNewIndication = newIndication != null
+ && !TextUtils.isEmpty(newIndication.getMessage());
if (!hasNewIndication) {
mIndicationMessages.remove(type);
mIndicationQueue.removeIf(x -> x == type);
} else {
- if (!hasPreviousIndication) {
+ if (!mIndicationQueue.contains(type)) {
mIndicationQueue.add(type);
}
@@ -230,6 +229,7 @@
public void clearMessages() {
mCurrIndicationType = INDICATION_TYPE_NONE;
mIndicationQueue.clear();
+ mIndicationMessages.clear();
mView.clearMessages();
}
@@ -310,7 +310,7 @@
if (mIsDozing) {
showIndication(INDICATION_TYPE_NONE);
} else if (mIndicationQueue.size() > 0) {
- showIndication(mIndicationQueue.remove(0));
+ showIndication(mIndicationQueue.get(0));
}
}
};
@@ -327,7 +327,7 @@
ShowNextIndication(long delay) {
mShowIndicationRunnable = () -> {
int type = mIndicationQueue.size() == 0
- ? INDICATION_TYPE_NONE : mIndicationQueue.remove(0);
+ ? INDICATION_TYPE_NONE : mIndicationQueue.get(0);
showIndication(type);
};
mCancelDelayedRunnable = mExecutor.executeDelayed(mShowIndicationRunnable, delay);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index fdd6f65..8376681 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1761,7 +1761,7 @@
}
};
- public void keyguardDone() {
+ private void keyguardDone() {
Trace.beginSection("KeyguardViewMediator#keyguardDone");
if (DEBUG) Log.d(TAG, "keyguardDone()");
userActivity();
@@ -1895,9 +1895,8 @@
resetKeyguardDonePendingLocked();
}
-
if (mGoingToSleep) {
- mUpdateMonitor.clearBiometricRecognized();
+ mUpdateMonitor.clearBiometricRecognizedWhenKeyguardDone(currentUser);
Log.i(TAG, "Device is going to sleep, aborting keyguardDone");
return;
}
@@ -1918,7 +1917,7 @@
}
handleHide();
- mUpdateMonitor.clearBiometricRecognized();
+ mUpdateMonitor.clearBiometricRecognizedWhenKeyguardDone(currentUser);
Trace.endSection();
}
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/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index e06b768..1dba536 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -28,6 +28,7 @@
import androidx.annotation.Nullable;
+import com.android.systemui.animation.Interpolators;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
@@ -41,7 +42,6 @@
import com.android.systemui.qs.tileimpl.HeightOverrideable;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
-import com.android.wm.shell.animation.Interpolators;
import java.util.ArrayList;
import java.util.Collection;
@@ -301,6 +301,8 @@
TouchAnimator.Builder qqsTranslationYBuilder = new Builder();
TouchAnimator.Builder translationXBuilder = new Builder();
TouchAnimator.Builder nonFirstPageAlphaBuilder = new Builder();
+ TouchAnimator.Builder quadraticInterpolatorBuilder = new Builder()
+ .setInterpolator(Interpolators.ACCELERATE);
Collection<QSTile> tiles = mHost.getTiles();
int count = 0;
@@ -413,7 +415,13 @@
qqsTranslationYBuilder
);
- firstPageBuilder.addFloat(quickTileView.getSecondaryLabel(), "alpha", 0, 1);
+ // Secondary labels on tiles not in QQS have two alpha animation applied:
+ // * on the tile themselves
+ // * on TileLayout
+ // Therefore, we use a quadratic interpolator animator to animate the alpha
+ // for tiles in QQS to match.
+ quadraticInterpolatorBuilder
+ .addFloat(quickTileView.getSecondaryLabel(), "alpha", 0, 1);
nonFirstPageAlphaBuilder
.addFloat(quickTileView.getSecondaryLabel(), "alpha", 0, 0);
@@ -461,6 +469,7 @@
mFirstPageAnimator = firstPageBuilder
// Fade in the tiles/labels as we reach the final position.
.addFloat(tileLayout, "alpha", 0, 1)
+ .addFloat(quadraticInterpolatorBuilder.build(), "position", 0, 1)
.setListener(this)
.build();
@@ -535,7 +544,11 @@
builder.addFloat(tileView.getSecondaryIcon(), "translationY", -centerDiff, 0);
// The labels have different apparent size in QQS vs QS (no secondary label), so the
// translation needs to account for that.
- int labelDiff = centerDiff - tileView.getSecondaryLabel().getMeasuredHeight() / 2;
+ int secondaryLabelOffset = 0;
+ if (tileView.getSecondaryLabel().getVisibility() == View.VISIBLE) {
+ secondaryLabelOffset = tileView.getSecondaryLabel().getMeasuredHeight() / 2;
+ }
+ int labelDiff = centerDiff - secondaryLabelOffset;
builder.addFloat(tileView.getLabelContainer(), "translationY", -labelDiff, 0);
builder.addFloat(tileView.getSecondaryLabel(), "alpha", 0, 0.3f, 1);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 9acd3eb..d3bad16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -414,9 +414,9 @@
public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) {
holder.mTileView.removeOnLayoutChangeListener(this);
- holder.mTileView.requestFocus();
+ holder.mTileView.requestAccessibilityFocus();
if (mAccessibilityAction == ACTION_NONE) {
- holder.mTileView.clearFocus();
+ holder.mTileView.clearAccessibilityFocus();
}
}
});
@@ -449,12 +449,13 @@
// Update the tile divider position
mTileDividerIndex++;
mFocusIndex = mEditIndex - 1;
+ final int focus = mFocusIndex;
mNeedsFocus = true;
if (mRecyclerView != null) {
mRecyclerView.post(() -> {
final RecyclerView recyclerView = mRecyclerView;
if (recyclerView != null) {
- recyclerView.smoothScrollToPosition(mFocusIndex);
+ recyclerView.smoothScrollToPosition(focus);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index cd4b745..963a0d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -34,8 +34,6 @@
import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON;
import static com.android.systemui.plugins.FalsingManager.LOW_PENALTY;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.app.IActivityManager;
import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
@@ -72,7 +70,6 @@
import com.android.settingslib.Utils;
import com.android.settingslib.fuelgauge.BatteryStatus;
import com.android.systemui.R;
-import com.android.systemui.animation.Interpolators;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
@@ -149,6 +146,7 @@
private CharSequence mBiometricMessage;
protected ColorStateList mInitialTextColorState;
private boolean mVisible;
+ private boolean mOrganizationOwnedDevice;
private boolean mPowerPluggedIn;
private boolean mPowerPluggedInWired;
@@ -256,13 +254,13 @@
mExecutor,
mStatusBarStateController);
updateIndication(false /* animate */);
- updateDisclosure();
+ updateOrganizedOwnedDevice();
if (mBroadcastReceiver == null) {
// Update the disclosure proactively to avoid IPC on the critical path.
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- updateDisclosure();
+ updateOrganizedOwnedDevice();
}
};
IntentFilter intentFilter = new IntentFilter();
@@ -305,12 +303,11 @@
}
/**
- * Doesn't include disclosure (also a persistent indication) which gets triggered separately.
- *
* This method also doesn't update transient messages like biometrics since those messages
* are also updated separately.
*/
private void updatePersistentIndications(boolean animate, int userId) {
+ updateDisclosure();
updateOwnerInfo();
updateBattery(animate);
updateUserLocked(userId);
@@ -320,9 +317,14 @@
updateResting();
}
- private void updateDisclosure() {
+ private void updateOrganizedOwnedDevice() {
// avoid calling this method since it has an IPC
- if (whitelistIpcs(this::isOrganizationOwnedDevice)) {
+ mOrganizationOwnedDevice = whitelistIpcs(this::isOrganizationOwnedDevice);
+ updatePersistentIndications(false, KeyguardUpdateMonitor.getCurrentUser());
+ }
+
+ private void updateDisclosure() {
+ if (mOrganizationOwnedDevice) {
final CharSequence organizationName = getOrganizationOwnedDeviceOrganizationName();
final CharSequence disclosure = getDisclosureText(organizationName);
mRotateTextViewController.updateIndication(
@@ -335,8 +337,6 @@
} else {
mRotateTextViewController.hideIndication(INDICATION_TYPE_DISCLOSURE);
}
-
- updateResting();
}
private CharSequence getDisclosureText(@Nullable CharSequence organizationName) {
@@ -753,60 +753,6 @@
updatePersistentIndications(animate, KeyguardUpdateMonitor.getCurrentUser());
}
- // animates textView - textView moves up and bounces down
- private void animateText(KeyguardIndicationTextView textView, String indication) {
- int yTranslation = mContext.getResources().getInteger(
- R.integer.wired_charging_keyguard_text_animation_distance);
- int animateUpDuration = mContext.getResources().getInteger(
- R.integer.wired_charging_keyguard_text_animation_duration_up);
- int animateDownDuration = mContext.getResources().getInteger(
- R.integer.wired_charging_keyguard_text_animation_duration_down);
- textView.animate().cancel();
- ViewClippingUtil.setClippingDeactivated(textView, true, mClippingParams);
- textView.animate()
- .translationYBy(yTranslation)
- .setInterpolator(Interpolators.LINEAR)
- .setDuration(animateUpDuration)
- .setListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationStart(Animator animation) {
- textView.switchIndication(indication, null);
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- textView.setTranslationY(BOUNCE_ANIMATION_FINAL_Y);
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mCancelled) {
- ViewClippingUtil.setClippingDeactivated(textView, false,
- mClippingParams);
- return;
- }
- textView.animate()
- .setDuration(animateDownDuration)
- .setInterpolator(Interpolators.BOUNCE)
- .translationY(BOUNCE_ANIMATION_FINAL_Y)
- .setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- textView.setTranslationY(BOUNCE_ANIMATION_FINAL_Y);
- ViewClippingUtil.setClippingDeactivated(textView, false,
- mClippingParams);
- // Unset the listener, otherwise this may persist for
- // another view property animation
- textView.animate().setListener(null);
- }
- });
- }
- });
- }
-
protected String computePowerIndication() {
int chargingId;
if (mBatteryOverheated) {
@@ -1182,9 +1128,12 @@
@Override
public void onKeyguardShowingChanged() {
+ // All transient messages are gone the next time keyguard is shown
if (!mKeyguardStateController.isShowing()) {
mTopIndicationView.clearMessages();
mRotateTextViewController.clearMessages();
+ } else {
+ updatePersistentIndications(false, KeyguardUpdateMonitor.getCurrentUser());
}
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index cbc113b..c3cc97b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -24,6 +24,7 @@
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
* A util class for various reusable functions
@@ -73,4 +74,20 @@
return (int) (dimensionPixelSize * factor);
}
+ /** Get the notification key, reformatted for logging, for the (optional) entry */
+ public static String logKey(NotificationEntry entry) {
+ if (entry == null) {
+ return "null";
+ }
+ return logKey(entry.getKey());
+ }
+
+ /** Removes newlines from the notification key to prettify apps that have these in the tag */
+ public static String logKey(String key) {
+ if (key == null) {
+ return "null";
+ }
+ return key.replace("\n", "");
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index bf81ea5..7605561 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -56,7 +56,6 @@
import android.service.notification.StatusBarNotification;
import android.util.ArrayMap;
import android.util.Pair;
-import android.util.Slog;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -622,7 +621,7 @@
entry.mLifetimeExtenders.clear();
mAmDispatchingToOtherCode = true;
for (NotifLifetimeExtender extender : mLifetimeExtenders) {
- if (extender.shouldExtendLifetime(entry, entry.mCancellationReason)) {
+ if (extender.maybeExtendLifetime(entry, entry.mCancellationReason)) {
mLogger.logLifetimeExtended(entry.getKey(), extender);
entry.mLifetimeExtenders.add(extender);
}
@@ -756,6 +755,7 @@
&& !entry.getSbn().getNotification().isGroupSummary()
&& !hasFlag(entry, Notification.FLAG_ONGOING_EVENT)
&& !hasFlag(entry, Notification.FLAG_BUBBLE)
+ && !hasFlag(entry, Notification.FLAG_NO_CLEAR)
&& entry.getDismissState() != DISMISSED;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
index dbecf1c..ac00581 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinator.kt
@@ -84,7 +84,7 @@
onEndLifetimeExtensionCallback = callback
}
- override fun shouldExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
+ override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
val isShowingGuts = isCurrentlyShowingGuts(entry)
if (isShowingGuts) {
notifsExtendingLifetime.add(entry.key)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
index f9f0b9d..7410912 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java
@@ -178,7 +178,7 @@
}
@Override
- public boolean shouldExtendLifetime(@NonNull NotificationEntry entry, int reason) {
+ public boolean maybeExtendLifetime(@NonNull NotificationEntry entry, int reason) {
boolean extend = !mHeadsUpManager.canRemoveImmediately(entry.getKey());
if (extend) {
if (isSticky(entry)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
index 3b93020..cd2affe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/legacy/NotificationGroupManagerLegacy.java
@@ -16,6 +16,10 @@
package com.android.systemui.statusbar.notification.collection.legacy;
+import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
+
+import static java.util.Objects.requireNonNull;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
@@ -49,6 +53,7 @@
import java.util.Objects;
import java.util.Optional;
import java.util.TreeSet;
+import java.util.function.Function;
import javax.inject.Inject;
@@ -79,10 +84,9 @@
private final HashMap<String, NotificationGroup> mGroupMap = new HashMap<>();
private final ArraySet<OnGroupExpansionChangeListener> mExpansionChangeListeners =
new ArraySet<>();
- private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>();
private final Lazy<PeopleNotificationIdentifier> mPeopleNotificationIdentifier;
private final Optional<Bubbles> mBubblesOptional;
- private final EventBuffer mEventBuffer = new EventBuffer();
+ private final GroupEventDispatcher mEventDispatcher = new GroupEventDispatcher(mGroupMap::get);
private int mBarState = -1;
private HashMap<String, StatusBarNotification> mIsolatedEntries = new HashMap<>();
private HeadsUpManager mHeadsUpManager;
@@ -105,7 +109,7 @@
* Add a listener for changes to groups.
*/
public void registerGroupChangeListener(OnGroupChangeListener listener) {
- mGroupChangeListeners.add(listener);
+ mEventDispatcher.registerGroupChangeListener(listener);
}
@Override
@@ -156,13 +160,15 @@
*/
public void onEntryRemoved(NotificationEntry removed) {
if (SPEW) {
- Log.d(TAG, "onEntryRemoved: entry=" + removed);
+ Log.d(TAG, "onEntryRemoved: entry=" + logKey(removed));
}
+ mEventDispatcher.openBufferScope();
onEntryRemovedInternal(removed, removed.getSbn());
StatusBarNotification oldSbn = mIsolatedEntries.remove(removed.getKey());
if (oldSbn != null) {
updateSuppression(mGroupMap.get(oldSbn.getGroupKey()));
}
+ mEventDispatcher.closeBufferScope();
}
/**
@@ -190,7 +196,8 @@
return;
}
if (SPEW) {
- Log.d(TAG, "onEntryRemovedInternal: entry=" + removed + " group=" + group.groupKey);
+ Log.d(TAG, "onEntryRemovedInternal: entry=" + logKey(removed)
+ + " group=" + logGroupKey(group));
}
if (isGroupChild(removed.getKey(), isGroup, isGroupSummary)) {
group.children.remove(removed.getKey());
@@ -201,9 +208,7 @@
if (group.children.isEmpty()) {
if (group.summary == null) {
mGroupMap.remove(groupKey);
- for (OnGroupChangeListener listener : mGroupChangeListeners) {
- listener.onGroupRemoved(group, groupKey);
- }
+ mEventDispatcher.notifyGroupRemoved(group);
}
}
}
@@ -213,10 +218,12 @@
*/
public void onEntryAdded(final NotificationEntry added) {
if (SPEW) {
- Log.d(TAG, "onEntryAdded: entry=" + added);
+ Log.d(TAG, "onEntryAdded: entry=" + logKey(added));
}
+ mEventDispatcher.openBufferScope();
updateIsolation(added);
onEntryAddedInternal(added);
+ mEventDispatcher.closeBufferScope();
}
private void onEntryAddedInternal(final NotificationEntry added) {
@@ -230,19 +237,17 @@
if (group == null) {
group = new NotificationGroup(groupKey);
mGroupMap.put(groupKey, group);
-
- for (OnGroupChangeListener listener : mGroupChangeListeners) {
- listener.onGroupCreated(group, groupKey);
- }
+ mEventDispatcher.notifyGroupCreated(group);
}
if (SPEW) {
- Log.d(TAG, "onEntryAddedInternal: entry=" + added + " group=" + group.groupKey);
+ Log.d(TAG, "onEntryAddedInternal: entry=" + logKey(added)
+ + " group=" + logGroupKey(group));
}
if (isGroupChild) {
NotificationEntry existing = group.children.get(added.getKey());
if (existing != null && existing != added) {
Throwable existingThrowable = existing.getDebugThrowable();
- Log.wtf(TAG, "Inconsistent entries found with the same key " + added.getKey()
+ Log.wtf(TAG, "Inconsistent entries found with the same key " + logKey(added)
+ "existing removed: " + existing.isRowRemoved()
+ (existingThrowable != null
? Log.getStackTraceString(existingThrowable) + "\n" : "")
@@ -262,9 +267,7 @@
for (NotificationEntry child : childrenCopy) {
onEntryBecomingChild(child);
}
- for (OnGroupChangeListener listener : mGroupChangeListeners) {
- listener.onGroupCreatedFromChildren(group);
- }
+ mEventDispatcher.notifyGroupsChanged();
}
}
}
@@ -323,29 +326,26 @@
boolean alertOverrideChanged = prevAlertOverride != group.alertOverride;
boolean suppressionChanged = prevSuppressed != group.suppressed;
if (alertOverrideChanged || suppressionChanged) {
- if (DEBUG && alertOverrideChanged) {
- Log.d(TAG, "updateSuppression: alertOverride was=" + prevAlertOverride
- + " now=" + group.alertOverride + " group:\n" + group);
- }
- if (DEBUG && suppressionChanged) {
- Log.d(TAG,
- "updateSuppression: suppressed changed to " + group.suppressed
- + " group:\n" + group);
- }
- if (!mIsUpdatingUnchangedGroup) {
+ if (DEBUG) {
+ Log.d(TAG, "updateSuppression:"
+ + " willNotifyListeners=" + !mIsUpdatingUnchangedGroup
+ + " changes for group:\n" + group);
if (alertOverrideChanged) {
- mEventBuffer.notifyAlertOverrideChanged(group, prevAlertOverride);
+ Log.d(TAG, "updateSuppression: alertOverride was=" + logKey(prevAlertOverride)
+ + " now=" + logKey(group.alertOverride));
}
if (suppressionChanged) {
- for (OnGroupChangeListener listener : mGroupChangeListeners) {
- listener.onGroupSuppressionChanged(group, group.suppressed);
- }
+ Log.d(TAG, "updateSuppression: suppressed changed to " + group.suppressed);
}
- mEventBuffer.notifyGroupsChanged();
- } else {
- if (DEBUG) {
- Log.d(TAG, group + " did not notify listeners of above change(s)");
- }
+ }
+ if (alertOverrideChanged) {
+ mEventDispatcher.notifyAlertOverrideChanged(group, prevAlertOverride);
+ }
+ if (suppressionChanged) {
+ mEventDispatcher.notifySuppressedChanged(group);
+ }
+ if (!mIsUpdatingUnchangedGroup) {
+ mEventDispatcher.notifyGroupsChanged();
}
}
}
@@ -369,13 +369,15 @@
// but which should be alerting (because priority conversations are isolated), find it.
if (group == null || group.summary == null) {
if (SPEW) {
- Log.d(TAG, "getPriorityConversationAlertOverride: null group or summary");
+ Log.d(TAG, "getPriorityConversationAlertOverride: null group or summary"
+ + " group=" + logGroupKey(group));
}
return null;
}
if (isIsolated(group.summary.getKey())) {
if (SPEW) {
- Log.d(TAG, "getPriorityConversationAlertOverride: isolated group");
+ Log.d(TAG, "getPriorityConversationAlertOverride: isolated group"
+ + " group=" + logGroupKey(group));
}
return null;
}
@@ -386,7 +388,8 @@
if (group.summary.getSbn().getNotification().getGroupAlertBehavior()
== Notification.GROUP_ALERT_CHILDREN) {
if (SPEW) {
- Log.d(TAG, "getPriorityConversationAlertOverride: summary == GROUP_ALERT_CHILDREN");
+ Log.d(TAG, "getPriorityConversationAlertOverride: summary == GROUP_ALERT_CHILDREN"
+ + " group=" + logGroupKey(group));
}
return null;
}
@@ -396,7 +399,8 @@
HashMap<String, NotificationEntry> children = getImportantConversations(group);
if (children == null || children.isEmpty()) {
if (SPEW) {
- Log.d(TAG, "getPriorityConversationAlertOverride: no important conversations");
+ Log.d(TAG, "getPriorityConversationAlertOverride: no important conversations"
+ + " group=" + logGroupKey(group));
}
return null;
}
@@ -408,8 +412,8 @@
if (child.getSbn().getNotification().getGroupAlertBehavior()
!= Notification.GROUP_ALERT_SUMMARY) {
if (SPEW) {
- Log.d(TAG, "getPriorityConversationAlertOverride: "
- + "child != GROUP_ALERT_SUMMARY");
+ Log.d(TAG, "getPriorityConversationAlertOverride: child != GROUP_ALERT_SUMMARY"
+ + " group=" + logGroupKey(group));
}
return null;
}
@@ -450,13 +454,16 @@
}
if (newestChild != null && importantChildKeys.contains(newestChild.getKey())) {
if (SPEW) {
- Log.d(TAG, "getPriorityConversationAlertOverride: result=" + newestChild);
+ Log.d(TAG, "getPriorityConversationAlertOverride:"
+ + " result=" + logKey(newestChild)
+ + " group=" + logGroupKey(group));
}
return newestChild;
}
if (SPEW) {
- Log.d(TAG, "getPriorityConversationAlertOverride: result=null, newestChild="
- + newestChild);
+ Log.d(TAG, "getPriorityConversationAlertOverride:"
+ + " result=null newestChild=" + logKey(newestChild)
+ + " group=" + logGroupKey(group));
}
return null;
}
@@ -500,7 +507,7 @@
*/
public void onEntryUpdated(NotificationEntry entry, StatusBarNotification oldNotification) {
if (SPEW) {
- Log.d(TAG, "onEntryUpdated: entry=" + entry);
+ Log.d(TAG, "onEntryUpdated: entry=" + logKey(entry));
}
onEntryUpdated(entry, oldNotification.getGroupKey(), oldNotification.isGroup(),
oldNotification.getNotification().isGroupSummary());
@@ -519,6 +526,7 @@
boolean groupKeysChanged = !oldGroupKey.equals(newGroupKey);
boolean wasGroupChild = isGroupChild(entry.getKey(), oldIsGroup, oldIsGroupSummary);
boolean isGroupChild = isGroupChild(entry.getSbn());
+ mEventDispatcher.openBufferScope();
mIsUpdatingUnchangedGroup = !groupKeysChanged && wasGroupChild == isGroupChild;
if (mGroupMap.get(getGroupKey(entry.getKey(), oldGroupKey)) != null) {
onEntryRemovedInternal(entry, oldGroupKey, oldIsGroup, oldIsGroupSummary);
@@ -536,6 +544,7 @@
} else if (!wasGroupChild && isGroupChild) {
onEntryBecomingChild(entry);
}
+ mEventDispatcher.closeBufferScope();
}
/**
@@ -798,7 +807,7 @@
*/
private void isolateNotification(NotificationEntry entry) {
if (SPEW) {
- Log.d(TAG, "isolateNotification: entry=" + entry);
+ Log.d(TAG, "isolateNotification: entry=" + logKey(entry));
}
// We will be isolated now, so lets update the groups
onEntryRemovedInternal(entry, entry.getSbn());
@@ -811,9 +820,7 @@
// When the notification gets added afterwards it is already isolated and therefore
// it doesn't lead to an update.
updateSuppression(mGroupMap.get(entry.getSbn().getGroupKey()));
- for (OnGroupChangeListener listener : mGroupChangeListeners) {
- listener.onGroupsChanged();
- }
+ mEventDispatcher.notifyGroupsChanged();
}
/**
@@ -827,7 +834,7 @@
// listener may be unable to correctly determine the true state of the group. By delaying
// the alertOverride change until after the add phase, we can ensure that listeners only
// have to handle a consistent state.
- mEventBuffer.startBuffering();
+ mEventDispatcher.openBufferScope();
boolean isIsolated = isIsolated(entry.getSbn().getKey());
if (shouldIsolate(entry)) {
if (!isIsolated) {
@@ -836,7 +843,7 @@
} else if (isIsolated) {
stopIsolatingNotification(entry);
}
- mEventBuffer.flushAndStopBuffering();
+ mEventDispatcher.closeBufferScope();
}
/**
@@ -846,15 +853,13 @@
*/
private void stopIsolatingNotification(NotificationEntry entry) {
if (SPEW) {
- Log.d(TAG, "stopIsolatingNotification: entry=" + entry);
+ Log.d(TAG, "stopIsolatingNotification: entry=" + logKey(entry));
}
// not isolated anymore, we need to update the groups
onEntryRemovedInternal(entry, entry.getSbn());
mIsolatedEntries.remove(entry.getKey());
onEntryAddedInternal(entry);
- for (OnGroupChangeListener listener : mGroupChangeListeners) {
- listener.onGroupsChanged();
- }
+ mEventDispatcher.notifyGroupsChanged();
}
private boolean isGroupNotFullyVisible(NotificationGroup notificationGroup) {
@@ -874,11 +879,11 @@
pw.println("GroupManagerLegacy state:");
pw.println(" number of groups: " + mGroupMap.size());
for (Map.Entry<String, NotificationGroup> entry : mGroupMap.entrySet()) {
- pw.println("\n key: " + entry.getKey()); pw.println(entry.getValue());
+ pw.println("\n key: " + logKey(entry.getKey())); pw.println(entry.getValue());
}
pw.println("\n isolated entries: " + mIsolatedEntries.size());
for (Map.Entry<String, StatusBarNotification> entry : mIsolatedEntries.entrySet()) {
- pw.print(" "); pw.print(entry.getKey());
+ pw.print(" "); pw.print(logKey(entry.getKey()));
pw.print(", "); pw.println(entry.getValue());
}
}
@@ -888,6 +893,14 @@
setStatusBarState(newState);
}
+ /** Get the group key, reformatted for logging, for the (optional) group */
+ public static String logGroupKey(NotificationGroup group) {
+ if (group == null) {
+ return "null";
+ }
+ return logKey(group.groupKey);
+ }
+
/**
* A record of a notification being posted, containing the time of the post and the key of the
* notification entry. These are stored in a TreeSet by the NotificationGroup and used to
@@ -977,18 +990,35 @@
* When buffering, instead of notifying the listeners it will set internal state that will allow
* it to notify listeners of those events later
*/
- private class EventBuffer {
+ static class GroupEventDispatcher {
+ private final Function<String, NotificationGroup> mGroupMapGetter;
+ private final ArraySet<OnGroupChangeListener> mGroupChangeListeners = new ArraySet<>();
private final HashMap<String, NotificationEntry> mOldAlertOverrideByGroup = new HashMap<>();
- private boolean mIsBuffering = false;
+ private final HashMap<String, Boolean> mOldSuppressedByGroup = new HashMap<>();
+ private int mBufferScopeDepth = 0;
private boolean mDidGroupsChange = false;
+ GroupEventDispatcher(Function<String, NotificationGroup> groupMapGetter) {
+ mGroupMapGetter = requireNonNull(groupMapGetter);
+ }
+
+ void registerGroupChangeListener(OnGroupChangeListener listener) {
+ mGroupChangeListeners.add(listener);
+ }
+
+ private boolean isBuffering() {
+ return mBufferScopeDepth > 0;
+ }
+
void notifyAlertOverrideChanged(NotificationGroup group,
NotificationEntry oldAlertOverride) {
- if (mIsBuffering) {
+ if (isBuffering()) {
// The value in this map is the override before the event. If there is an entry
// already in the map, then we are effectively coalescing two events, which means
// we need to preserve the original initial value.
- mOldAlertOverrideByGroup.putIfAbsent(group.groupKey, oldAlertOverride);
+ if (!mOldAlertOverrideByGroup.containsKey(group.groupKey)) {
+ mOldAlertOverrideByGroup.put(group.groupKey, oldAlertOverride);
+ }
} else {
for (OnGroupChangeListener listener : mGroupChangeListeners) {
listener.onGroupAlertOverrideChanged(group, oldAlertOverride,
@@ -997,8 +1027,21 @@
}
}
+ void notifySuppressedChanged(NotificationGroup group) {
+ if (isBuffering()) {
+ // The value in this map is the 'suppressed' before the event. If there is a value
+ // already in the map, then we are effectively coalescing two events, which means
+ // we need to preserve the original initial value.
+ mOldSuppressedByGroup.putIfAbsent(group.groupKey, !group.suppressed);
+ } else {
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
+ listener.onGroupSuppressionChanged(group, group.suppressed);
+ }
+ }
+ }
+
void notifyGroupsChanged() {
- if (mIsBuffering) {
+ if (isBuffering()) {
mDidGroupsChange = true;
} else {
for (OnGroupChangeListener listener : mGroupChangeListeners) {
@@ -1007,26 +1050,94 @@
}
}
- void startBuffering() {
- mIsBuffering = true;
+ void notifyGroupCreated(NotificationGroup group) {
+ // NOTE: given how this event is used, it doesn't need to be buffered right now
+ final String groupKey = group.groupKey;
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
+ listener.onGroupCreated(group, groupKey);
+ }
}
- void flushAndStopBuffering() {
- // stop buffering so that we can call our own helpers
- mIsBuffering = false;
+ void notifyGroupRemoved(NotificationGroup group) {
+ // NOTE: given how this event is used, it doesn't need to be buffered right now
+ final String groupKey = group.groupKey;
+ for (OnGroupChangeListener listener : mGroupChangeListeners) {
+ listener.onGroupRemoved(group, groupKey);
+ }
+ }
+
+ void openBufferScope() {
+ mBufferScopeDepth++;
+ if (SPEW) {
+ Log.d(TAG, "openBufferScope: scopeDepth=" + mBufferScopeDepth);
+ }
+ }
+
+ void closeBufferScope() {
+ mBufferScopeDepth--;
+ if (SPEW) {
+ Log.d(TAG, "closeBufferScope: scopeDepth=" + mBufferScopeDepth);
+ }
+ // Flush buffered events if the last buffer scope has closed
+ if (!isBuffering()) {
+ flushBuffer();
+ }
+ }
+
+ private void flushBuffer() {
+ if (SPEW) {
+ Log.d(TAG, "flushBuffer: "
+ + " suppressed.size=" + mOldSuppressedByGroup.size()
+ + " alertOverride.size=" + mOldAlertOverrideByGroup.size()
+ + " mDidGroupsChange=" + mDidGroupsChange);
+ }
+ // alert all group suppressed changes for groups that were not removed
+ for (Map.Entry<String, Boolean> entry : mOldSuppressedByGroup.entrySet()) {
+ NotificationGroup group = mGroupMapGetter.apply(entry.getKey());
+ if (group == null) {
+ // The group can be null if this suppressed changed before the group was
+ // permanently removed, meaning that there's no guarantee that listeners will
+ // that field clear.
+ if (SPEW) {
+ Log.d(TAG, "flushBuffer: suppressed:"
+ + " cannot report for removed group: " + logKey(entry.getKey()));
+ }
+ continue;
+ }
+ boolean oldSuppressed = entry.getValue();
+ if (group.suppressed == oldSuppressed) {
+ // If the final suppressed equals the initial, it means we coalesced two
+ // events which undid the change, so we can drop it entirely.
+ if (SPEW) {
+ Log.d(TAG, "flushBuffer: suppressed:"
+ + " did not change for group: " + logKey(entry.getKey()));
+ }
+ continue;
+ }
+ notifySuppressedChanged(group);
+ }
+ mOldSuppressedByGroup.clear();
// alert all group alert override changes for groups that were not removed
for (Map.Entry<String, NotificationEntry> entry : mOldAlertOverrideByGroup.entrySet()) {
- NotificationGroup group = mGroupMap.get(entry.getKey());
+ NotificationGroup group = mGroupMapGetter.apply(entry.getKey());
if (group == null) {
// The group can be null if this alertOverride changed before the group was
// permanently removed, meaning that there's no guarantee that listeners will
// that field clear.
+ if (SPEW) {
+ Log.d(TAG, "flushBuffer: alertOverride:"
+ + " cannot report for removed group: " + entry.getKey());
+ }
continue;
}
NotificationEntry oldAlertOverride = entry.getValue();
if (group.alertOverride == oldAlertOverride) {
// If the final alertOverride equals the initial, it means we coalesced two
// events which undid the change, so we can drop it entirely.
+ if (SPEW) {
+ Log.d(TAG, "flushBuffer: alertOverride:"
+ + " did not change for group: " + logKey(entry.getKey()));
+ }
continue;
}
notifyAlertOverrideChanged(group, oldAlertOverride);
@@ -1088,14 +1199,6 @@
@Nullable NotificationEntry newAlertOverride) {}
/**
- * A group of children just received a summary notification and should therefore become
- * children of it.
- *
- * @param group the group created
- */
- default void onGroupCreatedFromChildren(NotificationGroup group) {}
-
- /**
* The groups have changed. This can happen if the isolation of a child has changes or if a
* group became suppressed / unsuppressed
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
index 2fe3bd6..70ad8a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifLifetimeExtender.java
@@ -45,7 +45,7 @@
* called on all lifetime extenders even if earlier ones return true (in other words, multiple
* lifetime extenders can be extending a notification at the same time).
*/
- boolean shouldExtendLifetime(@NonNull NotificationEntry entry, @CancellationReason int reason);
+ boolean maybeExtendLifetime(@NonNull NotificationEntry entry, @CancellationReason int reason);
/**
* Called by the NotifCollection to inform a lifetime extender that its extension of a notif
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt
index 145c1e5..51dab72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtender.kt
@@ -73,7 +73,7 @@
final override fun getName(): String = name
- final override fun shouldExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
+ final override fun maybeExtendLifetime(entry: NotificationEntry, reason: Int): Boolean {
val shouldExtend = queryShouldExtendLifetime(entry)
if (debug) {
Log.d(tag, "$name.shouldExtendLifetime(key=${entry.key}, reason=$reason)" +
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 7c3399d..5833ec2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -93,7 +93,6 @@
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
-import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
@@ -689,11 +688,6 @@
(changedRow, expanded) -> mView.onGroupExpandChanged(changedRow, expanded));
legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
@Override
- public void onGroupCreatedFromChildren(NotificationGroup group) {
- mStatusBar.requestNotificationUpdate("onGroupCreatedFromChildren");
- }
-
- @Override
public void onGroupsChanged() {
mStatusBar.requestNotificationUpdate("onGroupsChanged");
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index 6632c9c..8bababf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -16,6 +16,9 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.notification.NotificationUtils.logKey;
+import static com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.logGroupKey;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Notification;
@@ -148,7 +151,9 @@
@Override
public void onGroupSuppressionChanged(NotificationGroup group, boolean suppressed) {
if (DEBUG) {
- Log.d(TAG, "!! onGroupSuppressionChanged: group.summary=" + group.summary
+ Log.d(TAG, "!! onGroupSuppressionChanged:"
+ + " group=" + logGroupKey(group)
+ + " group.summary=" + logKey(group.summary)
+ " suppressed=" + suppressed);
}
NotificationEntry oldAlertOverride = group.alertOverride;
@@ -160,9 +165,11 @@
@Nullable NotificationEntry oldAlertOverride,
@Nullable NotificationEntry newAlertOverride) {
if (DEBUG) {
- Log.d(TAG, "!! onGroupAlertOverrideChanged: group.summary=" + group.summary
- + " oldAlertOverride=" + oldAlertOverride
- + " newAlertOverride=" + newAlertOverride);
+ Log.d(TAG, "!! onGroupAlertOverrideChanged:"
+ + " group=" + logGroupKey(group)
+ + " group.summary=" + logKey(group.summary)
+ + " oldAlertOverride=" + logKey(oldAlertOverride)
+ + " newAlertOverride=" + logKey(newAlertOverride));
}
onGroupChanged(group, oldAlertOverride);
}
@@ -208,7 +215,9 @@
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
if (DEBUG) {
- Log.d(TAG, "!! onHeadsUpStateChanged: entry=" + entry + " isHeadsUp=" + isHeadsUp);
+ Log.d(TAG, "!! onHeadsUpStateChanged:"
+ + " entry=" + logKey(entry)
+ + " isHeadsUp=" + isHeadsUp);
}
if (isHeadsUp && entry.getSbn().getNotification().isGroupSummary()) {
// a group summary is alerting; trigger the forward transfer checks
@@ -240,6 +249,9 @@
} else if (mGroupManager.isSummaryOfSuppressedGroup(summary.getSbn())) {
handleSuppressedSummaryAlerted(summary, oldAlertOverride);
}
+ if (DEBUG) {
+ Log.d(TAG, "checkForForwardAlertTransfer: done");
+ }
}
private final NotificationEntryListener mNotificationEntryListener =
@@ -249,7 +261,7 @@
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
if (DEBUG) {
- Log.d(TAG, "!! onPendingEntryAdded: entry=" + entry);
+ Log.d(TAG, "!! onPendingEntryAdded: entry=" + logKey(entry));
}
String groupKey = mGroupManager.getGroupKey(entry.getSbn());
GroupAlertEntry groupAlertEntry = mGroupAlertEntries.get(groupKey);
@@ -345,7 +357,7 @@
private void handleSuppressedSummaryAlerted(@NonNull NotificationEntry summary,
NotificationEntry oldAlertOverride) {
if (DEBUG) {
- Log.d(TAG, "handleSuppressedSummaryAlerted: summary=" + summary);
+ Log.d(TAG, "handleSuppressedSummaryAlerted: summary=" + logKey(summary));
}
GroupAlertEntry groupAlertEntry =
mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn()));
@@ -407,7 +419,7 @@
*/
private void handleOverriddenSummaryAlerted(NotificationEntry summary) {
if (DEBUG) {
- Log.d(TAG, "handleOverriddenSummaryAlerted: summary=" + summary);
+ Log.d(TAG, "handleOverriddenSummaryAlerted: summary=" + logKey(summary));
}
GroupAlertEntry groupAlertEntry =
mGroupAlertEntries.get(mGroupManager.getGroupKey(summary.getSbn()));
@@ -481,7 +493,9 @@
groupAlertEntry.mLastAlertTransferTime = SystemClock.elapsedRealtime();
}
if (DEBUG) {
- Log.d(TAG, "transferAlertState: fromEntry=" + fromEntry + " toEntry=" + toEntry);
+ Log.d(TAG, "transferAlertState:"
+ + " fromEntry=" + logKey(fromEntry)
+ + " toEntry=" + logKey(toEntry));
}
transferAlertState(fromEntry, toEntry);
}
@@ -583,7 +597,8 @@
final RowContentBindParams params = mRowContentBindStage.getStageParams(entry);
if ((params.getContentViews() & contentFlag) == 0) {
if (DEBUG) {
- Log.d(TAG, "alertNotificationWhenPossible: async requestRebind entry=" + entry);
+ Log.d(TAG, "alertNotificationWhenPossible:"
+ + " async requestRebind entry=" + logKey(entry));
}
mPendingAlerts.put(entry.getKey(), new PendingAlertInfo(entry));
params.requireContentViews(contentFlag);
@@ -593,6 +608,10 @@
if (alertInfo.isStillValid()) {
alertNotificationWhenPossible(entry);
} else {
+ if (DEBUG) {
+ Log.d(TAG, "alertNotificationWhenPossible:"
+ + " markContentViewsFreeable entry=" + logKey(entry));
+ }
// The transfer is no longer valid. Free the content.
mRowContentBindStage.getStageParams(entry).markContentViewsFreeable(
contentFlag);
@@ -604,12 +623,14 @@
}
if (mHeadsUpManager.isAlerting(entry.getKey())) {
if (DEBUG) {
- Log.d(TAG, "alertNotificationWhenPossible: continue alerting entry=" + entry);
+ Log.d(TAG, "alertNotificationWhenPossible:"
+ + " continue alerting entry=" + logKey(entry));
}
mHeadsUpManager.updateNotification(entry.getKey(), true /* alert */);
} else {
if (DEBUG) {
- Log.d(TAG, "alertNotificationWhenPossible: start alerting entry=" + entry);
+ Log.d(TAG, "alertNotificationWhenPossible:"
+ + " start alerting entry=" + logKey(entry));
}
mHeadsUpManager.showNotification(entry);
}
@@ -657,7 +678,7 @@
// Notification is aborted due to the transfer being explicitly cancelled
return false;
}
- if (mEntry.getSbn().getGroupKey() != mOriginalNotification.getGroupKey()) {
+ if (!mEntry.getSbn().getGroupKey().equals(mOriginalNotification.getGroupKey())) {
// Groups have changed
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 23ea45b..0bc633c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -2439,7 +2439,7 @@
mSplitShadeHeaderController.setShadeExpandedFraction(shadeExpandedFraction);
mSplitShadeHeaderController.setQsExpandedFraction(qsExpansionFraction);
mSplitShadeHeaderController.setShadeExpanded(mQsVisible);
-
+ mKeyguardStatusBarViewController.updateViewState();
if (mCommunalViewController != null) {
mCommunalViewController.updateQsExpansion(qsExpansionFraction);
@@ -4736,8 +4736,6 @@
public interface NotificationPanelViewStateProvider {
/** Returns the expanded height of the panel view. */
float getPanelViewExpandedHeight();
- /** Returns the fraction of QS that's expanded. */
- float getQsExpansionFraction();
/**
* Returns true if heads up should be visible.
*
@@ -4758,18 +4756,15 @@
}
@Override
- public float getQsExpansionFraction() {
- return computeQsExpansionFraction();
- }
-
- @Override
public boolean shouldHeadsUpBeVisible() {
return mHeadsUpAppearanceController.shouldBeVisible();
}
@Override
public float getLockscreenShadeDragProgress() {
- return mLockscreenShadeTransitionController.getQSDragProgress();
+ return mTransitioningToFullShadeProgress > 0
+ ? mLockscreenShadeTransitionController.getQSDragProgress()
+ : computeQsExpansionFraction();
}
};
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalManagerUpdaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalManagerUpdaterTest.java
deleted file mode 100644
index 4a29ada..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalManagerUpdaterTest.java
+++ /dev/null
@@ -1,83 +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.systemui.communal;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.app.communal.CommunalManager;
-import android.testing.AndroidTestingRunner;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.systemui.SysuiTestCase;
-import com.android.systemui.util.concurrency.FakeExecutor;
-import com.android.systemui.util.condition.Monitor;
-import com.android.systemui.util.time.FakeSystemClock;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class CommunalManagerUpdaterTest extends SysuiTestCase {
- private CommunalSourceMonitor mMonitor;
- @Mock
- private CommunalManager mCommunalManager;
- @Mock
- private Monitor mCommunalConditionsMonitor;
-
- private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- mContext.addMockSystemService(CommunalManager.class, mCommunalManager);
-
- doAnswer(invocation -> {
- final Monitor.Callback callback = invocation.getArgument(0);
- callback.onConditionsChanged(true);
- return null;
- }).when(mCommunalConditionsMonitor).addCallback(any());
-
- mMonitor = new CommunalSourceMonitor(mExecutor, mCommunalConditionsMonitor);
- final CommunalManagerUpdater updater = new CommunalManagerUpdater(mContext, mMonitor);
- updater.start();
- clearInvocations(mCommunalManager);
- }
-
- @Test
- public void testUpdateSystemService_false() {
- mMonitor.setSource(null);
- mExecutor.runAllReady();
- verify(mCommunalManager).setCommunalViewShowing(false);
- }
-
- @Test
- public void testUpdateSystemService_true() {
- final CommunalSource source = mock(CommunalSource.class);
- mMonitor.setSource(source);
- mExecutor.runAllReady();
- verify(mCommunalManager).setCommunalViewShowing(true);
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
index cf53ccf..7c5f57f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayContainerViewControllerTest.java
@@ -19,10 +19,13 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Resources;
+import android.os.Handler;
import android.testing.AndroidTestingRunner;
import android.view.View;
import android.view.ViewGroup;
@@ -45,6 +48,8 @@
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
+ private static final int MAX_BURN_IN_OFFSET = 20;
+ private static final long BURN_IN_PROTECTION_UPDATE_INTERVAL = 10;
@Mock
Resources mResources;
@@ -61,6 +66,9 @@
@Mock
ViewGroup mDreamOverlayContentView;
+ @Mock
+ Handler mHandler;
+
DreamOverlayContainerViewController mController;
@Before
@@ -74,8 +82,12 @@
when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
mController = new DreamOverlayContainerViewController(
- mDreamOverlayContainerView, mDreamOverlayContentView,
- mDreamOverlayStatusBarViewController);
+ mDreamOverlayContainerView,
+ mDreamOverlayContentView,
+ mDreamOverlayStatusBarViewController,
+ mHandler,
+ MAX_BURN_IN_OFFSET,
+ BURN_IN_PROTECTION_UPDATE_INTERVAL);
}
@Test
@@ -129,4 +141,37 @@
computeInsetsListenerCapture.getValue().onComputeInternalInsets(info);
assertNotNull(info.touchableRegion);
}
+
+ @Test
+ public void testBurnInProtectionStartsWhenContentViewAttached() {
+ mController.onViewAttached();
+ verify(mHandler).postDelayed(any(Runnable.class), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
+ }
+
+ @Test
+ public void testBurnInProtectionStopsWhenContentViewDetached() {
+ mController.onViewDetached();
+ verify(mHandler).removeCallbacks(any(Runnable.class));
+ }
+
+ @Test
+ public void testBurnInProtectionUpdatesPeriodically() {
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ mController.onViewAttached();
+ verify(mHandler).postDelayed(
+ runnableCaptor.capture(), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
+ runnableCaptor.getValue().run();
+ verify(mDreamOverlayContainerView).setTranslationX(anyFloat());
+ verify(mDreamOverlayContainerView).setTranslationY(anyFloat());
+ }
+
+ @Test
+ public void testBurnInProtectionReschedulesUpdate() {
+ ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
+ mController.onViewAttached();
+ verify(mHandler).postDelayed(
+ runnableCaptor.capture(), eq(BURN_IN_PROTECTION_UPDATE_INTERVAL));
+ runnableCaptor.getValue().run();
+ verify(mHandler).postDelayed(runnableCaptor.getValue(), BURN_IN_PROTECTION_UPDATE_INTERVAL);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/ComplicationProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/ComplicationProviderTest.java
similarity index 94%
rename from packages/SystemUI/tests/src/com/android/systemui/dreams/ComplicationProviderTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/ComplicationProviderTest.java
index 7365568..f538112 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/ComplicationProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/appwidgets/ComplicationProviderTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.dreams;
+package com.android.systemui.dreams.appwidgets;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.isNull;
@@ -33,8 +33,8 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestableContext;
-import com.android.systemui.dreams.appwidgets.AppWidgetProvider;
-import com.android.systemui.dreams.appwidgets.ComplicationProvider;
+import com.android.systemui.dreams.ComplicationHost;
+import com.android.systemui.dreams.ComplicationHostView;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.utils.leaks.LeakCheckedTest;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 7f35732..cf1a36a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -24,6 +24,7 @@
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BATTERY;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_BIOMETRIC_MESSAGE;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_DISCLOSURE;
+import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_LOGOUT;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_OWNER_INFO;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_RESTING;
import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT;
@@ -86,7 +87,6 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
-import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -132,8 +132,6 @@
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
- private LockIcon mLockIcon;
- @Mock
private StatusBarStateController mStatusBarStateController;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -738,6 +736,41 @@
verifyHideIndication(INDICATION_TYPE_OWNER_INFO);
}
+ @Test
+ public void testOnKeyguardShowingChanged_notShowing_resetsMessages() {
+ createController();
+
+ // GIVEN keyguard isn't showing
+ when(mKeyguardStateController.isShowing()).thenReturn(false);
+
+ // WHEN keyguard showing changed called
+ mKeyguardStateControllerCallback.onKeyguardShowingChanged();
+
+ // THEN messages are reset
+ verify(mRotateTextViewController).clearMessages();
+ assertThat(mTextView.getText()).isEqualTo("");
+ }
+
+ @Test
+ public void testOnKeyguardShowingChanged_showing_updatesPersistentMessages() {
+ createController();
+
+ // GIVEN keyguard is showing
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+
+ // WHEN keyguard showing changed called
+ mKeyguardStateControllerCallback.onKeyguardShowingChanged();
+
+ // THEN persistent messages are updated (in this case, most messages are hidden since
+ // no info is provided) - verify that this happens
+ verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_DISCLOSURE);
+ verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_OWNER_INFO);
+ verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_BATTERY);
+ verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_TRUST);
+ verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_ALIGNMENT);
+ verify(mRotateTextViewController).hideIndication(INDICATION_TYPE_LOGOUT);
+ }
+
private void sendUpdateDisclosureBroadcast() {
mBroadcastReceiver.onReceive(mContext, new Intent());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index a7f8b6e..f08180d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -459,7 +459,7 @@
mCollection.dismissNotification(entry1, defaultStats(entry1));
// THEN lifetime extenders are never queried
- verify(mExtender1, never()).shouldExtendLifetime(eq(entry1), anyInt());
+ verify(mExtender1, never()).maybeExtendLifetime(eq(entry1), anyInt());
}
@Test
@@ -912,9 +912,9 @@
mNoMan.retractNotif(notif2.sbn, REASON_APP_CANCEL);
// THEN each extender is asked whether to extend, even if earlier ones return true
- verify(mExtender1).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
- verify(mExtender2).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
- verify(mExtender3).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender1).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender2).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender3).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
// THEN the entry is not removed
assertTrue(mCollection.getAllNotifs().contains(entry2));
@@ -948,9 +948,9 @@
mExtender2.callback.onEndLifetimeExtension(mExtender2, entry2);
// THEN each extender is re-queried
- verify(mExtender1).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
- verify(mExtender2).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
- verify(mExtender3).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender1).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender2).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender3).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
// THEN the entry is not removed
assertTrue(mCollection.getAllNotifs().contains(entry2));
@@ -986,9 +986,9 @@
assertTrue(mCollection.getAllNotifs().contains(entry2));
// THEN we don't re-query the extenders
- verify(mExtender1, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
- verify(mExtender2, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
- verify(mExtender3, never()).shouldExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender1, never()).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender2, never()).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
+ verify(mExtender3, never()).maybeExtendLifetime(entry2, REASON_APP_CANCEL);
// THEN the entry properly records all extenders that returned true
assertEquals(singletonList(mExtender1), entry2.mLifetimeExtenders);
@@ -1469,6 +1469,18 @@
}
@Test
+ public void testCannotDismissNoClearNotifications() {
+ // GIVEN an no-clear notification
+ final NotificationEntry container = new NotificationEntryBuilder()
+ .setFlag(mContext, FLAG_NO_CLEAR, true)
+ .build();
+
+ // THEN its children are not dismissible
+ assertFalse(mCollection.shouldAutoDismissChildren(
+ container, container.getSbn().getGroupKey()));
+ }
+
+ @Test
public void testCanDismissFgsNotificationChildren() {
// GIVEN an FGS but not ongoing notification
final NotificationEntry container = new NotificationEntryBuilder()
@@ -1585,7 +1597,7 @@
}
@Override
- public boolean shouldExtendLifetime(
+ public boolean maybeExtendLifetime(
@NonNull NotificationEntry entry,
@CancellationReason int reason) {
return shouldExtendLifetime;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
index 0f6bd77..4143647 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/GutsCoordinatorTest.kt
@@ -73,43 +73,43 @@
@Test
fun testSimpleLifetimeExtension() {
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
notifGutsViewListener.onGutsClose(entry1)
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
}
@Test
fun testDoubleOpenLifetimeExtension() {
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
notifGutsViewListener.onGutsClose(entry1)
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
}
@Test
fun testTwoEntryLifetimeExtension() {
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry1, mock(NotificationGuts::class.java))
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
notifGutsViewListener.onGutsOpen(entry2, mock(NotificationGuts::class.java))
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isTrue()
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isTrue()
notifGutsViewListener.onGutsClose(entry1)
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry1)
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isTrue()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isTrue()
notifGutsViewListener.onGutsClose(entry2)
verify(lifetimeExtenderCallback).onEndLifetimeExtension(notifLifetimeExtender, entry2)
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry1, 0)).isFalse()
- assertThat(notifLifetimeExtender.shouldExtendLifetime(entry2, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(notifLifetimeExtender.maybeExtendLifetime(entry2, 0)).isFalse()
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
index b3ee5f8..8ee892c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java
@@ -142,7 +142,7 @@
addHUN(mEntry);
when(mHeadsUpManager.canRemoveImmediately(anyString())).thenReturn(false, true);
when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 0L);
- assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0));
mClock.advanceTime(1000L);
mExecutor.runAllReady();
verify(mHeadsUpManager, times(0))
@@ -156,7 +156,7 @@
when(mHeadsUpManager.isSticky(anyString())).thenReturn(true);
addHUN(mEntry);
when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L);
- assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0));
mClock.advanceTime(1000L);
mExecutor.runAllReady();
verify(mHeadsUpManager, times(0))
@@ -170,7 +170,7 @@
when(mHeadsUpManager.isSticky(anyString())).thenReturn(false);
addHUN(mEntry);
when(mHeadsUpManager.getEarliestRemovalTime(anyString())).thenReturn(1000L, 500L);
- assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, 0));
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, 0));
mClock.advanceTime(1000L);
mExecutor.runAllReady();
verify(mHeadsUpManager, times(1))
@@ -216,8 +216,8 @@
return true;
});
// THEN only the current HUN, mEntry, should be lifetimeExtended
- assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, /* cancellationReason */ 0));
- assertFalse(mNotifLifetimeExtender.shouldExtendLifetime(
+ assertTrue(mNotifLifetimeExtender.maybeExtendLifetime(mEntry, /* cancellationReason */ 0));
+ assertFalse(mNotifLifetimeExtender.maybeExtendLifetime(
new NotificationEntryBuilder()
.setPkg("test-package")
.build(), /* cancellationReason */ 0));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
index 0ce6ada..7073cc7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/RemoteInputCoordinatorTest.kt
@@ -101,27 +101,27 @@
@Test
fun testRemoteInputActive() {
`when`(remoteInputManager.isRemoteInputActive(entry1)).thenReturn(true)
- assertThat(remoteInputActiveExtender.shouldExtendLifetime(entry1, 0)).isTrue()
- assertThat(remoteInputHistoryExtender.shouldExtendLifetime(entry1, 0)).isFalse()
- assertThat(smartReplyHistoryExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(remoteInputActiveExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ assertThat(remoteInputHistoryExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(smartReplyHistoryExtender.maybeExtendLifetime(entry1, 0)).isFalse()
assertThat(listener.isNotificationKeptForRemoteInputHistory(entry1.key)).isFalse()
}
@Test
fun testRemoteInputHistory() {
`when`(remoteInputManager.shouldKeepForRemoteInputHistory(entry1)).thenReturn(true)
- assertThat(remoteInputActiveExtender.shouldExtendLifetime(entry1, 0)).isFalse()
- assertThat(remoteInputHistoryExtender.shouldExtendLifetime(entry1, 0)).isTrue()
- assertThat(smartReplyHistoryExtender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(remoteInputActiveExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(remoteInputHistoryExtender.maybeExtendLifetime(entry1, 0)).isTrue()
+ assertThat(smartReplyHistoryExtender.maybeExtendLifetime(entry1, 0)).isFalse()
assertThat(listener.isNotificationKeptForRemoteInputHistory(entry1.key)).isTrue()
}
@Test
fun testSmartReplyHistory() {
`when`(remoteInputManager.shouldKeepForSmartReplyHistory(entry1)).thenReturn(true)
- assertThat(remoteInputActiveExtender.shouldExtendLifetime(entry1, 0)).isFalse()
- assertThat(remoteInputHistoryExtender.shouldExtendLifetime(entry1, 0)).isFalse()
- assertThat(smartReplyHistoryExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(remoteInputActiveExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(remoteInputHistoryExtender.maybeExtendLifetime(entry1, 0)).isFalse()
+ assertThat(smartReplyHistoryExtender.maybeExtendLifetime(entry1, 0)).isTrue()
assertThat(listener.isNotificationKeptForRemoteInputHistory(entry1.key)).isTrue()
}
@@ -136,7 +136,7 @@
verify(lifetimeExtensionCallback, never()).onEndLifetimeExtension(any(), any())
// Start extending lifetime & validate that the extension is ended
- assertThat(remoteInputActiveExtender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(remoteInputActiveExtender.maybeExtendLifetime(entry1, 0)).isTrue()
assertThat(remoteInputActiveExtender.isExtending(entry1.key)).isTrue()
listener.onPanelCollapsed()
verify(lifetimeExtensionCallback).onEndLifetimeExtension(remoteInputActiveExtender, entry1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/legacy/GroupEventDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/legacy/GroupEventDispatcherTest.kt
new file mode 100644
index 0000000..c17fe6f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/legacy/GroupEventDispatcherTest.kt
@@ -0,0 +1,294 @@
+/*
+ * 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.systemui.statusbar.notification.collection.legacy
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.GroupEventDispatcher
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup
+import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener
+import com.android.systemui.statusbar.phone.NotificationGroupTestHelper
+import com.android.systemui.util.mockito.mock
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyNoMoreInteractions
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@RunWithLooper
+class GroupEventDispatcherTest : SysuiTestCase() {
+ val groupMap = mutableMapOf<String, NotificationGroup>()
+ val groupTestHelper = NotificationGroupTestHelper(mContext)
+
+ private val dispatcher = GroupEventDispatcher(groupMap::get)
+ private val listener: OnGroupChangeListener = mock()
+
+ @Before
+ fun setup() {
+ dispatcher.registerGroupChangeListener(listener)
+ }
+
+ @Test
+ fun testOnGroupsChangedUnbuffered() {
+ dispatcher.notifyGroupsChanged()
+ verify(listener).onGroupsChanged()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testOnGroupsChangedBuffered() {
+ dispatcher.openBufferScope()
+ dispatcher.notifyGroupsChanged()
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verify(listener).onGroupsChanged()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testOnGroupsChangedDoubleBuffered() {
+ dispatcher.openBufferScope()
+ dispatcher.notifyGroupsChanged()
+ dispatcher.openBufferScope() // open a nested buffer scope
+ dispatcher.notifyGroupsChanged()
+ dispatcher.closeBufferScope() // should NOT flush events
+ dispatcher.notifyGroupsChanged()
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope() // this SHOULD flush events
+ verify(listener).onGroupsChanged()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testOnGroupsChangedBufferCoalesces() {
+ dispatcher.openBufferScope()
+ dispatcher.notifyGroupsChanged()
+ dispatcher.notifyGroupsChanged()
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verify(listener).onGroupsChanged()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testOnGroupCreatedIsNeverBuffered() {
+ val group = addGroup(1)
+
+ dispatcher.openBufferScope()
+ dispatcher.notifyGroupCreated(group)
+ verify(listener).onGroupCreated(group, group.groupKey)
+ verifyNoMoreInteractions(listener)
+
+ dispatcher.closeBufferScope()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testOnGroupRemovedIsNeverBuffered() {
+ val group = addGroup(1)
+
+ dispatcher.openBufferScope()
+ dispatcher.notifyGroupRemoved(group)
+ verify(listener).onGroupRemoved(group, group.groupKey)
+ verifyNoMoreInteractions(listener)
+
+ dispatcher.closeBufferScope()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testAlertOverrideAddedUnbuffered() {
+ val group = addGroup(1)
+ val newAlertEntry = groupTestHelper.createChildNotification()
+ group.alertOverride = newAlertEntry
+ dispatcher.notifyAlertOverrideChanged(group, null)
+ verify(listener).onGroupAlertOverrideChanged(group, null, newAlertEntry)
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testAlertOverrideRemovedUnbuffered() {
+ val group = addGroup(1)
+ val oldAlertEntry = groupTestHelper.createChildNotification()
+ dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
+ verify(listener).onGroupAlertOverrideChanged(group, oldAlertEntry, null)
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testAlertOverrideChangedUnbuffered() {
+ val group = addGroup(1)
+ val oldAlertEntry = groupTestHelper.createChildNotification()
+ val newAlertEntry = groupTestHelper.createChildNotification()
+ group.alertOverride = newAlertEntry
+ dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
+ verify(listener).onGroupAlertOverrideChanged(group, oldAlertEntry, newAlertEntry)
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testAlertOverrideChangedBuffered() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ val oldAlertEntry = groupTestHelper.createChildNotification()
+ val newAlertEntry = groupTestHelper.createChildNotification()
+ group.alertOverride = newAlertEntry
+ dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verify(listener).onGroupAlertOverrideChanged(group, oldAlertEntry, newAlertEntry)
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testAlertOverrideIgnoredIfRemoved() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ val oldAlertEntry = groupTestHelper.createChildNotification()
+ val newAlertEntry = groupTestHelper.createChildNotification()
+ group.alertOverride = newAlertEntry
+ dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
+ verifyNoMoreInteractions(listener)
+ groupMap.clear()
+ dispatcher.closeBufferScope()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testAlertOverrideMultipleChangesBuffered() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ val oldAlertEntry = groupTestHelper.createChildNotification()
+ val newAlertEntry = groupTestHelper.createChildNotification()
+ group.alertOverride = null
+ dispatcher.notifyAlertOverrideChanged(group, oldAlertEntry)
+ group.alertOverride = newAlertEntry
+ dispatcher.notifyAlertOverrideChanged(group, null)
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verify(listener).onGroupAlertOverrideChanged(group, oldAlertEntry, newAlertEntry)
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testAlertOverrideTemporaryValueSwallowed() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ val stableAlertEntry = groupTestHelper.createChildNotification()
+ group.alertOverride = null
+ dispatcher.notifyAlertOverrideChanged(group, stableAlertEntry)
+ group.alertOverride = stableAlertEntry
+ dispatcher.notifyAlertOverrideChanged(group, null)
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testAlertOverrideTemporaryNullSwallowed() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ val temporaryAlertEntry = groupTestHelper.createChildNotification()
+ group.alertOverride = temporaryAlertEntry
+ dispatcher.notifyAlertOverrideChanged(group, null)
+ group.alertOverride = null
+ dispatcher.notifyAlertOverrideChanged(group, temporaryAlertEntry)
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testSuppressOnUnbuffered() {
+ val group = addGroup(1)
+ group.suppressed = true
+ dispatcher.notifySuppressedChanged(group)
+ verify(listener).onGroupSuppressionChanged(group, true)
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testSuppressOffUnbuffered() {
+ val group = addGroup(1)
+ group.suppressed = false
+ dispatcher.notifySuppressedChanged(group)
+ verify(listener).onGroupSuppressionChanged(group, false)
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testSuppressOnBuffered() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ group.suppressed = false
+ dispatcher.notifySuppressedChanged(group)
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verify(listener).onGroupSuppressionChanged(group, false)
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testSuppressOnIgnoredIfRemoved() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ group.suppressed = false
+ dispatcher.notifySuppressedChanged(group)
+ verifyNoMoreInteractions(listener)
+ groupMap.clear()
+ dispatcher.closeBufferScope()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testSuppressOnOffBuffered() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ group.suppressed = true
+ dispatcher.notifySuppressedChanged(group)
+ group.suppressed = false
+ dispatcher.notifySuppressedChanged(group)
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verifyNoMoreInteractions(listener)
+ }
+
+ @Test
+ fun testSuppressOnOffOnBuffered() {
+ dispatcher.openBufferScope()
+ val group = addGroup(1)
+ group.suppressed = true
+ dispatcher.notifySuppressedChanged(group)
+ group.suppressed = false
+ dispatcher.notifySuppressedChanged(group)
+ group.suppressed = true
+ dispatcher.notifySuppressedChanged(group)
+ verifyNoMoreInteractions(listener)
+ dispatcher.closeBufferScope()
+ verify(listener).onGroupSuppressionChanged(group, true)
+ verifyNoMoreInteractions(listener)
+ }
+
+ private fun addGroup(id: Int): NotificationGroup {
+ val group = NotificationGroup("group:$id")
+ groupMap[group.groupKey] = group
+ return group
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
index 37ad835..a09f3a3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/notifcollection/SelfTrackingLifetimeExtenderTest.kt
@@ -77,7 +77,7 @@
@Test
fun testNoExtend() {
`when`(shouldExtend.test(entry1)).thenReturn(false)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isFalse()
assertThat(extender.isExtending(entry1.key)).isFalse()
verify(onStarted, never()).accept(entry1)
verify(onCanceled, never()).accept(entry1)
@@ -86,7 +86,7 @@
@Test
fun testExtendThenCancelForRepost() {
`when`(shouldExtend.test(entry1)).thenReturn(true)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
verify(onStarted).accept(entry1)
verify(onCanceled, never()).accept(entry1)
assertThat(extender.isExtending(entry1.key)).isTrue()
@@ -108,7 +108,7 @@
@Test
fun testExtendThenEnd() {
`when`(shouldExtend.test(entry1)).thenReturn(true)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
verify(onStarted).accept(entry1)
assertThat(extender.isExtending(entry1.key)).isTrue()
extender.endLifetimeExtension(entry1.key)
@@ -119,7 +119,7 @@
@Test
fun testExtendThenEndAfterDelay() {
`when`(shouldExtend.test(entry1)).thenReturn(true)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
verify(onStarted).accept(entry1)
assertThat(extender.isExtending(entry1.key)).isTrue()
@@ -142,11 +142,11 @@
fun testExtendThenEndAll() {
`when`(shouldExtend.test(entry1)).thenReturn(true)
`when`(shouldExtend.test(entry2)).thenReturn(true)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
verify(onStarted).accept(entry1)
assertThat(extender.isExtending(entry1.key)).isTrue()
assertThat(extender.isExtending(entry2.key)).isFalse()
- assertThat(extender.shouldExtendLifetime(entry2, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry2, 0)).isTrue()
verify(onStarted).accept(entry2)
assertThat(extender.isExtending(entry1.key)).isTrue()
assertThat(extender.isExtending(entry2.key)).isTrue()
@@ -160,11 +160,11 @@
@Test
fun testExtendWithinEndCanReExtend() {
`when`(shouldExtend.test(entry1)).thenReturn(true)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
verify(onStarted, times(1)).accept(entry1)
`when`(callback.onEndLifetimeExtension(extender, entry1)).thenAnswer {
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
}
extender.endLifetimeExtension(entry1.key)
verify(onStarted, times(2)).accept(entry1)
@@ -174,11 +174,11 @@
@Test
fun testExtendWithinEndCanNotReExtend() {
`when`(shouldExtend.test(entry1)).thenReturn(true, false)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
verify(onStarted, times(1)).accept(entry1)
`when`(callback.onEndLifetimeExtension(extender, entry1)).thenAnswer {
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isFalse()
}
extender.endLifetimeExtension(entry1.key)
verify(onStarted, times(1)).accept(entry1)
@@ -188,11 +188,11 @@
@Test
fun testExtendWithinEndAllCanReExtend() {
`when`(shouldExtend.test(entry1)).thenReturn(true)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
verify(onStarted, times(1)).accept(entry1)
`when`(callback.onEndLifetimeExtension(extender, entry1)).thenAnswer {
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
}
extender.endAllLifetimeExtensions()
verify(onStarted, times(2)).accept(entry1)
@@ -202,11 +202,11 @@
@Test
fun testExtendWithinEndAllCanNotReExtend() {
`when`(shouldExtend.test(entry1)).thenReturn(true, false)
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isTrue()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isTrue()
verify(onStarted, times(1)).accept(entry1)
`when`(callback.onEndLifetimeExtension(extender, entry1)).thenAnswer {
- assertThat(extender.shouldExtendLifetime(entry1, 0)).isFalse()
+ assertThat(extender.maybeExtendLifetime(entry1, 0)).isFalse()
}
extender.endAllLifetimeExtensions()
verify(onStarted, times(1)).accept(entry1)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 37cf748..36a4c1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -354,7 +354,6 @@
TestNotificationPanelViewStateProvider() {}
private float mPanelViewExpandedHeight = 100f;
- private float mQsExpansionFraction = 0f;
private boolean mShouldHeadsUpBeVisible = false;
private float mLockscreenShadeDragProgress = 0f;
@@ -364,11 +363,6 @@
}
@Override
- public float getQsExpansionFraction() {
- return mQsExpansionFraction;
- }
-
- @Override
public boolean shouldHeadsUpBeVisible() {
return mShouldHeadsUpBeVisible;
}
@@ -382,10 +376,6 @@
this.mPanelViewExpandedHeight = panelViewExpandedHeight;
}
- public void setQsExpansionFraction(float qsExpansionFraction) {
- this.mQsExpansionFraction = qsExpansionFraction;
- }
-
public void setShouldHeadsUpBeVisible(boolean shouldHeadsUpBeVisible) {
this.mShouldHeadsUpBeVisible = shouldHeadsUpBeVisible;
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
index 9898b4b..c13b335 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelperTest.java
@@ -312,10 +312,11 @@
@Test
public void testUpdateChildToSummaryDoesNotTransfer() {
+ final String tag = "fooTag";
NotificationEntry summaryEntry =
mGroupTestHelper.createSummaryNotification(Notification.GROUP_ALERT_SUMMARY);
NotificationEntry childEntry =
- mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY, 47);
+ mGroupTestHelper.createChildNotification(Notification.GROUP_ALERT_SUMMARY, 47, tag);
mockHasHeadsUpContentView(childEntry, false);
mHeadsUpManager.showNotification(summaryEntry);
@@ -327,7 +328,7 @@
StatusBarNotification oldNotification = childEntry.getSbn();
childEntry.setSbn(
mGroupTestHelper.createSummaryNotification(
- Notification.GROUP_ALERT_SUMMARY, 47).getSbn());
+ Notification.GROUP_ALERT_SUMMARY, 47, tag).getSbn());
mGroupManager.onEntryUpdated(childEntry, oldNotification);
assertFalse(mGroupAlertTransferHelper.isAlertTransferPending(childEntry));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
index 6d170b6..5d7b154 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupManagerLegacyTest.java
@@ -21,14 +21,19 @@
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.Notification;
+import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.Log;
import androidx.test.filters.SmallTest;
@@ -64,8 +69,10 @@
private final NotificationGroupTestHelper mGroupTestHelper =
new NotificationGroupTestHelper(mContext);
- @Mock PeopleNotificationIdentifier mPeopleNotificationIdentifier;
- @Mock HeadsUpManager mHeadsUpManager;
+ @Mock
+ PeopleNotificationIdentifier mPeopleNotificationIdentifier;
+ @Mock
+ HeadsUpManager mHeadsUpManager;
@Before
public void setup() {
@@ -177,15 +184,25 @@
helpTestAlertOverrideWithSiblings(2);
}
+ @Test
+ public void testAlertOverrideWithSiblings_3() {
+ helpTestAlertOverrideWithSiblings(3);
+ }
+
+ @Test
+ public void testAlertOverrideWithSiblings_9() {
+ helpTestAlertOverrideWithSiblings(9);
+ }
+
/**
* Helper for testing various sibling counts
*/
private void helpTestAlertOverrideWithSiblings(int numSiblings) {
helpTestAlertOverride(
/* numSiblings */ numSiblings,
- /* summaryAlert */ Notification.GROUP_ALERT_SUMMARY,
- /* childAlert */ Notification.GROUP_ALERT_SUMMARY,
- /* siblingAlert */ Notification.GROUP_ALERT_SUMMARY,
+ /* summaryGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
+ /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
+ /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
/* expectAlertOverride */ true);
}
@@ -194,9 +211,9 @@
// tests that summary can have GROUP_ALERT_ALL and this still works
helpTestAlertOverride(
/* numSiblings */ 1,
- /* summaryAlert */ Notification.GROUP_ALERT_ALL,
- /* childAlert */ Notification.GROUP_ALERT_SUMMARY,
- /* siblingAlert */ Notification.GROUP_ALERT_SUMMARY,
+ /* summaryGroupAlert */ Notification.GROUP_ALERT_ALL,
+ /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
+ /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
/* expectAlertOverride */ true);
}
@@ -205,9 +222,9 @@
// Tests that if the summary alerts CHILDREN, there's no alertOverride
helpTestAlertOverride(
/* numSiblings */ 1,
- /* summaryAlert */ Notification.GROUP_ALERT_CHILDREN,
- /* childAlert */ Notification.GROUP_ALERT_SUMMARY,
- /* siblingAlert */ Notification.GROUP_ALERT_SUMMARY,
+ /* summaryGroupAlert */ Notification.GROUP_ALERT_CHILDREN,
+ /* priorityGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
+ /* siblingGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
/* expectAlertOverride */ false);
}
@@ -216,9 +233,9 @@
// Tests that if the children alert ALL, there's no alertOverride
helpTestAlertOverride(
/* numSiblings */ 1,
- /* summaryAlert */ Notification.GROUP_ALERT_SUMMARY,
- /* childAlert */ Notification.GROUP_ALERT_ALL,
- /* siblingAlert */ Notification.GROUP_ALERT_ALL,
+ /* summaryGroupAlert */ Notification.GROUP_ALERT_SUMMARY,
+ /* priorityGroupAlert */ Notification.GROUP_ALERT_ALL,
+ /* siblingGroupAlert */ Notification.GROUP_ALERT_ALL,
/* expectAlertOverride */ false);
}
@@ -229,17 +246,19 @@
* 3) when the priority entry is removed, these are reversed
*/
private void helpTestAlertOverride(int numSiblings,
- @Notification.GroupAlertBehavior int summaryAlert,
- @Notification.GroupAlertBehavior int childAlert,
- @Notification.GroupAlertBehavior int siblingAlert,
+ @Notification.GroupAlertBehavior int summaryGroupAlert,
+ @Notification.GroupAlertBehavior int priorityGroupAlert,
+ @Notification.GroupAlertBehavior int siblingGroupAlert,
boolean expectAlertOverride) {
// Create entries in an order so that the priority entry can be deemed the newest child.
NotificationEntry[] siblings = new NotificationEntry[numSiblings];
for (int i = 0; i < numSiblings; i++) {
- siblings[i] = mGroupTestHelper.createChildNotification(siblingAlert);
+ siblings[i] = mGroupTestHelper.createChildNotification(siblingGroupAlert, i, "sibling");
}
- NotificationEntry priorityEntry = mGroupTestHelper.createChildNotification(childAlert);
- NotificationEntry summaryEntry = mGroupTestHelper.createSummaryNotification(summaryAlert);
+ NotificationEntry priorityEntry =
+ mGroupTestHelper.createChildNotification(priorityGroupAlert, 0, "priority");
+ NotificationEntry summaryEntry =
+ mGroupTestHelper.createSummaryNotification(summaryGroupAlert, 0, "summary");
// The priority entry is an important conversation.
when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry)))
@@ -263,11 +282,20 @@
assertNull(summaryGroup.alertOverride);
return;
}
+ int max2Siblings = Math.min(2, numSiblings);
// Verify that the summary group has the priority child as its alertOverride
NotificationGroup summaryGroup = mGroupManager.getGroupForSummary(summaryEntry.getSbn());
assertEquals(priorityEntry, summaryGroup.alertOverride);
verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry);
+ verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, true);
+ if (numSiblings > 1) {
+ verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false);
+ }
+ verify(groupChangeListener).onGroupCreated(any(), eq(priorityEntry.getKey()));
+ verify(groupChangeListener).onGroupCreated(any(), eq(summaryEntry.getSbn().getGroupKey()));
+ verify(groupChangeListener, times(max2Siblings + 1)).onGroupsChanged();
+ verifyNoMoreInteractions(groupChangeListener);
// Verify that only the priority notification is isolated from the group
assertEquals(priorityEntry, mGroupManager.getGroupSummary(priorityEntry));
@@ -283,6 +311,92 @@
// verify that the alertOverride is removed when the priority notification is
assertNull(summaryGroup.alertOverride);
+ verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, priorityEntry, null);
+ verify(groupChangeListener).onGroupRemoved(any(), eq(priorityEntry.getKey()));
+ verify(groupChangeListener, times(max2Siblings + 2)).onGroupsChanged();
+ if (numSiblings == 0) {
+ verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false);
+ }
+ verifyNoMoreInteractions(groupChangeListener);
+ }
+
+ @Test
+ public void testAlertOverrideWhenUpdatingSummaryAtEnd() {
+ int numSiblings = 2;
+ int groupAlert = Notification.GROUP_ALERT_SUMMARY;
+ // Create entries in an order so that the priority entry can be deemed the newest child.
+ NotificationEntry[] siblings = new NotificationEntry[numSiblings];
+ for (int i = 0; i < numSiblings; i++) {
+ siblings[i] = mGroupTestHelper.createChildNotification(groupAlert, i, "sibling");
+ }
+ NotificationEntry priorityEntry =
+ mGroupTestHelper.createChildNotification(groupAlert, 0, "priority");
+ NotificationEntry summaryEntry =
+ mGroupTestHelper.createSummaryNotification(groupAlert, 0, "summary");
+
+ // The priority entry is an important conversation.
+ when(mPeopleNotificationIdentifier.getPeopleNotificationType(eq(priorityEntry)))
+ .thenReturn(PeopleNotificationIdentifier.TYPE_IMPORTANT_PERSON);
+
+ // Register a listener so we can verify that the event is sent.
+ OnGroupChangeListener groupChangeListener = mock(OnGroupChangeListener.class);
+ mGroupManager.registerGroupChangeListener(groupChangeListener);
+
+ // Add all the entries. The order here shouldn't matter.
+ mGroupManager.onEntryAdded(summaryEntry);
+ for (int i = 0; i < numSiblings; i++) {
+ mGroupManager.onEntryAdded(siblings[i]);
+ }
+ mGroupManager.onEntryAdded(priorityEntry);
+
+ int max2Siblings = Math.min(2, numSiblings);
+
+ // Verify that the summary group has the priority child as its alertOverride
+ NotificationGroup summaryGroup = mGroupManager.getGroupForSummary(summaryEntry.getSbn());
+ assertEquals(priorityEntry, summaryGroup.alertOverride);
verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry);
+ verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, true);
+ if (numSiblings > 1) {
+ verify(groupChangeListener).onGroupSuppressionChanged(summaryGroup, false);
+ }
+ verify(groupChangeListener).onGroupCreated(any(), eq(priorityEntry.getKey()));
+ verify(groupChangeListener).onGroupCreated(any(), eq(summaryEntry.getSbn().getGroupKey()));
+ verify(groupChangeListener, times(max2Siblings + 1)).onGroupsChanged();
+ verifyNoMoreInteractions(groupChangeListener);
+
+ // Verify that only the priority notification is isolated from the group
+ assertEquals(priorityEntry, mGroupManager.getGroupSummary(priorityEntry));
+ assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(priorityEntry));
+ // Verify that the siblings are NOT isolated from the group
+ for (int i = 0; i < numSiblings; i++) {
+ assertEquals(summaryEntry, mGroupManager.getGroupSummary(siblings[i]));
+ assertEquals(summaryEntry, mGroupManager.getLogicalGroupSummary(siblings[i]));
+ }
+
+ Log.d("NotificationGroupManagerLegacyTest",
+ "testAlertOverrideWhenUpdatingSummaryAtEnd: About to update summary");
+
+ StatusBarNotification oldSummarySbn = mGroupTestHelper.incrementPost(summaryEntry, 10000);
+ mGroupManager.onEntryUpdated(summaryEntry, oldSummarySbn);
+
+ verify(groupChangeListener, times(max2Siblings + 2)).onGroupsChanged();
+ verify(groupChangeListener).onGroupAlertOverrideChanged(summaryGroup, priorityEntry, null);
+ verifyNoMoreInteractions(groupChangeListener);
+
+ Log.d("NotificationGroupManagerLegacyTest",
+ "testAlertOverrideWhenUpdatingSummaryAtEnd: About to update priority child");
+
+ StatusBarNotification oldPrioritySbn = mGroupTestHelper.incrementPost(priorityEntry, 10000);
+ mGroupManager.onEntryUpdated(priorityEntry, oldPrioritySbn);
+
+ verify(groupChangeListener).onGroupRemoved(any(), eq(priorityEntry.getKey()));
+ verify(groupChangeListener, times(2)).onGroupCreated(any(), eq(priorityEntry.getKey()));
+ verify(groupChangeListener, times(2))
+ .onGroupAlertOverrideChanged(summaryGroup, null, priorityEntry);
+ verify(groupChangeListener, times(max2Siblings + 3)).onGroupsChanged();
+ verifyNoMoreInteractions(groupChangeListener);
+
+ Log.d("NotificationGroupManagerLegacyTest",
+ "testAlertOverrideWhenUpdatingSummaryAtEnd: Done");
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
index d405fea..ac32b9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationGroupTestHelper.java
@@ -16,6 +16,8 @@
package com.android.systemui.statusbar.phone;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -23,8 +25,10 @@
import android.app.Notification;
import android.content.Context;
import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
import com.android.systemui.R;
+import com.android.systemui.statusbar.SbnBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -44,15 +48,15 @@
}
public NotificationEntry createSummaryNotification() {
- return createSummaryNotification(Notification.GROUP_ALERT_ALL, mId++);
+ return createSummaryNotification(Notification.GROUP_ALERT_ALL, mId++, null);
}
public NotificationEntry createSummaryNotification(int groupAlertBehavior) {
- return createSummaryNotification(groupAlertBehavior, mId++);
+ return createSummaryNotification(groupAlertBehavior, mId++, null);
}
- public NotificationEntry createSummaryNotification(int groupAlertBehavior, int id) {
- return createEntry(id, true, groupAlertBehavior);
+ public NotificationEntry createSummaryNotification(int groupAlertBehavior, int id, String tag) {
+ return createEntry(id, tag, true, groupAlertBehavior);
}
public NotificationEntry createChildNotification() {
@@ -60,14 +64,15 @@
}
public NotificationEntry createChildNotification(int groupAlertBehavior) {
- return createEntry(mId++, false, groupAlertBehavior);
+ return createEntry(mId++, null, false, groupAlertBehavior);
}
- public NotificationEntry createChildNotification(int groupAlertBehavior, int id) {
- return createEntry(id, false, groupAlertBehavior);
+ public NotificationEntry createChildNotification(int groupAlertBehavior, int id, String tag) {
+ return createEntry(id, tag, false, groupAlertBehavior);
}
- public NotificationEntry createEntry(int id, boolean isSummary, int groupAlertBehavior) {
+ public NotificationEntry createEntry(int id, String tag, boolean isSummary,
+ int groupAlertBehavior) {
Notification notif = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setContentTitle("Title")
.setSmallIcon(R.drawable.ic_person)
@@ -80,6 +85,7 @@
.setOpPkg(TEST_PACKAGE_NAME)
.setId(id)
.setNotification(notif)
+ .setTag(tag)
.setUser(new UserHandle(ActivityManager.getCurrentUser()))
.build();
@@ -88,4 +94,16 @@
when(row.getEntry()).thenReturn(entry);
return entry;
}
+
+ public StatusBarNotification incrementPost(NotificationEntry entry, int increment) {
+ StatusBarNotification oldSbn = entry.getSbn();
+ final long oldPostTime = oldSbn.getPostTime();
+ final long newPostTime = oldPostTime + increment;
+ entry.setSbn(new SbnBuilder(oldSbn)
+ .setPostTime(newPostTime)
+ .build());
+ assertThat(oldSbn.getPostTime()).isEqualTo(oldPostTime);
+ assertThat(entry.getSbn().getPostTime()).isEqualTo(newPostTime);
+ return oldSbn;
+ }
}
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/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index aa69a09..91e9093 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -48,6 +48,7 @@
import android.accessibilityservice.TouchInteractionController;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.app.ActivityOptions;
import android.app.AlertDialog;
import android.app.PendingIntent;
@@ -262,6 +263,7 @@
private final UiAutomationManager mUiAutomationManager = new UiAutomationManager(mLock);
private final AccessibilityTraceManager mTraceManager;
+ private final CaptioningManagerImpl mCaptioningManagerImpl;
private int mCurrentUserId = UserHandle.USER_SYSTEM;
@@ -339,6 +341,7 @@
mA11yDisplayListener = a11yDisplayListener;
mMagnificationController = magnificationController;
mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
+ mCaptioningManagerImpl = new CaptioningManagerImpl(mContext);
if (inputFilter != null) {
mInputFilter = inputFilter;
mHasInputFilter = true;
@@ -373,6 +376,7 @@
mMagnificationController = new MagnificationController(this, mLock, mContext,
new MagnificationScaleProvider(mContext));
mMagnificationProcessor = new MagnificationProcessor(mMagnificationController);
+ mCaptioningManagerImpl = new CaptioningManagerImpl(mContext);
init();
}
@@ -3458,6 +3462,31 @@
}
@Override
+ @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
+ public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.SET_SYSTEM_AUDIO_CAPTION,
+ "setSystemAudioCaptioningRequested");
+
+ mCaptioningManagerImpl.setSystemAudioCaptioningRequested(isEnabled, userId);
+ }
+
+ @Override
+ public boolean isSystemAudioCaptioningUiRequested(int userId) {
+ return mCaptioningManagerImpl.isSystemAudioCaptioningUiRequested(userId);
+ }
+
+ @Override
+ @RequiresPermission(Manifest.permission.SET_SYSTEM_AUDIO_CAPTION)
+ public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.SET_SYSTEM_AUDIO_CAPTION,
+ "setSystemAudioCaptioningUiRequested");
+
+ mCaptioningManagerImpl.setSystemAudioCaptioningUiRequested(isEnabled, userId);
+ }
+
+ @Override
public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
synchronized (mLock) {
diff --git a/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java b/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java
new file mode 100644
index 0000000..39780d2
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/CaptioningManagerImpl.java
@@ -0,0 +1,87 @@
+/*
+ * 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.accessibility;
+
+import android.content.Context;
+import android.os.Binder;
+import android.provider.Settings;
+import android.view.accessibility.CaptioningManager;
+
+/**
+ * Implementation class for CaptioningManager's interface that need system server identity.
+ */
+public class CaptioningManagerImpl implements CaptioningManager.SystemAudioCaptioningAccessing {
+ private static final boolean SYSTEM_AUDIO_CAPTIONING_UI_DEFAULT_ENABLED = false;
+
+ private final Context mContext;
+
+ public CaptioningManagerImpl(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Sets the system audio caption enabled state.
+ *
+ * @param isEnabled The system audio captioning enabled state.
+ * @param userId The user Id.
+ */
+ @Override
+ public void setSystemAudioCaptioningRequested(boolean isEnabled, int userId) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ODI_CAPTIONS_ENABLED, isEnabled ? 1 : 0, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Gets the system audio caption UI enabled state.
+ *
+ * @param userId The user Id.
+ * @return the system audio caption UI enabled state.
+ */
+ @Override
+ public boolean isSystemAudioCaptioningUiRequested(int userId) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED,
+ SYSTEM_AUDIO_CAPTIONING_UI_DEFAULT_ENABLED ? 1 : 0, userId) == 1;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Sets the system audio caption UI enabled state.
+ *
+ * @param isEnabled The system audio captioning UI enabled state.
+ * @param userId The user Id.
+ */
+ @Override
+ public void setSystemAudioCaptioningUiRequested(boolean isEnabled, int userId) {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ODI_CAPTIONS_VOLUME_UI_ENABLED, isEnabled ? 1 : 0, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+}
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/CompanionDevicePresenceController.java b/services/companion/java/com/android/server/companion/CompanionDevicePresenceController.java
index 4447684..fc66817 100644
--- a/services/companion/java/com/android/server/companion/CompanionDevicePresenceController.java
+++ b/services/companion/java/com/android/server/companion/CompanionDevicePresenceController.java
@@ -48,7 +48,7 @@
public class CompanionDevicePresenceController {
private static final String LOG_TAG = "CompanionDevicePresenceController";
PerUser<ArrayMap<String, List<BoundService>>> mBoundServices;
- private static final String META_DATA_KEY_PRIMARY = "primary";
+ private static final String META_DATA_KEY_PRIMARY = "android.companion.primary";
private final CompanionDeviceManagerService mService;
public CompanionDevicePresenceController(CompanionDeviceManagerService service) {
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/companion/java/com/android/server/companion/PackageUtils.java b/services/companion/java/com/android/server/companion/PackageUtils.java
index 985daa3..fcb14a4 100644
--- a/services/companion/java/com/android/server/companion/PackageUtils.java
+++ b/services/companion/java/com/android/server/companion/PackageUtils.java
@@ -53,7 +53,7 @@
final class PackageUtils {
private static final Intent COMPANION_SERVICE_INTENT =
new Intent(CompanionDeviceService.SERVICE_INTERFACE);
- private static final String META_DATA_KEY_PRIMARY = "primary";
+ private static final String META_DATA_PRIMARY_TAG = "android.companion.primary";
static @Nullable PackageInfo getPackageInfo(@NonNull Context context,
@UserIdInt int userId, @NonNull String packageName) {
@@ -121,6 +121,6 @@
}
private static boolean isPrimaryCompanionDeviceService(ServiceInfo service) {
- return service.metaData != null && service.metaData.getBoolean(META_DATA_KEY_PRIMARY);
+ return service.metaData != null && service.metaData.getBoolean(META_DATA_PRIMARY_TAG);
}
}
diff --git a/services/companion/java/com/android/server/companion/PersistentDataStore.java b/services/companion/java/com/android/server/companion/PersistentDataStore.java
index ef3aa7f..3c8c3cb 100644
--- a/services/companion/java/com/android/server/companion/PersistentDataStore.java
+++ b/services/companion/java/com/android/server/companion/PersistentDataStore.java
@@ -67,17 +67,20 @@
* The class responsible for persisting Association records and other related information (such as
* previously used IDs) to a disk, and reading the data back from the disk.
*
- * Before Android T the data was stored to `companion_device_manager_associations.xml` file in
- * {@link Environment#getUserSystemDirectory(int)}
- * (eg. `/data/system/users/0/companion_device_manager_associations.xml`)
- * @see #getBaseLegacyStorageFileForUser(int)
+ * <p>
+ * Before Android T the data was stored in "companion_device_manager_associations.xml" file in
+ * {@link Environment#getUserSystemDirectory(int) /data/system/user/}.
*
- * Before Android T the data was stored using the v0 schema.
+ * See {@link #getBaseLegacyStorageFileForUser(int) getBaseLegacyStorageFileForUser()}.
*
- * @see #readAssociationsV0(TypedXmlPullParser, int, Collection)
- * @see #readAssociationV0(TypedXmlPullParser, int, int, Collection)
+ * <p>
+ * Before Android T the data was stored using the v0 schema. See:
+ * <ul>
+ * <li>{@link #readAssociationsV0(TypedXmlPullParser, int, Collection) readAssociationsV0()}.
+ * <li>{@link #readAssociationV0(TypedXmlPullParser, int, int, Collection) readAssociationV0()}.
+ * </ul>
*
- * The following snippet is a sample of a the file that is using v0 schema.
+ * The following snippet is a sample of a file that is using v0 schema.
* <pre>{@code
* <associations>
* <association
@@ -93,24 +96,28 @@
* </associations>
* }</pre>
*
+ * <p>
+ * Since Android T the data is stored to "companion_device_manager.xml" file in
+ * {@link Environment#getDataSystemDeDirectory(int) /data/system_de/}.
*
- * Since Android T the data is stored to `companion_device_manager.xml` file in
- * {@link Environment#getDataSystemDeDirectory(int)}.
- * (eg. `/data/system_de/0/companion_device_manager.xml`)
- * @see #getBaseStorageFileForUser(int)
-
+ * See {@link #getBaseStorageFileForUser(int) getBaseStorageFileForUser()}
+ *
+ * <p>
* Since Android T the data is stored using the v1 schema.
- * In the v1 schema, a list of the previously used IDs is storead along with the association
+ *
+ * In the v1 schema, a list of the previously used IDs is stored along with the association
* records.
- * V1 schema adds a new optional `display_name` attribute, and makes the `mac_address` attribute
+ *
+ * V1 schema adds a new optional "display_name" attribute, and makes the "mac_address" attribute
* optional.
+ * <ul>
+ * <li> {@link #CURRENT_PERSISTENCE_VERSION}
+ * <li> {@link #readAssociationsV1(TypedXmlPullParser, int, Collection) readAssociationsV1()}
+ * <li> {@link #readAssociationV1(TypedXmlPullParser, int, Collection) readAssociationV1()}
+ * <li> {@link #readPreviouslyUsedIdsV1(TypedXmlPullParser, Map) readPreviouslyUsedIdsV1()}
+ * </ul>
*
- * @see #CURRENT_PERSISTENCE_VERSION
- * @see #readAssociationsV1(TypedXmlPullParser, int, Collection)
- * @see #readAssociationV1(TypedXmlPullParser, int, Collection)
- * @see #readPreviouslyUsedIdsV1(TypedXmlPullParser, Map)
- *
- * The following snippet is a sample of a the file that is using v0 schema.
+ * The following snippet is a sample of a file that is using v0 schema.
* <pre>{@code
* <state persistence-version="1">
* <associations>
@@ -206,6 +213,8 @@
final AtomicFile file = getStorageFileForUser(userId);
if (DEBUG) Slog.d(LOG_TAG, " > File=" + file.getBaseFile().getPath());
+ // getStorageFileForUser() ALWAYS returns the SAME OBJECT, which allows us to synchronize
+ // accesses to the file on the file system using this AtomicFile object.
synchronized (file) {
File legacyBaseFile = null;
final AtomicFile readFrom;
@@ -269,6 +278,8 @@
final AtomicFile file = getStorageFileForUser(userId);
if (DEBUG) Slog.d(LOG_TAG, " > File=" + file.getBaseFile().getPath());
+ // getStorageFileForUser() ALWAYS returns the SAME OBJECT, which allows us to synchronize
+ // accesses to the file on the file system using this AtomicFile object.
synchronized (file) {
persistStateToFileLocked(file, associations, previouslyUsedIdsPerPackage);
}
@@ -329,6 +340,13 @@
});
}
+ /**
+ * Creates and caches {@link AtomicFile} object that represents the back-up file for the given
+ * user.
+ *
+ * IMPORTANT: the method will ALWAYS return the same {@link AtomicFile} object, which makes it
+ * possible to synchronize reads and writes to the file using the returned object.
+ */
private @NonNull AtomicFile getStorageFileForUser(@UserIdInt int userId) {
return mUserIdToStorageFile.computeIfAbsent(userId,
u -> new AtomicFile(getBaseStorageFileForUser(userId)));
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/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index 9b2948f..60cae4d 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -30,7 +30,6 @@
import android.content.IntentSender;
import android.content.pm.SigningDetails.CertCapabilities;
import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.parsing.component.ParsedMainComponent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -50,6 +49,7 @@
import com.android.server.pm.pkg.AndroidPackageApi;
import com.android.server.pm.pkg.PackageState;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.mutate.PackageStateMutator;
import java.io.IOException;
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/SerialService.java b/services/core/java/com/android/server/SerialService.java
index 1abe458..e915fa1 100644
--- a/services/core/java/com/android/server/SerialService.java
+++ b/services/core/java/com/android/server/SerialService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import android.annotation.EnforcePermission;
import android.content.Context;
import android.hardware.ISerialManager;
import android.os.ParcelFileDescriptor;
@@ -34,9 +35,8 @@
com.android.internal.R.array.config_serialPorts);
}
+ @EnforcePermission(android.Manifest.permission.SERIAL_PORT)
public String[] getSerialPorts() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
-
ArrayList<String> ports = new ArrayList<String>();
for (int i = 0; i < mSerialPorts.length; i++) {
String path = mSerialPorts[i];
@@ -49,8 +49,8 @@
return result;
}
+ @EnforcePermission(android.Manifest.permission.SERIAL_PORT)
public ParcelFileDescriptor openSerialPort(String path) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null);
for (int i = 0; i < mSerialPorts.length; i++) {
if (mSerialPorts[i].equals(path)) {
return native_open(path);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 7993936..b92556b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3472,11 +3472,9 @@
}
private int getAllowMode(Intent service, @Nullable String callingPackage) {
- if (callingPackage == null || service.getComponent() == null) {
- return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
- }
- if (callingPackage.equals(service.getComponent().getPackageName())) {
- return ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
+ if (callingPackage != null && service.getComponent() != null
+ && callingPackage.equals(service.getComponent().getPackageName())) {
+ return ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
} else {
return ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 70bd734..f67e732 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -233,11 +233,11 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ProviderInfoList;
import android.content.pm.ResolveInfo;
-import android.content.pm.SELinuxUtil;
+import com.android.server.pm.pkg.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.TestUtilityService;
import android.content.pm.UserInfo;
-import android.content.pm.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -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;
@@ -10359,10 +10360,6 @@
if (thread != null) {
pw.println("\n\n** Cache info for pid " + pid + " [" + r.processName + "] **");
pw.flush();
- if (pid == MY_PID) {
- PropertyInvalidatedCache.dumpCacheInfo(fd, args);
- continue;
- }
try {
TransferPipe tp = new TransferPipe();
try {
@@ -13312,6 +13309,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/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index a7864b9..028a0ec 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -26,10 +26,10 @@
import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
import static android.app.ActivityManager.USER_OP_IS_CURRENT;
import static android.app.ActivityManager.USER_OP_SUCCESS;
-import static android.app.ActivityManagerInternal.ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE;
import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
import static android.os.PowerWhitelistManager.REASON_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.REASON_LOCKED_BOOT_COMPLETED;
import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
@@ -2153,11 +2153,10 @@
callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
// If the caller does not have either permission, they are always doomed.
allow = false;
- } else if (allowMode == ALLOW_NON_FULL) {
+ } else if (allowMode == ALLOW_NON_FULL || allowMode == ALLOW_PROFILES_OR_NON_FULL) {
// We are blanket allowing non-full access, you lucky caller!
allow = true;
- } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE
- || allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) {
// We may or may not allow this depending on whether the two users are
// in the same profile.
allow = isSameProfileGroup;
@@ -2184,12 +2183,13 @@
builder.append("; this requires ");
builder.append(INTERACT_ACROSS_USERS_FULL);
if (allowMode != ALLOW_FULL_ONLY) {
- if (allowMode == ALLOW_NON_FULL || isSameProfileGroup) {
+ if (allowMode == ALLOW_NON_FULL
+ || allowMode == ALLOW_PROFILES_OR_NON_FULL
+ || (allowMode == ALLOW_NON_FULL_IN_PROFILE && isSameProfileGroup)) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_USERS);
}
- if (isSameProfileGroup
- && allowMode == ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ if (isSameProfileGroup && allowMode == ALLOW_PROFILES_OR_NON_FULL) {
builder.append(" or ");
builder.append(INTERACT_ACROSS_PROFILES);
}
@@ -2216,19 +2216,14 @@
private boolean canInteractWithAcrossProfilesPermission(
int allowMode, boolean isSameProfileGroup, int callingPid, int callingUid,
String callingPackage) {
- if (allowMode != ALLOW_ALL_PROFILE_PERMISSIONS_IN_PROFILE) {
+ if (allowMode != ALLOW_PROFILES_OR_NON_FULL) {
return false;
}
if (!isSameProfileGroup) {
return false;
}
- return PermissionChecker.PERMISSION_GRANTED
- == PermissionChecker.checkPermissionForPreflight(
- mInjector.getContext(),
- INTERACT_ACROSS_PROFILES,
- callingPid,
- callingUid,
- callingPackage);
+ return mInjector.checkPermissionForPreflight(INTERACT_ACROSS_PROFILES, callingPid,
+ callingUid, callingPackage);
}
int unsafeConvertIncomingUser(@UserIdInt int userId) {
@@ -3157,6 +3152,12 @@
return mService.checkComponentPermission(permission, pid, uid, owningUid, exported);
}
+ boolean checkPermissionForPreflight(String permission, int pid, int uid, String pkg) {
+ return PermissionChecker.PERMISSION_GRANTED
+ == PermissionChecker.checkPermissionForPreflight(
+ getContext(), permission, pid, uid, pkg);
+ }
+
protected void startHomeActivity(@UserIdInt int userId, String reason) {
mService.mAtmInternal.startHomeActivity(userId, reason);
}
@@ -3234,7 +3235,7 @@
mService.mAtmInternal.clearLockedTasks(reason);
}
- protected boolean isCallerRecents(int callingUid) {
+ boolean isCallerRecents(int callingUid) {
return mService.mAtmInternal.isCallerRecents(callingUid);
}
diff --git a/services/core/java/com/android/server/app/OWNERS b/services/core/java/com/android/server/app/OWNERS
index aaebbfa..221e06c 100644
--- a/services/core/java/com/android/server/app/OWNERS
+++ b/services/core/java/com/android/server/app/OWNERS
@@ -1 +1 @@
-per-file GameManager* = file:/GAME_MANAGER_OWNERS
+per-file Game* = file:/GAME_MANAGER_OWNERS
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 3c557d0..40fda4c 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -113,7 +113,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
import android.content.pm.UserInfo;
-import android.content.pm.parsing.component.ParsedAttribution;
+import com.android.server.pm.pkg.component.ParsedAttribution;
import android.database.ContentObserver;
import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
import android.net.Uri;
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/communal/CommunalManagerService.java b/services/core/java/com/android/server/communal/CommunalManagerService.java
deleted file mode 100644
index 600313b..0000000
--- a/services/core/java/com/android/server/communal/CommunalManagerService.java
+++ /dev/null
@@ -1,69 +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.communal;
-
-import android.Manifest;
-import android.annotation.RequiresPermission;
-import android.app.communal.ICommunalManager;
-import android.content.Context;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.SystemService;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * System service for handling Communal Mode state.
- */
-public final class CommunalManagerService extends SystemService {
- private final Context mContext;
- private final AtomicBoolean mCommunalViewIsShowing = new AtomicBoolean(false);
- private final BinderService mBinderService;
-
- public CommunalManagerService(Context context) {
- super(context);
- mContext = context;
- mBinderService = new BinderService();
- }
-
- @VisibleForTesting
- BinderService getBinderServiceInstance() {
- return mBinderService;
- }
-
- @Override
- public void onStart() {
- publishBinderService(Context.COMMUNAL_SERVICE, mBinderService);
- }
-
- private final class BinderService extends ICommunalManager.Stub {
- /**
- * Sets whether or not we are in communal mode.
- */
- @RequiresPermission(Manifest.permission.WRITE_COMMUNAL_STATE)
- @Override
- public void setCommunalViewShowing(boolean isShowing) {
- mContext.enforceCallingPermission(Manifest.permission.WRITE_COMMUNAL_STATE,
- Manifest.permission.WRITE_COMMUNAL_STATE
- + "permission required to modify communal state.");
- if (mCommunalViewIsShowing.get() == isShowing) {
- return;
- }
- mCommunalViewIsShowing.set(isShowing);
- }
- }
-}
diff --git a/services/core/java/com/android/server/communal/OWNERS b/services/core/java/com/android/server/communal/OWNERS
deleted file mode 100644
index b02883d..0000000
--- a/services/core/java/com/android/server/communal/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-brycelee@google.com
-justinkoh@google.com
-lusilva@google.com
-xilei@google.com
\ No newline at end of file
diff --git a/services/core/java/com/android/server/communal/TEST_MAPPING b/services/core/java/com/android/server/communal/TEST_MAPPING
deleted file mode 100644
index 026e9bb..0000000
--- a/services/core/java/com/android/server/communal/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "FrameworksMockingServicesTests",
- "options": [
- {
- "include-filter": "com.android.server.communal"
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/display/HighBrightnessModeController.java b/services/core/java/com/android/server/display/HighBrightnessModeController.java
index 16273ce..b3be894b 100644
--- a/services/core/java/com/android/server/display/HighBrightnessModeController.java
+++ b/services/core/java/com/android/server/display/HighBrightnessModeController.java
@@ -91,6 +91,7 @@
private int mHeight;
private float mAmbientLux;
private int mDisplayStatsId;
+ private int mHbmStatsState = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF;
/**
* If HBM is currently running, this is the start time for the current HBM session.
@@ -278,6 +279,7 @@
pw.println(" mHbmMode=" + BrightnessInfo.hbmToString(mHbmMode)
+ (mHbmMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
? "(" + getHdrBrightnessValue() + ")" : ""));
+ pw.println(" mHbmStatsState=" + hbmStatsStateToString(mHbmStatsState));
pw.println(" mHbmData=" + mHbmData);
pw.println(" mAmbientLux=" + mAmbientLux
+ (mIsAutoBrightnessEnabled ? "" : " (old/invalid)"));
@@ -444,8 +446,8 @@
private void updateHbmMode() {
int newHbmMode = calculateHighBrightnessMode();
+ updateHbmStats(mHbmMode, newHbmMode);
if (mHbmMode != newHbmMode) {
- updateHbmStats(mHbmMode, newHbmMode);
mHbmMode = newHbmMode;
mHbmChangeCallback.run();
}
@@ -453,11 +455,16 @@
private void updateHbmStats(int mode, int newMode) {
int state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF;
- if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR) {
+ if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR
+ && getHdrBrightnessValue() > mHbmData.transitionPoint) {
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR;
} else if (newMode == BrightnessInfo.HIGH_BRIGHTNESS_MODE_SUNLIGHT) {
state = FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT;
}
+ if (state == mHbmStatsState) {
+ return;
+ }
+ mHbmStatsState = state;
int reason =
FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__REASON__HBM_TRANSITION_REASON_UNKNOWN;
@@ -491,6 +498,19 @@
mInjector.reportHbmStateChange(mDisplayStatsId, state, reason);
}
+ private String hbmStatsStateToString(int hbmStatsState) {
+ switch (hbmStatsState) {
+ case FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_OFF:
+ return "HBM_OFF";
+ case FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR:
+ return "HBM_ON_HDR";
+ case FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_SUNLIGHT:
+ return "HBM_ON_SUNLIGHT";
+ default:
+ return String.valueOf(hbmStatsState);
+ }
+ }
+
private int calculateHighBrightnessMode() {
if (!deviceSupportsHbm()) {
return BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
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 4d125c3..ec49b47 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -228,10 +228,7 @@
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;
- /**
- * package-private because this is also used by {@link InputMethodBindingController}.
- */
- static final int MSG_INITIALIZE_IME = 1040;
+ 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;
@@ -246,10 +243,7 @@
private static final int MSG_SET_INTERACTIVE = 3030;
private static final int MSG_REPORT_FULLSCREEN_MODE = 3045;
- /**
- * package-private because this is also used by {@link InputMethodMenuController}.
- */
- static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
+ private static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
private static final int MSG_SYSTEM_UNLOCK_USER = 5000;
private static final int MSG_DISPATCH_ON_INPUT_METHOD_LIST_UPDATED = 5010;
@@ -284,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<>();
@@ -1470,31 +1464,6 @@
}
}
- private static final class MethodCallback extends IInputSessionCallback.Stub {
- private final InputMethodManagerService mParentIMMS;
- private final IInputMethod mMethod;
- private final InputChannel mChannel;
-
- MethodCallback(InputMethodManagerService imms, IInputMethod method,
- InputChannel channel) {
- mParentIMMS = imms;
- mMethod = method;
- mChannel = channel;
- }
-
- @Override
- public void sessionCreated(IInputMethodSession session) {
- Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.sessionCreated");
- final long ident = Binder.clearCallingIdentity();
- try {
- mParentIMMS.onSessionCreated(mMethod, session, mChannel);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
- }
- }
-
private static final class UserSwitchHandlerTask implements Runnable {
final InputMethodManagerService mService;
@@ -1812,10 +1781,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);
@@ -2247,7 +2216,7 @@
}
}
- void executeOrSendMessage(IInterface target, Message msg) {
+ private void executeOrSendMessage(IInterface target, Message msg) {
if (target.asBinder() instanceof Binder) {
mCaller.sendMessage(msg);
} else {
@@ -2533,39 +2502,52 @@
}
@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();
}
- void onSessionCreated(IInputMethod method, IInputMethodSession session,
- InputChannel channel) {
- synchronized (ImfLock.class) {
- if (mUserSwitchHandlerTask != null) {
- // We have a pending user-switching task so it's better to just ignore this session.
- channel.dispose();
- return;
- }
- IInputMethod curMethod = getCurMethodLocked();
- if (curMethod != null && method != null
- && curMethod.asBinder() == method.asBinder()) {
- if (mCurClient != null) {
- clearClientSessionLocked(mCurClient);
- mCurClient.curSession = new SessionState(mCurClient,
- method, session, channel);
- InputBindResult res = attachNewInputLocked(
- StartInputReason.SESSION_CREATED_BY_IME, true);
- if (res.method != null) {
- executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
- MSG_BIND_CLIENT, mCurClient.client, res));
- }
+ @BinderThread
+ void onSessionCreated(IInputMethod method, IInputMethodSession session, InputChannel channel) {
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMMS.onSessionCreated");
+ try {
+ synchronized (ImfLock.class) {
+ if (mUserSwitchHandlerTask != null) {
+ // We have a pending user-switching task so it's better to just ignore this
+ // session.
+ channel.dispose();
return;
}
+ IInputMethod curMethod = getCurMethodLocked();
+ if (curMethod != null && method != null
+ && curMethod.asBinder() == method.asBinder()) {
+ if (mCurClient != null) {
+ clearClientSessionLocked(mCurClient);
+ mCurClient.curSession = new SessionState(mCurClient,
+ method, session, channel);
+ InputBindResult res = attachNewInputLocked(
+ StartInputReason.SESSION_CREATED_BY_IME, true);
+ if (res.method != null) {
+ executeOrSendMessage(mCurClient.client, mCaller.obtainMessageOO(
+ MSG_BIND_CLIENT, mCurClient.client, res));
+ }
+ return;
+ }
+ }
}
- }
- // Session abandoned. Close its associated input channel.
- channel.dispose();
+ // Session abandoned. Close its associated input channel.
+ channel.dispose();
+ } finally {
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ }
}
@GuardedBy("ImfLock.class")
@@ -2602,7 +2584,17 @@
IInputMethod curMethod = getCurMethodLocked();
executeOrSendMessage(curMethod, mCaller.obtainMessageOOO(
MSG_CREATE_SESSION, curMethod, channels[1],
- new MethodCallback(this, curMethod, channels[0])));
+ new IInputSessionCallback.Stub() {
+ @Override
+ public void sessionCreated(IInputMethodSession session) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ onSessionCreated(curMethod, session, channels[0]);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }));
}
}
@@ -4422,9 +4414,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/integrity/AppIntegrityManagerServiceImpl.java b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
index 09780f3..6676987 100644
--- a/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
+++ b/services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java
@@ -45,7 +45,7 @@
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
-import android.content.pm.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.net.Uri;
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 1657b22..d459f8d 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -239,18 +239,13 @@
*/
private void notifyInstallerOfAppWhoseLocaleChanged(String appPackageName, int userId,
LocaleList locales) {
- try {
- String installingPackageName = mContext.getPackageManager()
- .getInstallSourceInfo(appPackageName).getInstallingPackageName();
- if (installingPackageName != null) {
- Intent intent = createBaseIntent(Intent.ACTION_APPLICATION_LOCALE_CHANGED,
- appPackageName, locales);
- //Set package name to ensure that only installer of the app receives this intent.
- intent.setPackage(installingPackageName);
- mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
- }
- } catch (PackageManager.NameNotFoundException e) {
- Slog.w(TAG, "Package not found " + appPackageName);
+ String installingPackageName = getInstallingPackageName(appPackageName);
+ if (installingPackageName != null) {
+ Intent intent = createBaseIntent(Intent.ACTION_APPLICATION_LOCALE_CHANGED,
+ appPackageName, locales);
+ //Set package name to ensure that only installer of the app receives this intent.
+ intent.setPackage(installingPackageName);
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
}
@@ -291,8 +286,7 @@
*/
private boolean isPackageOwnedByCaller(String appPackageName, int userId,
@Nullable AppLocaleChangedAtomRecord atomRecordForMetrics) {
- final int uid = mPackageManagerInternal
- .getPackageUid(appPackageName, /* flags */ 0, userId);
+ final int uid = getPackageUid(appPackageName, userId);
if (uid < 0) {
Slog.w(TAG, "Unknown package " + appPackageName + " for user " + userId);
if (atomRecordForMetrics != null) {
@@ -336,13 +330,17 @@
false /* allowAll */, ActivityManagerInternal.ALLOW_NON_FULL,
"getApplicationLocales", appPackageName);
- // This function handles two types of query operations:
+ // This function handles three types of query operations:
// 1.) A normal, non-privileged app querying its own locale.
- // 2.) A privileged system service querying locales of another package.
+ // 2.) The installer of the given app querying locales of a package installed
+ // by said installer.
+ // 3.) A privileged system service querying locales of another package.
// The least privileged case is a normal app performing a query, so check that first and
- // get locales if the package name is owned by the app. Next, check if the caller has the
- // necessary permission and get locales.
- if (!isPackageOwnedByCaller(appPackageName, userId)) {
+ // get locales if the package name is owned by the app. Next check if the calling app
+ // is the installer of the given app and get locales. If neither conditions matched,
+ // check if the caller has the necessary permission and fetch locales.
+ if (!isPackageOwnedByCaller(appPackageName, userId)
+ && !isCallerInstaller(appPackageName, userId)) {
enforceReadAppSpecificLocalesPermission();
}
final long token = Binder.clearCallingIdentity();
@@ -374,12 +372,41 @@
return locales != null ? locales : LocaleList.getEmptyLocaleList();
}
+ /**
+ * Checks if the calling app is the installer of the app whose locale changed.
+ */
+ private boolean isCallerInstaller(String appPackageName, int userId) {
+ String installingPackageName = getInstallingPackageName(appPackageName);
+ if (installingPackageName != null) {
+ // Get the uid of installer-on-record to compare with the calling uid.
+ int installerUid = getPackageUid(installingPackageName, userId);
+ return installerUid >= 0 && UserHandle.isSameApp(Binder.getCallingUid(), installerUid);
+ }
+ return false;
+ }
+
private void enforceReadAppSpecificLocalesPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_APP_SPECIFIC_LOCALES,
"getApplicationLocales");
}
+ private int getPackageUid(String appPackageName, int userId) {
+ return mPackageManagerInternal
+ .getPackageUid(appPackageName, /* flags */ 0, userId);
+ }
+
+ @Nullable
+ private String getInstallingPackageName(String packageName) {
+ try {
+ return mContext.getPackageManager()
+ .getInstallSourceInfo(packageName).getInstallingPackageName();
+ } catch (PackageManager.NameNotFoundException e) {
+ Slog.w(TAG, "Package not found " + packageName);
+ }
+ return null;
+ }
+
/**
* Dumps useful info related to service.
*/
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 047a701..38781fa 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -33,7 +33,7 @@
import android.content.om.OverlayIdentifier;
import android.content.om.OverlayInfo;
import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
import android.os.FabricatedOverlayInfo;
import android.os.FabricatedOverlayInternal;
import android.text.TextUtils;
@@ -492,7 +492,7 @@
Set<PackageAndUser> registerFabricatedOverlay(
@NonNull final FabricatedOverlayInternal overlay)
throws OperationFailedException {
- if (ParsingPackageUtils.validateName(overlay.overlayName,
+ if (FrameworkParsingPackageUtils.validateName(overlay.overlayName,
false /* requireSeparator */, true /* requireFilename */) != null) {
throw new OperationFailedException(
"overlay name can only consist of alphanumeric characters, '_', and '.'");
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index a1c97a8..6f10a6b 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -32,9 +32,9 @@
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.component.ParsedApexSystemService;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.component.ParsedApexSystemService;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Binder;
@@ -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/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index 22cd06d..a66af3c 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -24,7 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageManager;
-import android.content.pm.SELinuxUtil;
+import com.android.server.pm.pkg.SELinuxUtil;
import android.content.pm.UserInfo;
import android.os.CreateAppDataArgs;
import android.os.Environment;
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 6f54625..b916de3 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -33,11 +33,11 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.SigningDetails;
import android.content.pm.UserInfo;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedProvider;
import android.os.Binder;
import android.os.Process;
import android.os.Trace;
diff --git a/services/core/java/com/android/server/pm/ComponentResolver.java b/services/core/java/com/android/server/pm/ComponentResolver.java
index 6ec3405..cd4244b 100644
--- a/services/core/java/com/android/server/pm/ComponentResolver.java
+++ b/services/core/java/com/android/server/pm/ComponentResolver.java
@@ -36,14 +36,14 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.parsing.component.ComponentMutateUtils;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedProviderImpl;
-import android.content.pm.parsing.component.ParsedService;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedProviderImpl;
+import com.android.server.pm.pkg.component.ParsedService;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index e37aaa5..2aa0e01 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -92,14 +92,14 @@
import android.content.pm.SigningInfo;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.pkg.PackageUserStateUtils;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.PackageUserStateUtils;
import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
diff --git a/services/core/java/com/android/server/pm/InitAppsHelper.java b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
similarity index 61%
rename from services/core/java/com/android/server/pm/InitAppsHelper.java
rename to services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
index a5e6d6f..9efe81a 100644
--- a/services/core/java/com/android/server/pm/InitAppsHelper.java
+++ b/services/core/java/com/android/server/pm/InitAndSystemPackageHelper.java
@@ -31,9 +31,7 @@
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
-import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.pm.parsing.ParsingPackageUtils;
import android.os.Environment;
import android.os.SystemClock;
import android.os.Trace;
@@ -48,6 +46,7 @@
import com.android.server.pm.parsing.PackageCacher;
import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.utils.WatchedArrayMap;
import java.io.File;
@@ -60,25 +59,14 @@
* further cleanup and eventually all the installation/scanning related logic will go to another
* class.
*/
-final class InitAppsHelper {
+final class InitAndSystemPackageHelper {
private final PackageManagerService mPm;
+
private final List<ScanPartition> mDirsToScanAsSystem;
private final int mScanFlags;
private final int mSystemParseFlags;
private final int mSystemScanFlags;
private final InstallPackageHelper mInstallPackageHelper;
- private final ApexManager mApexManager;
- private final PackageParser2 mPackageParser;
- private final ExecutorService mExecutorService;
- /* Tracks how long system scan took */
- private long mSystemScanTime;
- /* Track of the number of cached system apps */
- private int mCachedSystemApps;
- /* Track of the number of system apps */
- private int mSystemPackagesCount;
- private final boolean mIsDeviceUpgrading;
- private final boolean mIsOnlyCoreApps;
- private final List<ScanPartition> mSystemPartitions;
/**
* Tracks new system packages [received in an OTA] that we expect to
@@ -86,39 +74,26 @@
* are package location.
*/
private final ArrayMap<String, File> mExpectingBetter = new ArrayMap<>();
- /* Tracks of any system packages that no longer exist that needs to be pruned. */
- private final List<String> mPossiblyDeletedUpdatedSystemApps = new ArrayList<>();
- // Tracks of stub packages that must either be replaced with full versions in the /data
- // partition or be disabled.
- private final List<String> mStubSystemApps = new ArrayList<>();
// TODO(b/198166813): remove PMS dependency
- InitAppsHelper(PackageManagerService pm, ApexManager apexManager,
- InstallPackageHelper installPackageHelper, PackageParser2 packageParser,
- List<ScanPartition> systemPartitions) {
+ InitAndSystemPackageHelper(PackageManagerService pm) {
mPm = pm;
- mApexManager = apexManager;
- mInstallPackageHelper = installPackageHelper;
- mPackageParser = packageParser;
- mSystemPartitions = systemPartitions;
+ mInstallPackageHelper = new InstallPackageHelper(pm);
mDirsToScanAsSystem = getSystemScanPartitions();
- mIsDeviceUpgrading = mPm.isDeviceUpgrading();
- mIsOnlyCoreApps = mPm.isOnlyCoreApps();
// Set flag to monitor and not change apk file paths when scanning install directories.
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
- if (mIsDeviceUpgrading || mPm.isFirstBoot()) {
+ if (mPm.isDeviceUpgrading() || mPm.isFirstBoot()) {
mScanFlags = scanFlags | SCAN_FIRST_BOOT_OR_UPGRADE;
} else {
mScanFlags = scanFlags;
}
mSystemParseFlags = mPm.getDefParseFlags() | ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
- mExecutorService = ParallelPackageParser.makeExecutorService();
}
private List<ScanPartition> getSystemScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- scanPartitions.addAll(mSystemPartitions);
+ scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
scanPartitions.addAll(getApexScanPartitions());
Slog.d(TAG, "Directories scanned as system partitions: " + scanPartitions);
return scanPartitions;
@@ -126,7 +101,8 @@
private List<ScanPartition> getApexScanPartitions() {
final List<ScanPartition> scanPartitions = new ArrayList<>();
- final List<ApexManager.ActiveApexInfo> activeApexInfos = mApexManager.getActiveApexInfos();
+ final List<ApexManager.ActiveApexInfo> activeApexInfos =
+ mPm.mApexManager.getActiveApexInfos();
for (int i = 0; i < activeApexInfos.size(); i++) {
final ScanPartition scanPartition = resolveApexToScanPartition(activeApexInfos.get(i));
if (scanPartition != null) {
@@ -143,133 +119,116 @@
if (apexInfo.preInstalledApexPath.getAbsolutePath().equals(
sp.getFolder().getAbsolutePath())
|| apexInfo.preInstalledApexPath.getAbsolutePath().startsWith(
- sp.getFolder().getAbsolutePath() + File.separator)) {
+ sp.getFolder().getAbsolutePath() + File.separator)) {
return new ScanPartition(apexInfo.apexDirectory, sp, SCAN_AS_APK_IN_APEX);
}
}
return null;
}
- /**
- * Install apps from system dirs.
- */
- @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
- public OverlayConfig initSystemApps(WatchedArrayMap<String, PackageSetting> packageSettings,
- int[] userIds, long startTime) {
+ public OverlayConfig initPackages(
+ WatchedArrayMap<String, PackageSetting> packageSettings, int[] userIds,
+ long startTime) {
+ PackageParser2 packageParser = mPm.mInjector.getScanningCachingPackageParser();
+
+ ExecutorService executorService = ParallelPackageParser.makeExecutorService();
// Prepare apex package info before scanning APKs, this information is needed when
// scanning apk in apex.
- mApexManager.scanApexPackagesTraced(mPackageParser, mExecutorService);
+ mPm.mApexManager.scanApexPackagesTraced(packageParser, executorService);
- scanSystemDirs(mPackageParser, mExecutorService);
+ scanSystemDirs(packageParser, executorService);
// Parse overlay configuration files to set default enable state, mutability, and
// priority of system overlays.
final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>();
- for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) {
- for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) {
+ for (ApexManager.ActiveApexInfo apexInfo : mPm.mApexManager.getActiveApexInfos()) {
+ for (String packageName : mPm.mApexManager.getApksInApex(apexInfo.apexModuleName)) {
apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath);
}
}
- final OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
+ OverlayConfig overlayConfig = OverlayConfig.initializeSystemInstance(
consumer -> mPm.forEachPackage(
pkg -> consumer.accept(pkg, pkg.isSystem(),
- apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
+ apkInApexPreInstalledPaths.get(pkg.getPackageName()))));
+ // Prune any system packages that no longer exist.
+ final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
+ // Stub packages must either be replaced with full versions in the /data
+ // partition or be disabled.
+ final List<String> stubSystemApps = new ArrayList<>();
- if (!mIsOnlyCoreApps) {
+ if (!mPm.isOnlyCoreApps()) {
// do this first before mucking with mPackages for the "expecting better" case
- updateStubSystemAppsList(mStubSystemApps);
+ updateStubSystemAppsList(stubSystemApps);
mInstallPackageHelper.prepareSystemPackageCleanUp(packageSettings,
- mPossiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
+ possiblyDeletedUpdatedSystemApps, mExpectingBetter, userIds);
}
- logSystemAppsScanningTime(startTime);
- return overlayConfig;
- }
-
- @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
- private void logSystemAppsScanningTime(long startTime) {
- mCachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
+ final int cachedSystemApps = PackageCacher.sCachedPackageReadCount.get();
// Remove any shared userIDs that have no associated packages
mPm.mSettings.pruneSharedUsersLPw();
- mSystemScanTime = SystemClock.uptimeMillis() - startTime;
- mSystemPackagesCount = mPm.mPackages.size();
- Slog.i(TAG, "Finished scanning system apps. Time: " + mSystemScanTime
- + " ms, packageCount: " + mSystemPackagesCount
+ final long systemScanTime = SystemClock.uptimeMillis() - startTime;
+ final int systemPackagesCount = mPm.mPackages.size();
+ Slog.i(TAG, "Finished scanning system apps. Time: " + systemScanTime
+ + " ms, packageCount: " + systemPackagesCount
+ " , timePerPackage: "
- + (mSystemPackagesCount == 0 ? 0 : mSystemScanTime / mSystemPackagesCount)
- + " , cached: " + mCachedSystemApps);
- if (mIsDeviceUpgrading && mSystemPackagesCount > 0) {
+ + (systemPackagesCount == 0 ? 0 : systemScanTime / systemPackagesCount)
+ + " , cached: " + cachedSystemApps);
+ if (mPm.isDeviceUpgrading() && systemPackagesCount > 0) {
//CHECKSTYLE:OFF IndentationCheck
FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_SYSTEM_APP_AVG_SCAN_TIME,
- mSystemScanTime / mSystemPackagesCount);
+ systemScanTime / systemPackagesCount);
//CHECKSTYLE:ON IndentationCheck
}
- }
- /**
- * Install apps/updates from data dir and fix system apps that are affected.
- */
- @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
- public void initNonSystemApps(@NonNull int[] userIds, long startTime) {
- if (!mIsOnlyCoreApps) {
+ if (!mPm.isOnlyCoreApps()) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
- scanDirTracedLI(mPm.getAppInstallDir(), 0, mScanFlags | SCAN_REQUIRE_KNOWN,
- mPackageParser, mExecutorService);
+ scanDirTracedLI(mPm.getAppInstallDir(), 0, mScanFlags | SCAN_REQUIRE_KNOWN, 0,
+ packageParser, executorService);
}
- List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
+ List<Runnable> unfinishedTasks = executorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
+ unfinishedTasks);
}
- if (!mIsOnlyCoreApps) {
- fixSystemPackages(userIds);
- logNonSystemAppScanningTime(startTime);
+
+ if (!mPm.isOnlyCoreApps()) {
+ mInstallPackageHelper.cleanupDisabledPackageSettings(possiblyDeletedUpdatedSystemApps,
+ userIds, mScanFlags);
+ mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
+ stubSystemApps, mSystemScanFlags, mSystemParseFlags);
+
+ // Uncompress and install any stubbed system applications.
+ // This must be done last to ensure all stubs are replaced or disabled.
+ mInstallPackageHelper.installSystemStubPackages(stubSystemApps, mScanFlags);
+
+ final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
+ - cachedSystemApps;
+
+ final long dataScanTime = SystemClock.uptimeMillis() - systemScanTime - startTime;
+ final int dataPackagesCount = mPm.mPackages.size() - systemPackagesCount;
+ Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
+ + " ms, packageCount: " + dataPackagesCount
+ + " , timePerPackage: "
+ + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
+ + " , cached: " + cachedNonSystemApps);
+ if (mPm.isDeviceUpgrading() && dataPackagesCount > 0) {
+ //CHECKSTYLE:OFF IndentationCheck
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
+ BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
+ dataScanTime / dataPackagesCount);
+ //CHECKSTYLE:OFF IndentationCheck
+ }
}
mExpectingBetter.clear();
+
mPm.mSettings.pruneRenamedPackagesLPw();
- mPackageParser.close();
- }
-
- /**
- * Clean up system packages now that some system package updates have been installed from
- * the data dir. Also install system stub packages as the last step.
- */
- @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
- private void fixSystemPackages(@NonNull int[] userIds) {
- mInstallPackageHelper.cleanupDisabledPackageSettings(mPossiblyDeletedUpdatedSystemApps,
- userIds, mScanFlags);
- mInstallPackageHelper.checkExistingBetterPackages(mExpectingBetter,
- mStubSystemApps, mSystemScanFlags, mSystemParseFlags);
-
- // Uncompress and install any stubbed system applications.
- // This must be done last to ensure all stubs are replaced or disabled.
- mInstallPackageHelper.installSystemStubPackages(mStubSystemApps, mScanFlags);
- }
-
- @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
- private void logNonSystemAppScanningTime(long startTime) {
- final int cachedNonSystemApps = PackageCacher.sCachedPackageReadCount.get()
- - mCachedSystemApps;
-
- final long dataScanTime = SystemClock.uptimeMillis() - mSystemScanTime - startTime;
- final int dataPackagesCount = mPm.mPackages.size() - mSystemPackagesCount;
- Slog.i(TAG, "Finished scanning non-system apps. Time: " + dataScanTime
- + " ms, packageCount: " + dataPackagesCount
- + " , timePerPackage: "
- + (dataPackagesCount == 0 ? 0 : dataScanTime / dataPackagesCount)
- + " , cached: " + cachedNonSystemApps);
- if (mIsDeviceUpgrading && dataPackagesCount > 0) {
- //CHECKSTYLE:OFF IndentationCheck
- FrameworkStatsLog.write(
- FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
- BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_DATA_APP_AVG_SCAN_TIME,
- dataScanTime / dataPackagesCount);
- //CHECKSTYLE:OFF IndentationCheck
- }
+ packageParser.close();
+ return overlayConfig;
}
/**
@@ -289,12 +248,12 @@
continue;
}
scanDirTracedLI(partition.getOverlayFolder(), mSystemParseFlags,
- mSystemScanFlags | partition.scanFlag,
+ mSystemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
scanDirTracedLI(frameworkDir, mSystemParseFlags,
- mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED,
+ mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
packageParser, executorService);
if (!mPm.mPackages.containsKey("android")) {
throw new IllegalStateException(
@@ -305,11 +264,11 @@
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getPrivAppFolder() != null) {
scanDirTracedLI(partition.getPrivAppFolder(), mSystemParseFlags,
- mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag,
+ mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
packageParser, executorService);
}
scanDirTracedLI(partition.getAppFolder(), mSystemParseFlags,
- mSystemScanFlags | partition.scanFlag,
+ mSystemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
}
@@ -327,11 +286,11 @@
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
- PackageParser2 packageParser, ExecutorService executorService) {
+ long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
try {
mInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags, scanFlags,
- packageParser, executorService);
+ currentTime, packageParser, executorService);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 47a7a92..6a5d76b 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -112,11 +112,6 @@
import android.content.pm.SigningDetails;
import android.content.pm.VerifierInfo;
import android.content.pm.dex.DexMetadataHelper;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.component.ComponentMutateUtils;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.net.Uri;
@@ -162,6 +157,11 @@
import com.android.server.pm.permission.Permission;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.pm.pkg.PackageStateInternal;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.rollback.RollbackManagerInternal;
import com.android.server.utils.WatchedArrayMap;
import com.android.server.utils.WatchedLongSparseArray;
@@ -3073,7 +3073,7 @@
final RemovePackageHelper removePackageHelper = new RemovePackageHelper(mPm);
removePackageHelper.removePackageLI(stubPkg, true /*chatty*/);
try {
- return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, null);
+ return scanSystemPackageTracedLI(scanFile, parseFlags, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to install compressed system package:" + stubPkg.getPackageName(),
e);
@@ -3206,7 +3206,7 @@
| ParsingPackageUtils.PARSE_IS_SYSTEM_DIR;
@PackageManagerService.ScanFlags int scanFlags = mPm.getSystemPackageScanFlags(codePath);
final AndroidPackage pkg = scanSystemPackageTracedLI(
- codePath, parseFlags, scanFlags, null);
+ codePath, parseFlags, scanFlags, 0 /*currentTime*/, null);
PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
@@ -3381,7 +3381,7 @@
mRemovePackageHelper.removePackageLI(pkg, true);
try {
final File codePath = new File(pkg.getPath());
- scanSystemPackageTracedLI(codePath, 0, scanFlags, null);
+ scanSystemPackageTracedLI(codePath, 0, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
@@ -3402,7 +3402,7 @@
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public void installPackagesFromDir(File scanDir, int parseFlags, int scanFlags,
- PackageParser2 packageParser, ExecutorService executorService) {
+ long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
final File[] files = scanDir.listFiles();
if (ArrayUtils.isEmpty(files)) {
Log.d(TAG, "No files in app dir " + scanDir);
@@ -3444,7 +3444,7 @@
parseResult.parsedPackage);
}
try {
- addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags,
+ addForInitLI(parseResult.parsedPackage, parseFlags, scanFlags, currentTime,
null);
} catch (PackageManagerException e) {
errorCode = e.error;
@@ -3507,7 +3507,7 @@
try {
final AndroidPackage newPkg = scanSystemPackageTracedLI(
- scanFile, reparseFlags, rescanFlags, null);
+ scanFile, reparseFlags, rescanFlags, 0, null);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
@@ -3521,14 +3521,14 @@
/**
* Traces a package scan.
- * @see #scanSystemPackageLI(File, int, int, UserHandle)
+ * @see #scanSystemPackageLI(File, int, int, long, UserHandle)
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
public AndroidPackage scanSystemPackageTracedLI(File scanFile, final int parseFlags,
- int scanFlags, UserHandle user) throws PackageManagerException {
+ int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanPackage [" + scanFile.toString() + "]");
try {
- return scanSystemPackageLI(scanFile, parseFlags, scanFlags, user);
+ return scanSystemPackageLI(scanFile, parseFlags, scanFlags, currentTime, user);
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -3540,7 +3540,7 @@
*/
@GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
private AndroidPackage scanSystemPackageLI(File scanFile, int parseFlags, int scanFlags,
- UserHandle user) throws PackageManagerException {
+ long currentTime, UserHandle user) throws PackageManagerException {
if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
@@ -3556,7 +3556,7 @@
PackageManagerService.renameStaticSharedLibraryPackage(parsedPackage);
}
- return addForInitLI(parsedPackage, parseFlags, scanFlags, user);
+ return addForInitLI(parsedPackage, parseFlags, scanFlags, currentTime, user);
}
/**
@@ -3575,11 +3575,11 @@
@GuardedBy({"mPm.mLock", "mPm.mInstallLock"})
private AndroidPackage addForInitLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags,
+ @PackageManagerService.ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user) throws PackageManagerException {
final Pair<ScanResult, Boolean> scanResultPair = scanSystemPackageLI(
- parsedPackage, parseFlags, scanFlags, user);
+ parsedPackage, parseFlags, scanFlags, currentTime, user);
final ScanResult scanResult = scanResultPair.first;
boolean shouldHideSystemApp = scanResultPair.second;
if (scanResult.mSuccess) {
@@ -3757,7 +3757,7 @@
private Pair<ScanResult, Boolean> scanSystemPackageLI(ParsedPackage parsedPackage,
@ParsingPackageUtils.ParseFlags int parseFlags,
- @PackageManagerService.ScanFlags int scanFlags,
+ @PackageManagerService.ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle user) throws PackageManagerException {
final boolean scanSystemPartition =
(parseFlags & ParsingPackageUtils.PARSE_IS_SYSTEM_DIR) != 0;
@@ -3944,7 +3944,7 @@
}
final ScanResult scanResult = scanPackageNewLI(parsedPackage, parseFlags,
- scanFlags | SCAN_UPDATE_SIGNATURE, 0 /* currentTime */, user, null);
+ scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user, null);
return new Pair<>(scanResult, shouldHideSystemApp);
}
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 1e1d169..db346da 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -17,11 +17,11 @@
package com.android.server.pm;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
-import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
import android.annotation.NonNull;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Base64;
@@ -340,9 +340,10 @@
if (p == null || p.getKeySetData() == null) {
return null;
}
- Long keySetId = p.getKeySetData().getAliases().get(alias);
+ final ArrayMap<String, Long> aliases = p.getKeySetData().getAliases();
+ Long keySetId = aliases.get(alias);
if (keySetId == null) {
- throw new IllegalArgumentException("Unknown KeySet alias: " + alias);
+ throw new IllegalArgumentException("Unknown KeySet alias: " + alias + ", aliases = " + aliases);
}
return mKeySets.get(keySetId);
}
@@ -811,7 +812,7 @@
long identifier = parser.getAttributeLong(null, "identifier");
int refCount = 0;
byte[] publicKey = parser.getAttributeBytesBase64(null, "value", null);
- PublicKey pub = parsePublicKey(publicKey);
+ PublicKey pub = FrameworkParsingPackageUtils.parsePublicKey(publicKey);
if (pub != null) {
PublicKeyHandle pkh = new PublicKeyHandle(identifier, refCount, pub);
mPublicKeys.put(identifier, pkh);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index b3bb26c..1f10d77 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -1661,9 +1661,16 @@
}
synchronized (mSessions) {
// Child sessions will be removed along with its parent as a whole
- if (!session.hasParentSessionId()
- && (!session.isStaged() || session.isDestroyed())) {
- removeActiveSession(session);
+ if (!session.hasParentSessionId()) {
+ // Retain policy:
+ // 1. Don't keep non-staged sessions
+ // 2. Don't keep explicitly abandoned sessions
+ // 3. Don't keep sessions that fail validation (isCommitted() is false)
+ boolean shouldRemove = !session.isStaged() || session.isDestroyed()
+ || !session.isCommitted();
+ if (shouldRemove) {
+ removeActiveSession(session);
+ }
}
final File appIconFile = buildAppIconFile(session.sessionId);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index c813317..e0f1b0b 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -91,7 +91,7 @@
import android.content.pm.parsing.ApkLite;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
-import android.content.pm.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.graphics.Bitmap;
@@ -1734,61 +1734,22 @@
@WorkerThread
private void handleStreamValidateAndCommit() {
- PackageManagerException unrecoverableFailure = null;
- // This will track whether the session and any children were validated and are ready to
- // progress to the next phase of install
- boolean allSessionsReady = false;
try {
- allSessionsReady = streamValidateAndCommit();
+ // This will track whether the session and any children were validated and are ready to
+ // progress to the next phase of install
+ boolean allSessionsReady = true;
+ for (PackageInstallerSession child : getChildSessions()) {
+ allSessionsReady &= child.streamValidateAndCommit();
+ }
+ if (allSessionsReady && streamValidateAndCommit()) {
+ mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
+ }
} catch (PackageManagerException e) {
- unrecoverableFailure = e;
+ destroy();
+ String msg = ExceptionUtils.getCompleteMessage(e);
+ dispatchSessionFinished(e.error, msg, null);
+ maybeFinishChildSessions(e.error, msg);
}
-
- if (isMultiPackage()) {
- final List<PackageInstallerSession> childSessions;
- synchronized (mLock) {
- childSessions = getChildSessionsLocked();
- }
- int childCount = childSessions.size();
-
- // This will contain all child sessions that do not encounter an unrecoverable failure
- ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount);
-
- for (int i = childCount - 1; i >= 0; --i) {
- // commit all children, regardless if any of them fail; we'll throw/return
- // as appropriate once all children have been processed
- try {
- PackageInstallerSession session = childSessions.get(i);
- allSessionsReady &= session.streamValidateAndCommit();
- nonFailingSessions.add(session);
- } catch (PackageManagerException e) {
- allSessionsReady = false;
- if (unrecoverableFailure == null) {
- unrecoverableFailure = e;
- }
- }
- }
- // If we encountered any unrecoverable failures, destroy all other sessions including
- // the parent
- if (unrecoverableFailure != null) {
- // {@link #streamValidateAndCommit()} calls
- // {@link #onSessionValidationFailure(PackageManagerException)}, but we don't
- // expect it to ever do so for parent sessions. Call that on this parent to clean
- // it up and notify listeners of the error.
- onSessionValidationFailure(unrecoverableFailure);
- // fail other child sessions that did not already fail
- for (int i = nonFailingSessions.size() - 1; i >= 0; --i) {
- PackageInstallerSession session = nonFailingSessions.get(i);
- session.onSessionValidationFailure(unrecoverableFailure);
- }
- }
- }
-
- if (!allSessionsReady) {
- return;
- }
-
- mHandler.obtainMessage(MSG_INSTALL).sendToTarget();
}
private final class FileSystemConnector extends
@@ -2026,11 +1987,11 @@
}
return true;
} catch (PackageManagerException e) {
- throw onSessionValidationFailure(e);
+ throw e;
} catch (Throwable e) {
// Convert all exceptions into package manager exceptions as only those are handled
// in the code above.
- throw onSessionValidationFailure(new PackageManagerException(e));
+ throw new PackageManagerException(e);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 548eb58..13f91e0d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -130,9 +130,6 @@
import android.content.pm.VersionedPackage;
import android.content.pm.dex.IArtManager;
import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedMainComponent;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
@@ -239,8 +236,11 @@
import com.android.server.pm.pkg.PackageUserState;
import com.android.server.pm.pkg.PackageUserStateInternal;
import com.android.server.pm.pkg.SuspendParams;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
import com.android.server.pm.pkg.mutate.PackageStateMutator;
import com.android.server.pm.pkg.mutate.PackageStateWrite;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal;
import com.android.server.pm.verify.domain.DomainVerificationService;
import com.android.server.pm.verify.domain.proxy.DomainVerificationProxy;
@@ -964,7 +964,7 @@
private final BroadcastHelper mBroadcastHelper;
private final RemovePackageHelper mRemovePackageHelper;
private final DeletePackageHelper mDeletePackageHelper;
- private final InitAppsHelper mInitAppsHelper;
+ private final InitAndSystemPackageHelper mInitAndSystemPackageHelper;
private final AppDataHelper mAppDataHelper;
private final InstallPackageHelper mInstallPackageHelper;
private final PreferredActivityHelper mPreferredActivityHelper;
@@ -1700,7 +1700,7 @@
mAppDataHelper = testParams.appDataHelper;
mInstallPackageHelper = testParams.installPackageHelper;
mRemovePackageHelper = testParams.removePackageHelper;
- mInitAppsHelper = testParams.initAndSystemPackageHelper;
+ mInitAndSystemPackageHelper = testParams.initAndSystemPackageHelper;
mDeletePackageHelper = testParams.deletePackageHelper;
mPreferredActivityHelper = testParams.preferredActivityHelper;
mResolveIntentHelper = testParams.resolveIntentHelper;
@@ -1844,8 +1844,7 @@
mAppDataHelper = new AppDataHelper(this);
mInstallPackageHelper = new InstallPackageHelper(this, mAppDataHelper);
mRemovePackageHelper = new RemovePackageHelper(this, mAppDataHelper);
- mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
- mInjector.getScanningPackageParser(), mInjector.getSystemPartitions());
+ mInitAndSystemPackageHelper = new InitAndSystemPackageHelper(this);
mDeletePackageHelper = new DeletePackageHelper(this, mRemovePackageHelper,
mAppDataHelper);
mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);
@@ -1977,8 +1976,8 @@
mIsEngBuild, mIsUserDebugBuild, mIncrementalVersion);
final int[] userIds = mUserManager.getUserIds();
- mOverlayConfig = mInitAppsHelper.initSystemApps(packageSettings, userIds, startTime);
- mInitAppsHelper.initNonSystemApps(userIds, startTime);
+ mOverlayConfig = mInitAndSystemPackageHelper.initPackages(packageSettings,
+ userIds, startTime);
// Resolve the storage manager.
mStorageManagerPackage = getStorageManagerPackageName();
@@ -9147,7 +9146,7 @@
}
boolean isExpectingBetter(String packageName) {
- return mInitAppsHelper.isExpectingBetter(packageName);
+ return mInitAndSystemPackageHelper.isExpectingBetter(packageName);
}
int getDefParseFlags() {
@@ -9256,7 +9255,7 @@
@ScanFlags int getSystemPackageScanFlags(File codePath) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAppsHelper.getDirsToScanAsSystem();
+ mInitAndSystemPackageHelper.getDirsToScanAsSystem();
@PackageManagerService.ScanFlags int scanFlags = SCAN_AS_SYSTEM;
for (int i = dirsToScanAsSystem.size() - 1; i >= 0; i--) {
ScanPartition partition = dirsToScanAsSystem.get(i);
@@ -9274,7 +9273,7 @@
Pair<Integer, Integer> getSystemPackageRescanFlagsAndReparseFlags(File scanFile,
int systemScanFlags, int systemParseFlags) {
List<ScanPartition> dirsToScanAsSystem =
- mInitAppsHelper.getDirsToScanAsSystem();
+ mInitAndSystemPackageHelper.getDirsToScanAsSystem();
@ParsingPackageUtils.ParseFlags int reparseFlags = 0;
@PackageManagerService.ScanFlags int rescanFlags = 0;
for (int i1 = dirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
index 168401a..a1acc38 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceTestParams.java
@@ -106,7 +106,7 @@
public AppDataHelper appDataHelper;
public InstallPackageHelper installPackageHelper;
public RemovePackageHelper removePackageHelper;
- public InitAppsHelper initAndSystemPackageHelper;
+ public InitAndSystemPackageHelper initAndSystemPackageHelper;
public DeletePackageHelper deletePackageHelper;
public PreferredActivityHelper preferredActivityHelper;
public ResolveIntentHelper resolveIntentHelper;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 898f673..d8f0cc3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -51,7 +51,7 @@
import android.content.pm.SigningDetails;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
-import android.content.pm.parsing.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Binder;
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e27ad17..fd2256f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -230,6 +230,8 @@
return runDexoptJob();
case "cancel-bg-dexopt-job":
return cancelBgDexOptJob();
+ case "delete-dexopt":
+ return runDeleteDexOpt();
case "dump-profiles":
return runDumpProfiles();
case "snapshot-profile":
@@ -1917,6 +1919,24 @@
return 0;
}
+ private int runDeleteDexOpt() throws RemoteException {
+ PrintWriter pw = getOutPrintWriter();
+ String packageName = getNextArg();
+ if (TextUtils.isEmpty(packageName)) {
+ pw.println("Error: no package name");
+ return 1;
+ }
+ long freedBytes = LocalServices.getService(
+ PackageManagerInternal.class).deleteOatArtifactsOfPackage(packageName);
+ if (freedBytes < 0) {
+ pw.println("Error: delete failed");
+ return 1;
+ }
+ pw.println("Success: freed " + freedBytes + " bytes");
+ Slog.i(TAG, "delete-dexopt " + packageName + " ,freed " + freedBytes + " bytes");
+ return 0;
+ }
+
private int runDumpProfiles() throws RemoteException {
String packageName = getNextArg();
mInterface.dumpProfiles(packageName);
@@ -4000,6 +4020,9 @@
pw.println(" force-dex-opt PACKAGE");
pw.println(" Force immediate execution of dex opt for the given PACKAGE.");
pw.println("");
+ pw.println(" delete-dexopt PACKAGE");
+ pw.println(" Delete dex optimization results for the given PACKAGE.");
+ pw.println("");
pw.println(" bg-dexopt-job");
pw.println(" Execute the background optimizations immediately.");
pw.println(" Note that the command only runs the background optimizer logic. It may");
diff --git a/services/core/java/com/android/server/pm/PackageProperty.java b/services/core/java/com/android/server/pm/PackageProperty.java
index ee9ed3b..2055537 100644
--- a/services/core/java/com/android/server/pm/PackageProperty.java
+++ b/services/core/java/com/android/server/pm/PackageProperty.java
@@ -27,7 +27,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.Property;
import android.content.pm.PackageManager.PropertyLocation;
-import android.content.pm.parsing.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedComponent;
import android.os.Binder;
import android.os.UserHandle;
import android.util.ArrayMap;
diff --git a/services/core/java/com/android/server/pm/PackageSessionVerifier.java b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
index ccabce7..9bfb7d1 100644
--- a/services/core/java/com/android/server/pm/PackageSessionVerifier.java
+++ b/services/core/java/com/android/server/pm/PackageSessionVerifier.java
@@ -28,7 +28,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.content.rollback.RollbackInfo;
diff --git a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
index 67f6b12..f3d88ed 100644
--- a/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
+++ b/services/core/java/com/android/server/pm/ReconcilePackageUtils.java
@@ -28,7 +28,7 @@
import android.content.pm.SharedLibraryInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.os.SystemProperties;
import android.util.ArrayMap;
import android.util.Log;
diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java
index d60d019..b0e0340 100644
--- a/services/core/java/com/android/server/pm/RemovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java
@@ -29,7 +29,7 @@
import android.annotation.NonNull;
import android.content.pm.PackageManager;
-import android.content.pm.parsing.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
import android.os.UserHandle;
import android.os.incremental.IncrementalManager;
import android.util.Log;
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index 6d2ec0d..79ab563 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -52,13 +52,6 @@
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.component.ComponentMutateUtils;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedProcess;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Build;
@@ -85,6 +78,13 @@
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.pm.pkg.PackageStateUtils;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import dalvik.system.VMRuntime;
diff --git a/services/core/java/com/android/server/pm/ScanRequest.java b/services/core/java/com/android/server/pm/ScanRequest.java
index 482b79c..34abdb1 100644
--- a/services/core/java/com/android/server/pm/ScanRequest.java
+++ b/services/core/java/com/android/server/pm/ScanRequest.java
@@ -18,12 +18,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.pm.parsing.ParsingPackageUtils;
import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
/** A package to be scanned */
@VisibleForTesting
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7085682..45837717 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -50,13 +50,13 @@
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedProcess;
-import android.content.pm.pkg.PackageUserStateUtils;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.PackageUserStateUtils;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index 9df0edb2..bc48461 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -18,9 +18,9 @@
import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
-import android.content.pm.parsing.component.ComponentMutateUtils;
-import android.content.pm.parsing.component.ParsedProcess;
-import android.content.pm.parsing.component.ParsedProcessImpl;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.component.ParsedProcessImpl;
import android.service.pm.PackageServiceDumpProto;
import android.util.ArrayMap;
import android.util.ArraySet;
diff --git a/services/core/java/com/android/server/pm/StorageEventHelper.java b/services/core/java/com/android/server/pm/StorageEventHelper.java
index de64405..bb7e55a 100644
--- a/services/core/java/com/android/server/pm/StorageEventHelper.java
+++ b/services/core/java/com/android/server/pm/StorageEventHelper.java
@@ -32,7 +32,7 @@
import android.content.pm.PackagePartitions;
import android.content.pm.UserInfo;
import android.content.pm.VersionedPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.os.Environment;
import android.os.FileUtils;
import android.os.UserHandle;
@@ -150,7 +150,7 @@
final AndroidPackage pkg;
try {
pkg = installPackageHelper.scanSystemPackageTracedLI(
- ps.getPath(), parseFlags, SCAN_INITIAL, null);
+ ps.getPath(), parseFlags, SCAN_INITIAL, 0, null);
loaded.add(pkg);
} catch (PackageManagerException e) {
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 01bf634..e28a6ea 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -31,7 +31,7 @@
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.ISnapshotRuntimeProfileCallback;
import android.content.pm.dex.PackageOptimizationInfo;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
diff --git a/services/core/java/com/android/server/pm/dex/ViewCompiler.java b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
index 8afe62a..61aedd8 100644
--- a/services/core/java/com/android/server/pm/dex/ViewCompiler.java
+++ b/services/core/java/com/android/server/pm/dex/ViewCompiler.java
@@ -16,7 +16,7 @@
package com.android.server.pm.dex;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
import android.os.Binder;
import android.os.UserHandle;
import android.util.Log;
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index 07cc3d0..0fa0dc3 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -34,19 +34,19 @@
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.SharedLibraryInfo;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.ParsingUtils;
-import android.content.pm.parsing.component.ComponentParseUtils;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.content.pm.parsing.component.ParsedProcess;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.pkg.PackageUserStateUtils;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
+import com.android.server.pm.pkg.component.ComponentParseUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.PackageUserStateUtils;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
diff --git a/services/core/java/com/android/server/pm/parsing/PackageParser2.java b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
index f467a7f..08e2f7d 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageParser2.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageParser2.java
@@ -22,9 +22,9 @@
import android.app.ActivityThread;
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
diff --git a/services/core/java/com/android/server/pm/parsing/ParsedComponentStateUtils.java b/services/core/java/com/android/server/pm/parsing/ParsedComponentStateUtils.java
index 3a49216..564585b 100644
--- a/services/core/java/com/android/server/pm/parsing/ParsedComponentStateUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/ParsedComponentStateUtils.java
@@ -18,10 +18,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.pm.parsing.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedComponent;
import android.util.Pair;
-import com.android.server.pm.PackageSetting;
import com.android.server.pm.pkg.PackageStateInternal;
/**
diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index bbf584d..dc3bf78 100644
--- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
@@ -21,7 +21,7 @@
import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
-import android.content.pm.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
index bf7d897..b357ba0 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackage.java
@@ -17,7 +17,9 @@
package com.android.server.pm.parsing.pkg;
import android.annotation.NonNull;
-import android.content.pm.parsing.ParsingPackageRead;
+
+import com.android.internal.content.om.OverlayConfig;
+import com.android.server.pm.pkg.parsing.ParsingPackageRead;
import com.android.server.pm.pkg.AndroidPackageApi;
@@ -31,8 +33,8 @@
*
* @hide
*/
-public interface AndroidPackage extends ParsingPackageRead, AndroidPackageApi {
-
+public interface AndroidPackage extends ParsingPackageRead, AndroidPackageApi,
+ OverlayConfig.PackageProvider.Package {
/**
* The package name as declared in the manifest, since the package can be renamed. For example,
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 8b2c3a12..7e59bd6 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -23,12 +23,12 @@
import android.content.pm.SharedLibraryInfo;
import android.content.pm.VersionedPackage;
import android.content.pm.dex.DexMetadataHelper;
-import android.content.pm.parsing.ParsingPackageRead;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
+import com.android.server.pm.pkg.parsing.ParsingPackageRead;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedService;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.incremental.IncrementalManager;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index 6846ac5..193e1a2 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -22,14 +22,8 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
-import android.content.pm.SELinuxUtil;
+import com.android.server.pm.pkg.SELinuxUtil;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageImpl;
-import android.content.pm.parsing.component.ComponentMutateUtils;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
import android.content.res.TypedArray;
import android.os.Environment;
import android.os.Parcel;
@@ -41,6 +35,12 @@
import com.android.internal.util.DataClass;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedString;
import com.android.server.pm.parsing.PackageInfoUtils;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageImpl;
import java.io.File;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java b/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java
index a13f297..6ddae9b 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PkgAppInfo.java
@@ -18,7 +18,7 @@
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
-import android.content.pm.parsing.PkgWithoutStateAppInfo;
+import com.android.server.pm.pkg.parsing.PkgWithoutStateAppInfo;
import com.android.server.pm.PackageManagerService;
import com.android.server.pm.pkg.PackageState;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java b/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java
index e2efbe1..da7f1dc 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PkgPackageInfo.java
@@ -17,7 +17,7 @@
package com.android.server.pm.parsing.pkg;
import android.content.pm.PackageInfo;
-import android.content.pm.parsing.PkgWithoutStatePackageInfo;
+import com.android.server.pm.pkg.parsing.PkgWithoutStatePackageInfo;
import com.android.server.pm.PackageManagerService;
diff --git a/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java b/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java
similarity index 95%
rename from core/java/android/content/pm/permission/CompatibilityPermissionInfo.java
rename to services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java
index b70353a4..d962505 100644
--- a/core/java/android/content/pm/permission/CompatibilityPermissionInfo.java
+++ b/services/core/java/com/android/server/pm/permission/CompatibilityPermissionInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,11 +14,10 @@
* limitations under the License.
*/
-package android.content.pm.permission;
+package com.android.server.pm.permission;
import android.Manifest;
import android.annotation.NonNull;
-import android.content.pm.parsing.component.ParsedUsesPermission;
import com.android.internal.util.DataClass;
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index 041c4fe..d5456e3 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -23,7 +23,7 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PermissionInfo;
-import android.content.pm.parsing.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermission;
import android.os.Build;
import android.os.UserHandle;
import android.util.Log;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 7833c43..981fd8e 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -73,11 +73,11 @@
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.component.ComponentMutateUtils;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.content.pm.parsing.component.ParsedPermissionUtils;
-import android.content.pm.permission.CompatibilityPermissionInfo;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedPermissionUtils;
+
import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.metrics.LogMaker;
import android.os.AsyncTask;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionRegistry.java b/services/core/java/com/android/server/pm/permission/PermissionRegistry.java
index 0e3fda7..3a61704 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionRegistry.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionRegistry.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
import android.util.ArrayMap;
import android.util.ArraySet;
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
index 6c8e0b7..656c445 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUtils.java
@@ -20,8 +20,8 @@
import android.annotation.Nullable;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.pkg.PackageUserStateUtils;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+
import android.util.SparseArray;
import com.android.server.pm.parsing.pkg.AndroidPackage;
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserState.java b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
index 03b1692..d47c5ec 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserState.java
@@ -20,7 +20,6 @@
import android.annotation.Nullable;
import android.content.pm.PackageManager;
import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.pkg.FrameworkPackageUserState;
import android.os.UserHandle;
import java.util.Map;
@@ -34,7 +33,7 @@
*/
// TODO(b/173807334): Expose API
//@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
-public interface PackageUserState extends FrameworkPackageUserState {
+public interface PackageUserState {
PackageUserState DEFAULT = PackageUserStateInternal.DEFAULT;
diff --git a/core/java/android/content/pm/pkg/PackageUserStateUtils.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
similarity index 86%
rename from core/java/android/content/pm/pkg/PackageUserStateUtils.java
rename to services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
index 468bff1..917c4af 100644
--- a/core/java/android/content/pm/pkg/PackageUserStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.pkg;
+package com.android.server.pm.pkg;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
@@ -22,26 +22,27 @@
import android.annotation.NonNull;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
-import android.content.pm.parsing.ParsingPackageRead;
-import android.content.pm.parsing.component.ParsedMainComponent;
import android.os.Debug;
import android.util.DebugUtils;
import android.util.Slog;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.parsing.ParsingPackageRead;
+
/** @hide */
public class PackageUserStateUtils {
private static final boolean DEBUG = false;
private static final String TAG = "PackageUserStateUtils";
- public static boolean isMatch(@NonNull FrameworkPackageUserState state,
+ public static boolean isMatch(@NonNull PackageUserState state,
ComponentInfo componentInfo, long flags) {
return isMatch(state, componentInfo.applicationInfo.isSystemApp(),
componentInfo.applicationInfo.enabled, componentInfo.enabled,
componentInfo.directBootAware, componentInfo.name, flags);
}
- public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem,
+ public static boolean isMatch(@NonNull PackageUserState state, boolean isSystem,
boolean isPackageEnabled, ParsedMainComponent component, long flags) {
return isMatch(state, isSystem, isPackageEnabled, component.isEnabled(),
component.isDirectBootAware(), component.getName(), flags);
@@ -56,7 +57,7 @@
* PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
* </p>
*/
- public static boolean isMatch(@NonNull FrameworkPackageUserState state, boolean isSystem,
+ public static boolean isMatch(@NonNull PackageUserState state, boolean isSystem,
boolean isPackageEnabled, boolean isComponentEnabled,
boolean isComponentDirectBootAware, String componentName, long flags) {
final boolean matchUninstalled = (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0;
@@ -81,7 +82,7 @@
return reportIfDebug(matchesUnaware || matchesAware, flags);
}
- public static boolean isAvailable(@NonNull FrameworkPackageUserState state, long flags) {
+ public static boolean isAvailable(@NonNull PackageUserState state, long flags) {
// True if it is installed for this user and it is not hidden. If it is hidden,
// still return true if the caller requested MATCH_UNINSTALLED_PACKAGES
final boolean matchAnyUser = (flags & PackageManager.MATCH_ANY_USER) != 0;
@@ -100,13 +101,13 @@
return result;
}
- public static boolean isEnabled(@NonNull FrameworkPackageUserState state, ComponentInfo componentInfo,
+ public static boolean isEnabled(@NonNull PackageUserState state, ComponentInfo componentInfo,
long flags) {
return isEnabled(state, componentInfo.applicationInfo.enabled, componentInfo.enabled,
componentInfo.name, flags);
}
- public static boolean isEnabled(@NonNull FrameworkPackageUserState state, boolean isPackageEnabled,
+ public static boolean isEnabled(@NonNull PackageUserState state, boolean isPackageEnabled,
ParsedMainComponent parsedComponent, long flags) {
return isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
parsedComponent.getName(), flags);
@@ -115,7 +116,7 @@
/**
* Test if the given component is considered enabled.
*/
- public static boolean isEnabled(@NonNull FrameworkPackageUserState state,
+ public static boolean isEnabled(@NonNull PackageUserState state,
boolean isPackageEnabled, boolean isComponentEnabled, String componentName,
long flags) {
if ((flags & MATCH_DISABLED_COMPONENTS) != 0) {
@@ -153,7 +154,7 @@
return isComponentEnabled;
}
- public static boolean isPackageEnabled(@NonNull FrameworkPackageUserState state,
+ public static boolean isPackageEnabled(@NonNull PackageUserState state,
@NonNull ParsingPackageRead pkg) {
switch (state.getEnabledState()) {
case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
diff --git a/core/java/android/content/pm/SELinuxUtil.java b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
similarity index 83%
rename from core/java/android/content/pm/SELinuxUtil.java
rename to services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
index 898dddf..6cbc1de 100644
--- a/core/java/android/content/pm/SELinuxUtil.java
+++ b/services/core/java/com/android/server/pm/pkg/SELinuxUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * 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.
@@ -14,9 +14,7 @@
* limitations under the License.
*/
-package android.content.pm;
-
-import android.content.pm.pkg.FrameworkPackageUserState;
+package com.android.server.pm.pkg;
/**
* Utility methods that need to be used in application space.
@@ -31,7 +29,7 @@
public static final String COMPLETE_STR = ":complete";
/** @hide */
- public static String getSeinfoUser(FrameworkPackageUserState userState) {
+ public static String getSeinfoUser(PackageUserState userState) {
if (userState.isInstantApp()) {
return INSTANT_APP_STR + COMPLETE_STR;
}
diff --git a/core/java/android/content/pm/parsing/component/ComponentMutateUtils.java b/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ComponentMutateUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java
index 73d0b9f..1deb8d0 100644
--- a/core/java/android/content/pm/parsing/component/ComponentMutateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ComponentMutateUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java b/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
similarity index 87%
rename from core/java/android/content/pm/parsing/component/ComponentParseUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
index 0334601..a8fb79a 100644
--- a/core/java/android/content/pm/parsing/component/ComponentParseUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ComponentParseUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,27 +14,27 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
-
-import static android.content.pm.parsing.ParsingPackageUtils.validateName;
+package com.android.server.pm.pkg.component;
import android.annotation.AttrRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.ParsingUtils;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
-import android.content.pm.pkg.FrameworkPackageUserState;
-import android.content.pm.pkg.PackageUserStateUtils;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.text.TextUtils;
+import com.android.server.pm.pkg.PackageUserState;
+import com.android.server.pm.pkg.PackageUserStateUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -125,7 +125,8 @@
+ ": must be at least two characters");
}
String subName = proc.substring(1);
- final ParseResult<?> nameResult = validateName(input, subName, false, false);
+ final ParseResult<?> nameResult = FrameworkParsingPackageUtils.validateName(input,
+ subName, false, false);
if (nameResult.isError()) {
return input.error("Invalid " + type + " name " + proc + " in package " + pkg
+ ": " + nameResult.getErrorMessage());
@@ -133,7 +134,8 @@
return input.success(pkg + proc);
}
if (!"system".equals(proc)) {
- final ParseResult<?> nameResult = validateName(input, proc, true, false);
+ final ParseResult<?> nameResult = FrameworkParsingPackageUtils.validateName(input, proc,
+ true, false);
if (nameResult.isError()) {
return input.error("Invalid " + type + " name " + proc + " in package " + pkg
+ ": " + nameResult.getErrorMessage());
@@ -169,13 +171,13 @@
return component.getIcon();
}
- public static boolean isMatch(FrameworkPackageUserState state, boolean isSystem,
+ public static boolean isMatch(PackageUserState state, boolean isSystem,
boolean isPackageEnabled, ParsedMainComponent component, long flags) {
return PackageUserStateUtils.isMatch(state, isSystem, isPackageEnabled,
component.isEnabled(), component.isDirectBootAware(), component.getName(), flags);
}
- public static boolean isEnabled(FrameworkPackageUserState state, boolean isPackageEnabled,
+ public static boolean isEnabled(PackageUserState state, boolean isPackageEnabled,
ParsedMainComponent parsedComponent, long flags) {
return PackageUserStateUtils.isEnabled(state, isPackageEnabled, parsedComponent.isEnabled(),
parsedComponent.getName(), flags);
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivity.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
similarity index 95%
rename from core/java/android/content/pm/parsing/component/ParsedActivity.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
index a661b51..6d978c4 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivity.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
similarity index 98%
rename from core/java/android/content/pm/parsing/component/ParsedActivityImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
index 93dc5a4..ff97c13 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForInternedString;
import static android.view.WindowManager.LayoutParams.ROTATION_ANIMATION_UNSPECIFIED;
import android.annotation.NonNull;
@@ -29,7 +29,7 @@
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
diff --git a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
index 2ddf923..db8815e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedActivityUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE_PER_TASK;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.content.pm.parsing.ParsingUtils.NOT_SET;
-import static android.content.pm.parsing.component.ComponentParseUtils.flag;
+import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
+import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -27,9 +27,9 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseInput.DeferredError;
import android.content.pm.parsing.result.ParseResult;
@@ -58,7 +58,9 @@
import java.util.Objects;
import java.util.Set;
-/** @hide */
+/**
+ * @hide
+ */
public class ParsedActivityUtils {
private static final String TAG = ParsingUtils.TAG;
@@ -601,7 +603,7 @@
* AndroidManifest.xml.
* @hide
*/
- static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) {
+ public static int getActivityConfigChanges(int configChanges, int recreateOnConfigChanges) {
return configChanges | ((~recreateOnConfigChanges) & RECREATE_ON_CONFIG_CHANGES_MASK);
}
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemService.java
similarity index 92%
rename from core/java/android/content/pm/parsing/component/ParsedApexSystemService.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemService.java
index c89d3b2..7690818 100644
--- a/core/java/android/content/pm/parsing/component/ParsedApexSystemService.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -35,6 +35,4 @@
@Nullable
String getMaxSdkVersion();
- int getInitOrder();
-
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
similarity index 89%
rename from core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
index 65d26b9..8c4d8f0 100644
--- a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
@@ -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/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
similarity index 88%
rename from core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
index eca8976..38a6f5a35 100644
--- a/core/java/android/content/pm/parsing/component/ParsedApexSystemServiceUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedApexSystemServiceUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.R;
import android.annotation.NonNull;
@@ -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/content/pm/parsing/component/ParsedAttribution.java b/services/core/java/com/android/server/pm/pkg/component/ParsedAttribution.java
similarity index 86%
rename from core/java/android/content/pm/parsing/component/ParsedAttribution.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedAttribution.java
index ac7a928..3b91f28 100644
--- a/core/java/android/content/pm/parsing/component/ParsedAttribution.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedAttribution.java
@@ -14,18 +14,12 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.StringRes;
-import android.os.Parcel;
import android.os.Parcelable;
-import android.util.ArraySet;
-import com.android.internal.util.DataClass;
-
-import java.util.ArrayList;
import java.util.List;
/**
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java
index 510425f..a4eb4f1 100644
--- a/core/java/android/content/pm/parsing/component/ParsedAttributionImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,14 +14,12 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.StringRes;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DataClass;
diff --git a/core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java
index 84f1d44..98e94c5 100644
--- a/core/java/android/content/pm/parsing/component/ParsedAttributionUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedAttributionUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponent.java b/services/core/java/com/android/server/pm/pkg/component/ParsedComponent.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ParsedComponent.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedComponent.java
index c1372f6..1a8230d 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponent.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedComponent.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedComponentImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java
index 1c46a10..9125e8c 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponentImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedComponentImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForInternedString;
import static java.util.Collections.emptyMap;
@@ -25,7 +25,7 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.pm.PackageManager.Property;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.os.Bundle;
import android.os.Parcel;
import android.text.TextUtils;
diff --git a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
similarity index 92%
rename from core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
index 5c33cfd..e208854 100644
--- a/core/java/android/content/pm/parsing/component/ParsedComponentUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedComponentUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.Property;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentation.java
similarity index 89%
rename from core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentation.java
index e8fcc00..a0eae8c 100644
--- a/core/java/android/content/pm/parsing/component/ParsedInstrumentation.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java
index d2b5368..c8baa9e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedInstrumentationImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
similarity index 93%
rename from core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
index df5e73e..51e1428 100644
--- a/core/java/android/content/pm/parsing/component/ParsedInstrumentationUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedInstrumentationUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
-import android.content.pm.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfo.java
similarity index 80%
rename from core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfo.java
index 1e36ccca..57b486a 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfo.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfo.java
@@ -14,20 +14,12 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.IntentFilter;
-import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Pair;
-
-import com.android.internal.util.DataClass;
-import com.android.internal.util.Parcelling;
-
-import java.util.ArrayList;
-import java.util.List;
/** @hide **/
public interface ParsedIntentInfo extends Parcelable {
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java
similarity index 95%
rename from core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java
index 9ff7a16..1c816da 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfoImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,23 +14,20 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.IntentFilter;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DataClass;
-import com.android.internal.util.Parcelling;
-import java.util.ArrayList;
-import java.util.List;
-
-/** @hide **/
+/**
+ * @hide
+ **/
@DataClass(genGetters = true, genSetters = true, genParcelable = true, genAidl = false,
genBuilder = false, genConstructor = false)
@DataClass.Suppress({"setIntentFilter"})
diff --git a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
index cb72c2b..1e6f630 100644
--- a/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedIntentInfoUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,16 +14,16 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
+import static com.android.server.pm.pkg.parsing.ParsingUtils.ANDROID_RES_NAMESPACE;
import android.annotation.NonNull;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponent.java
similarity index 91%
rename from core/java/android/content/pm/parsing/component/ParsedMainComponent.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedMainComponent.java
index 2507205..8c1d6c8 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponent.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponent.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java
index 6051435..9b57f48 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponentImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForInternedString;
import android.annotation.Nullable;
import android.os.Parcel;
diff --git a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
similarity index 95%
rename from core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
index 87f75b0..2a3e653 100644
--- a/core/java/android/content/pm/parsing/component/ParsedMainComponentUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedMainComponentUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.IntentFilter;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Configuration;
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermission.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermission.java
similarity index 90%
rename from core/java/android/content/pm/parsing/component/ParsedPermission.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedPermission.java
index 6acdb6e..4a6d2c3 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermission.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermission.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroup.java
similarity index 88%
rename from core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroup.java
index 22aa085..73b5ffa 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionGroup.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroup.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
/** @hide */
public interface ParsedPermissionGroup extends ParsedComponent {
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionGroupImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
similarity index 98%
rename from core/java/android/content/pm/parsing/component/ParsedPermissionGroupImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
index 1fa04cf..f47fb75 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionGroupImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionGroupImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.os.Parcel;
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
index 2145e44..98007ff 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -109,14 +109,13 @@
protected ParsedPermissionImpl(Parcel in) {
super(in);
- // We use the boot classloader for all classes that we load.
- final ClassLoader boot = Object.class.getClassLoader();
this.backgroundPermission = in.readString();
this.group = TextUtils.safeIntern(in.readString());
this.requestRes = in.readInt();
this.protectionLevel = in.readInt();
this.tree = in.readBoolean();
- this.parsedPermissionGroup = in.readParcelable(boot);
+ this.parsedPermissionGroup = in.readParcelable(ParsedPermissionGroup.class.getClassLoader(),
+ ParsedPermissionGroup.class);
this.knownCerts = sForStringSet.unparcel(in);
}
diff --git a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
index 86c8f02..8562fdf 100644
--- a/core/java/android/content/pm/parsing/component/ParsedPermissionUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedPermissionUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingUtils.NOT_SET;
+import static com.android.server.pm.pkg.parsing.ParsingUtils.NOT_SET;
import android.annotation.NonNull;
import android.content.pm.PermissionInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcess.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProcess.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ParsedProcess.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedProcess.java
index 27a540d..ff391ff 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcess.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProcess.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java
similarity index 98%
rename from core/java/android/content/pm/parsing/component/ParsedProcessImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java
index d404ecfd..96560c7 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcessImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProcessImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import static java.util.Collections.emptySet;
diff --git a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
index 5e4cf66..d03f153 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProcessUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProcessUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.content.pm.ApplicationInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
diff --git a/core/java/android/content/pm/parsing/component/ParsedProvider.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProvider.java
similarity index 91%
rename from core/java/android/content/pm/parsing/component/ParsedProvider.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedProvider.java
index 1211ce2..8cc6fc7 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProvider.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.Nullable;
import android.content.pm.PathPermission;
diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedProviderImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java
index 774c3fc..e04fc86 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProviderImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
similarity index 97%
rename from core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
index de9dd44..9d3129b 100644
--- a/core/java/android/content/pm/parsing/component/ParsedProviderUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedProviderUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,18 +14,18 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingPackageUtils.RIGID_PARSER;
-import static android.content.pm.parsing.component.ComponentParseUtils.flag;
+import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
+import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.IntentFilter;
import android.content.pm.PathPermission;
import android.content.pm.ProviderInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
diff --git a/core/java/android/content/pm/parsing/component/ParsedService.java b/services/core/java/com/android/server/pm/pkg/component/ParsedService.java
similarity index 88%
rename from core/java/android/content/pm/parsing/component/ParsedService.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedService.java
index 6736afa..11696be 100644
--- a/core/java/android/content/pm/parsing/component/ParsedService.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedService.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ParsedServiceImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java
index a85fb5c..0171c49 100644
--- a/core/java/android/content/pm/parsing/component/ParsedServiceImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.ParsingPackageImpl.sForInternedString;
+import static com.android.server.pm.pkg.parsing.ParsingPackageImpl.sForInternedString;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
index d27a0ed..6fe9411 100644
--- a/core/java/android/content/pm/parsing/component/ParsedServiceUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedServiceUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
-import static android.content.pm.parsing.component.ComponentParseUtils.flag;
+import static com.android.server.pm.pkg.component.ComponentParseUtils.flag;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseInput.DeferredError;
import android.content.pm.parsing.result.ParseResult;
diff --git a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java b/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermission.java
similarity index 96%
rename from core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermission.java
index e2f5f14..8e3401e 100644
--- a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermission.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.IntDef;
import android.annotation.NonNull;
diff --git a/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java
similarity index 98%
rename from core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java
rename to services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java
index d3c7afb..70d6f24 100644
--- a/core/java/android/content/pm/parsing/component/ParsedUsesPermissionImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedUsesPermissionImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2021 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing.component;
+package com.android.server.pm.pkg.component;
import android.annotation.NonNull;
import android.os.Parcel;
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
similarity index 93%
rename from core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
rename to services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
index 28290d7..2d6c616 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PackageInfoWithoutStateUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import android.annotation.CheckResult;
import android.annotation.NonNull;
@@ -35,29 +35,29 @@
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
-import android.content.pm.SELinuxUtil;
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.SigningInfo;
import android.content.pm.overlay.OverlayPaths;
-import android.content.pm.parsing.component.ComponentParseUtils;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedAttribution;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.parsing.component.ParsedUsesPermission;
-import android.content.pm.pkg.FrameworkPackageUserState;
-import android.content.pm.pkg.PackageUserStateUtils;
import android.os.Environment;
import android.os.UserHandle;
import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.pkg.PackageUserState;
+import com.android.server.pm.pkg.PackageUserStateUtils;
+import com.android.server.pm.pkg.SELinuxUtil;
+import com.android.server.pm.pkg.component.ComponentParseUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedAttribution;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.component.ParsedUsesPermission;
import libcore.util.EmptyArray;
@@ -77,7 +77,7 @@
@Nullable
public static PackageInfo generate(ParsingPackageRead pkg, int[] gids,
@PackageManager.PackageInfoFlagsBits long flags, long firstInstallTime,
- long lastUpdateTime, Set<String> grantedPermissions, FrameworkPackageUserState state,
+ long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state,
int userId) {
return generateWithComponents(pkg, gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions,
state, userId, null);
@@ -86,13 +86,13 @@
@Nullable
public static PackageInfo generate(ParsingPackageRead pkg, ApexInfo apexInfo, int flags) {
return generateWithComponents(pkg, EmptyArray.INT, flags, 0, 0, Collections.emptySet(),
- FrameworkPackageUserState.DEFAULT, UserHandle.getCallingUserId(), apexInfo);
+ PackageUserState.DEFAULT, UserHandle.getCallingUserId(), apexInfo);
}
@Nullable
private static PackageInfo generateWithComponents(ParsingPackageRead pkg, int[] gids,
@PackageManager.PackageInfoFlagsBits long flags, long firstInstallTime,
- long lastUpdateTime, Set<String> grantedPermissions, FrameworkPackageUserState state,
+ long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state,
int userId, @Nullable ApexInfo apexInfo) {
ApplicationInfo applicationInfo = generateApplicationInfo(pkg, flags, state, userId);
if (applicationInfo == null) {
@@ -192,7 +192,7 @@
@Nullable
public static PackageInfo generateWithoutComponents(ParsingPackageRead pkg, int[] gids,
@PackageManager.PackageInfoFlagsBits long flags, long firstInstallTime,
- long lastUpdateTime, Set<String> grantedPermissions, FrameworkPackageUserState state,
+ long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state,
int userId, @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
if (!checkUseInstalled(pkg, state, flags)) {
return null;
@@ -207,12 +207,12 @@
* server.
* <p>
* Prefer {@link #generateWithoutComponents(ParsingPackageRead, int[], int, long, long, Set,
- * FrameworkPackageUserState, int, ApexInfo, ApplicationInfo)}.
+ * PackageUserState, int, ApexInfo, ApplicationInfo)}.
*/
@NonNull
public static PackageInfo generateWithoutComponentsUnchecked(ParsingPackageRead pkg, int[] gids,
@PackageManager.PackageInfoFlagsBits long flags, long firstInstallTime,
- long lastUpdateTime, Set<String> grantedPermissions, FrameworkPackageUserState state,
+ long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state,
int userId, @Nullable ApexInfo apexInfo, @NonNull ApplicationInfo applicationInfo) {
PackageInfo pi = new PackageInfo();
pi.packageName = pkg.getPackageName();
@@ -366,7 +366,7 @@
@Nullable
public static ApplicationInfo generateApplicationInfo(ParsingPackageRead pkg,
- @PackageManager.ApplicationInfoFlagsBits long flags, FrameworkPackageUserState state,
+ @PackageManager.ApplicationInfoFlagsBits long flags, PackageUserState state,
int userId) {
if (pkg == null) {
return null;
@@ -384,7 +384,7 @@
* This bypasses critical checks that are necessary for usage with data passed outside of system
* server.
* <p>
- * Prefer {@link #generateApplicationInfo(ParsingPackageRead, int, FrameworkPackageUserState, int)}.
+ * Prefer {@link #generateApplicationInfo(ParsingPackageRead, int, PackageUserState, int)}.
*
* @param assignUserFields whether to fill the returned {@link ApplicationInfo} with user
* specific fields. This can be skipped when building from a system
@@ -395,7 +395,7 @@
@NonNull
public static ApplicationInfo generateApplicationInfoUnchecked(@NonNull ParsingPackageRead pkg,
@PackageManager.ApplicationInfoFlagsBits long flags,
- @NonNull FrameworkPackageUserState state, int userId, boolean assignUserFields) {
+ @NonNull PackageUserState state, int userId, boolean assignUserFields) {
// Make shallow copy so we can store the metadata/libraries safely
ApplicationInfo ai = ((ParsingPackageHidden) pkg).toAppInfoWithoutState();
@@ -409,7 +409,7 @@
}
private static void updateApplicationInfo(ApplicationInfo ai, long flags,
- FrameworkPackageUserState state) {
+ PackageUserState state) {
if ((flags & PackageManager.GET_META_DATA) == 0) {
ai.metaData = null;
}
@@ -455,7 +455,7 @@
@Nullable
public static ApplicationInfo generateDelegateApplicationInfo(@Nullable ApplicationInfo ai,
@PackageManager.ApplicationInfoFlagsBits long flags,
- @NonNull FrameworkPackageUserState state, int userId) {
+ @NonNull PackageUserState state, int userId) {
if (ai == null || !checkUseInstalledOrHidden(flags, state, ai)) {
return null;
}
@@ -472,7 +472,7 @@
@Nullable
public static ActivityInfo generateDelegateActivityInfo(@Nullable ActivityInfo a,
@PackageManager.ComponentInfoFlagsBits long flags,
- @NonNull FrameworkPackageUserState state, int userId) {
+ @NonNull PackageUserState state, int userId) {
if (a == null || !checkUseInstalledOrHidden(flags, state, a.applicationInfo)) {
return null;
}
@@ -486,7 +486,7 @@
@Nullable
public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
- @PackageManager.ComponentInfoFlagsBits long flags, FrameworkPackageUserState state,
+ @PackageManager.ComponentInfoFlagsBits long flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId) {
if (a == null) return null;
if (!checkUseInstalled(pkg, state, flags)) {
@@ -507,7 +507,7 @@
* server.
* <p>
* Prefer {@link #generateActivityInfo(ParsingPackageRead, ParsedActivity, long,
- * FrameworkPackageUserState, ApplicationInfo, int)}.
+ * PackageUserState, ApplicationInfo, int)}.
*/
@NonNull
public static ActivityInfo generateActivityInfoUnchecked(@NonNull ParsedActivity a,
@@ -552,14 +552,14 @@
@Nullable
public static ActivityInfo generateActivityInfo(ParsingPackageRead pkg, ParsedActivity a,
- @PackageManager.ComponentInfoFlagsBits long flags, FrameworkPackageUserState state,
+ @PackageManager.ComponentInfoFlagsBits long flags, PackageUserState state,
int userId) {
return generateActivityInfo(pkg, a, flags, state, null, userId);
}
@Nullable
public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
- @PackageManager.ComponentInfoFlagsBits long flags, FrameworkPackageUserState state,
+ @PackageManager.ComponentInfoFlagsBits long flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId) {
if (s == null) return null;
if (!checkUseInstalled(pkg, state, flags)) {
@@ -579,8 +579,8 @@
* This bypasses critical checks that are necessary for usage with data passed outside of system
* server.
* <p>
- * Prefer {@link #generateServiceInfo(ParsingPackageRead, ParsedService, long,
- * FrameworkPackageUserState, ApplicationInfo, int)}.
+ * Prefer {@link #generateServiceInfo(ParsingPackageRead, ParsedService, long, PackageUserState,
+ * ApplicationInfo, int)}.
*/
@NonNull
public static ServiceInfo generateServiceInfoUnchecked(@NonNull ParsedService s,
@@ -603,14 +603,14 @@
@Nullable
public static ServiceInfo generateServiceInfo(ParsingPackageRead pkg, ParsedService s,
- @PackageManager.ComponentInfoFlagsBits long flags, FrameworkPackageUserState state,
+ @PackageManager.ComponentInfoFlagsBits long flags, PackageUserState state,
int userId) {
return generateServiceInfo(pkg, s, flags, state, null, userId);
}
@Nullable
public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
- @PackageManager.ComponentInfoFlagsBits long flags, FrameworkPackageUserState state,
+ @PackageManager.ComponentInfoFlagsBits long flags, PackageUserState state,
@Nullable ApplicationInfo applicationInfo, int userId) {
if (p == null) return null;
if (!checkUseInstalled(pkg, state, flags)) {
@@ -631,7 +631,7 @@
* server.
* <p>
* Prefer {@link #generateProviderInfo(ParsingPackageRead, ParsedProvider, long,
- * FrameworkPackageUserState, ApplicationInfo, int)}.
+ * PackageUserState, ApplicationInfo, int)}.
*/
@NonNull
public static ProviderInfo generateProviderInfoUnchecked(@NonNull ParsedProvider p,
@@ -665,14 +665,14 @@
@Nullable
public static ProviderInfo generateProviderInfo(ParsingPackageRead pkg, ParsedProvider p,
- @PackageManager.ComponentInfoFlagsBits long flags, FrameworkPackageUserState state,
+ @PackageManager.ComponentInfoFlagsBits long flags, PackageUserState state,
int userId) {
return generateProviderInfo(pkg, p, flags, state, null, userId);
}
/**
* @param assignUserFields see {@link #generateApplicationInfoUnchecked(ParsingPackageRead,
- * long, FrameworkPackageUserState, int, boolean)}
+ * long, PackageUserState, int, boolean)}
*/
@Nullable
public static InstrumentationInfo generateInstrumentationInfo(ParsedInstrumentation i,
@@ -759,7 +759,7 @@
}
private static boolean checkUseInstalledOrHidden(long flags,
- @NonNull FrameworkPackageUserState state, @Nullable ApplicationInfo appInfo) {
+ @NonNull PackageUserState state, @Nullable ApplicationInfo appInfo) {
// Returns false if the package is hidden system app until installed.
if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
&& !state.isInstalled()
@@ -888,7 +888,7 @@
}
private static boolean checkUseInstalled(ParsingPackageRead pkg,
- FrameworkPackageUserState state, @PackageManager.PackageInfoFlagsBits long flags) {
+ PackageUserState state, @PackageManager.PackageInfoFlagsBits long flags) {
// If available for the target user
return PackageUserStateUtils.isAvailable(state, flags);
}
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
similarity index 93%
rename from core/java/android/content/pm/parsing/ParsingPackage.java
rename to services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
index e635e91..18a6435 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackage.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import android.annotation.CallSuper;
import android.annotation.NonNull;
@@ -26,17 +26,17 @@
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager.Property;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedApexSystemService;
-import android.content.pm.parsing.component.ParsedAttribution;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.content.pm.parsing.component.ParsedProcess;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.parsing.component.ParsedUsesPermission;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedApexSystemService;
+import com.android.server.pm.pkg.component.ParsedAttribution;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.component.ParsedUsesPermission;
import android.os.Bundle;
import android.util.SparseArray;
import android.util.SparseIntArray;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageHidden.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageHidden.java
similarity index 93%
rename from core/java/android/content/pm/parsing/ParsingPackageHidden.java
rename to services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageHidden.java
index c49d11e..66e01a6 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageHidden.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageHidden.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageImpl.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
similarity index 97%
rename from core/java/android/content/pm/parsing/ParsingPackageImpl.java
rename to services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
index fb42804..c4de862 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import static java.util.Collections.emptyList;
import static java.util.Collections.emptyMap;
@@ -33,28 +33,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.Property;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedActivityImpl;
-import android.content.pm.parsing.component.ParsedApexSystemService;
-import android.content.pm.parsing.component.ParsedApexSystemServiceImpl;
-import android.content.pm.parsing.component.ParsedAttribution;
-import android.content.pm.parsing.component.ParsedAttributionImpl;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedInstrumentationImpl;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.content.pm.parsing.component.ParsedPermissionGroupImpl;
-import android.content.pm.parsing.component.ParsedPermissionImpl;
-import android.content.pm.parsing.component.ParsedProcess;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedProviderImpl;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.parsing.component.ParsedServiceImpl;
-import android.content.pm.parsing.component.ParsedUsesPermission;
-import android.content.pm.parsing.component.ParsedUsesPermissionImpl;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.Bundle;
@@ -81,6 +59,33 @@
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringSet;
import com.android.internal.util.Parcelling.BuiltIn.ForInternedStringValueMap;
import com.android.internal.util.Parcelling.BuiltIn.ForStringSet;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedActivityImpl;
+import com.android.server.pm.pkg.component.ParsedApexSystemService;
+import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl;
+import com.android.server.pm.pkg.component.ParsedAttribution;
+import com.android.server.pm.pkg.component.ParsedAttributionImpl;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
+import com.android.server.pm.pkg.component.ParsedPermissionImpl;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedProviderImpl;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.component.ParsedServiceImpl;
+import com.android.server.pm.pkg.component.ParsedUsesPermission;
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageHidden;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingUtils;
import java.security.PublicKey;
import java.util.Collections;
@@ -1409,7 +1414,7 @@
this.instrumentations = ParsingUtils.createTypedInterfaceList(in,
ParsedInstrumentationImpl.CREATOR);
this.preferredActivityFilters = sForIntentInfoPairs.unparcel(in);
- this.processes = in.readHashMap(boot);
+ this.processes = in.readHashMap(ParsedProcess.class.getClassLoader());
this.metaData = in.readBundle(boot);
this.volumeUuid = sForInternedString.unparcel(in);
this.signingDetails = in.readParcelable(boot);
diff --git a/core/java/android/content/pm/parsing/ParsingPackageInternal.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageInternal.java
similarity index 94%
rename from core/java/android/content/pm/parsing/ParsingPackageInternal.java
rename to services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageInternal.java
index ca16fa2..5457785 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageInternal.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageInternal.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import android.annotation.Nullable;
import android.content.pm.PackageInfo;
diff --git a/core/java/android/content/pm/parsing/ParsingPackageRead.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
similarity index 93%
rename from core/java/android/content/pm/parsing/ParsingPackageRead.java
rename to services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
index a5e98d6..1497112 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageRead.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageRead.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,26 +14,26 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.Property;
-import android.content.pm.PackageParser;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.component.ParsedApexSystemService;
-import android.content.pm.parsing.component.ParsedAttribution;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.content.pm.parsing.component.ParsedProcess;
-import android.content.pm.parsing.component.ParsedUsesPermission;
import android.os.Bundle;
import android.util.ArraySet;
import android.util.Pair;
import android.util.SparseIntArray;
+import com.android.server.pm.pkg.component.ParsedApexSystemService;
+import com.android.server.pm.pkg.component.ParsedAttribution;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.component.ParsedUsesPermission;
+
import java.security.PublicKey;
import java.util.List;
import java.util.Map;
@@ -49,7 +49,7 @@
/**
* The names of packages to adopt ownership of permissions from, parsed under {@link
- * PackageParser#TAG_ADOPT_PERMISSIONS}.
+ * ParsingPackageUtils#TAG_ADOPT_PERMISSIONS}.
*
* @see R.styleable#AndroidManifestOriginalPackage_name
*/
@@ -77,7 +77,7 @@
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * PackageParser#TAG_KEY_SETS}.
+ * ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestKeySet
* @see R.styleable#AndroidManifestPublicKey
@@ -226,7 +226,7 @@
/**
* For use with {@link com.android.server.pm.KeySetManagerService}. Parsed in {@link
- * PackageParser#TAG_KEY_SETS}.
+ * ParsingPackageUtils#TAG_KEY_SETS}.
*
* @see R.styleable#AndroidManifestUpgradeKeySet
*/
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
similarity index 88%
rename from core/java/android/content/pm/parsing/ParsingPackageUtils.java
rename to services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 795e7ef..1ce01f6 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -33,7 +33,6 @@
import android.annotation.AnyRes;
import android.annotation.CheckResult;
import android.annotation.IntDef;
-import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StyleableRes;
@@ -50,39 +49,13 @@
import android.content.pm.PackageManager.Property;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.component.ComponentMutateUtils;
-import android.content.pm.parsing.component.ComponentParseUtils;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedActivityUtils;
-import android.content.pm.parsing.component.ParsedApexSystemService;
-import android.content.pm.parsing.component.ParsedApexSystemServiceUtils;
-import android.content.pm.parsing.component.ParsedAttribution;
-import android.content.pm.parsing.component.ParsedAttributionUtils;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedInstrumentationUtils;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedIntentInfoUtils;
-import android.content.pm.parsing.component.ParsedMainComponent;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.content.pm.parsing.component.ParsedPermissionUtils;
-import android.content.pm.parsing.component.ParsedProcess;
-import android.content.pm.parsing.component.ParsedProcessUtils;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedProviderUtils;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.parsing.component.ParsedServiceUtils;
-import android.content.pm.parsing.component.ParsedUsesPermission;
-import android.content.pm.parsing.component.ParsedUsesPermissionImpl;
+import android.content.pm.parsing.ApkLiteParseUtils;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
+import android.content.pm.parsing.PackageLite;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseInput.DeferredError;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
-import android.content.pm.permission.CompatibilityPermissionInfo;
-import android.content.pm.split.DefaultSplitAssetLoader;
-import android.content.pm.split.SplitAssetDependencyLoader;
-import android.content.pm.split.SplitAssetLoader;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.content.res.Configuration;
@@ -92,7 +65,6 @@
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.os.FileUtils;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -104,7 +76,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AttributeSet;
-import android.util.Base64;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.util.Slog;
@@ -117,6 +88,35 @@
import com.android.internal.os.ClassLoaderFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.server.pm.permission.CompatibilityPermissionInfo;
+import com.android.server.pm.pkg.component.ComponentMutateUtils;
+import com.android.server.pm.pkg.component.ComponentParseUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedActivityUtils;
+import com.android.server.pm.pkg.component.ParsedApexSystemService;
+import com.android.server.pm.pkg.component.ParsedApexSystemServiceUtils;
+import com.android.server.pm.pkg.component.ParsedAttribution;
+import com.android.server.pm.pkg.component.ParsedAttributionUtils;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedInstrumentationUtils;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedIntentInfoUtils;
+import com.android.server.pm.pkg.component.ParsedMainComponent;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedPermissionUtils;
+import com.android.server.pm.pkg.component.ParsedProcess;
+import com.android.server.pm.pkg.component.ParsedProcessUtils;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedProviderUtils;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.component.ParsedServiceUtils;
+import com.android.server.pm.pkg.component.ParsedUsesPermission;
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
+import com.android.server.pm.split.DefaultSplitAssetLoader;
+import com.android.server.pm.split.SplitAssetDependencyLoader;
+import com.android.server.pm.split.SplitAssetLoader;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
@@ -129,14 +129,8 @@
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
-import java.security.spec.EncodedKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -158,10 +152,14 @@
public static final float DEFAULT_PRE_O_MAX_ASPECT_RATIO = 1.86f;
public static final float ASPECT_RATIO_NOT_SET = -1f;
- /** File name in an APK for the Android manifest. */
+ /**
+ * File name in an APK for the Android manifest.
+ */
public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
- /** Path prefix for apps on expanded storage */
+ /**
+ * Path prefix for apps on expanded storage
+ */
public static final String MNT_EXPAND = "/mnt/expand/";
public static final String TAG_ADOPT_PERMISSIONS = "adopt-permissions";
@@ -214,10 +212,11 @@
PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
public static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
- /** If set to true, we will only allow package files that exactly match
- * the DTD. Otherwise, we try to get as much from the package as we
- * can without failing. This should normally be set to false, to
- * support extensions to the DTD in future versions. */
+ /**
+ * If set to true, we will only allow package files that exactly match the DTD. Otherwise, we
+ * try to get as much from the package as we can without failing. This should normally be set to
+ * false, to support extensions to the DTD in future versions.
+ */
public static final boolean RIGID_PARSER = false;
public static final int PARSE_MUST_BE_APK = 1 << 0;
@@ -227,8 +226,8 @@
public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
public static final int PARSE_ENFORCE_CODE = 1 << 6;
/**
- * This flag is applied in the ApkLiteParser. Used by OverlayConfigParser to ignore the
- * checks of required system property within the overlay tag.
+ * This flag is applied in the ApkLiteParser. Used by OverlayConfigParser to ignore the checks
+ * of required system property within the overlay tag.
*/
public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
public static final int PARSE_CHATTY = 1 << 31;
@@ -247,12 +246,6 @@
public @interface ParseFlags {}
/**
- * For those names would be used as a part of the file name. Limits size to 223 and reserves 32
- * for the OS.
- */
- static final int MAX_FILE_NAME_SIZE = 223;
-
- /**
* @see #parseDefault(ParseInput, File, int, List, boolean)
*/
@NonNull
@@ -266,8 +259,8 @@
/**
* For cases outside of PackageManagerService when an APK needs to be parsed as a one-off
- * request, without caching the input object and without querying the internal system state
- * for feature support.
+ * request, without caching the input object and without querying the internal system state for
+ * feature support.
*/
@NonNull
public static ParseResult<ParsingPackage> parseDefault(ParseInput input, File file,
@@ -293,8 +286,7 @@
@NonNull String baseApkPath,
@NonNull String path,
@NonNull TypedArray manifestArray, boolean isCoreApp) {
- return new ParsingPackageImpl(packageName, baseApkPath, path,
- manifestArray);
+ return new ParsingPackageImpl(packageName, baseApkPath, path, manifestArray);
}
});
result = parser.parsePackage(input, file, parseFlags);
@@ -337,21 +329,19 @@
}
/**
- * Parse the package at the given location. Automatically detects if the
- * package is a monolithic style (single APK file) or cluster style
- * (directory of APKs).
+ * Parse the package at the given location. Automatically detects if the package is a monolithic
+ * style (single APK file) or cluster style (directory of APKs).
* <p>
- * This performs validity checking on cluster style packages, such as
- * requiring identical package name and version codes, a single base APK,
- * and unique split names.
+ * This performs validity checking on cluster style packages, such as requiring identical
+ * package name and version codes, a single base APK, and unique split names.
* <p>
- * Note that this <em>does not</em> perform signature verification; that must
- * be done separately in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
- *
- * If {@code useCaches} is true, the package parser might return a cached
- * result from a previous parse of the same {@code packageFile} with the same
- * {@code flags}. Note that this method does not check whether {@code packageFile}
- * has changed since the last parse, it's up to callers to do so.
+ * Note that this <em>does not</em> perform signature verification; that must be done separately
+ * in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
+ * <p>
+ * If {@code useCaches} is true, the package parser might return a cached result from a previous
+ * parse of the same {@code packageFile} with the same {@code flags}. Note that this method does
+ * not check whether {@code packageFile} has changed since the last parse, it's up to callers to
+ * do so.
*/
public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags) {
if (packageFile.isDirectory()) {
@@ -362,13 +352,12 @@
}
/**
- * Parse all APKs contained in the given directory, treating them as a
- * single package. This also performs validity checking, such as requiring
- * identical package name and version codes, a single base APK, and unique
- * split names.
+ * Parse all APKs contained in the given directory, treating them as a single package. This also
+ * performs validity checking, such as requiring identical package name and version codes, a
+ * single base APK, and unique split names.
* <p>
- * Note that this <em>does not</em> perform signature verification; that must
- * be done separately in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
+ * Note that this <em>does not</em> perform signature verification; that must be done separately
+ * in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
int flags) {
@@ -439,8 +428,8 @@
/**
* Parse the given APK file, treating it as as a single monolithic package.
* <p>
- * Note that this <em>does not</em> perform signature verification; that must
- * be done separately in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
+ * Note that this <em>does not</em> perform signature verification; that must be done separately
+ * in {@link #getSigningDetails(ParseInput, ParsingPackageRead, boolean)}.
*/
private ParseResult<ParsingPackage> parseMonolithicPackage(ParseInput input, File apkFile,
int flags) {
@@ -599,9 +588,8 @@
}
/**
- * Parse the manifest of a <em>base APK</em>. When adding new features you
- * need to consider whether they should be supported by split APKs and child
- * packages.
+ * Parse the manifest of a <em>base APK</em>. When adding new features you need to consider
+ * whether they should be supported by split APKs and child packages.
*
* @param apkPath The package apk file path
* @param res The resources from which to resolve values
@@ -653,9 +641,8 @@
/**
* Parse the manifest of a <em>split APK</em>.
* <p>
- * Note that split APKs have many more restrictions on what they're capable
- * of doing, so many valid features of a base APK have been carefully
- * omitted here.
+ * Note that split APKs have many more restrictions on what they're capable of doing, so many
+ * valid features of a base APK have been carefully omitted here.
*
* @param pkg builder to fill
* @return false on failure
@@ -718,9 +705,8 @@
* Parse the {@code application} XML tree at the current parse location in a
* <em>split APK</em> manifest.
* <p>
- * Note that split APKs have many more restrictions on what they're capable
- * of doing, so many valid features of a base APK have been carefully
- * omitted here.
+ * Note that split APKs have many more restrictions on what they're capable of doing, so many
+ * valid features of a base APK have been carefully omitted here.
*/
private ParseResult<ParsingPackage> parseSplitApplication(ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags, int splitIndex)
@@ -1030,7 +1016,8 @@
}
if (!"android".equals(pkg.getPackageName())) {
- ParseResult<?> nameResult = validateName(input, str, true, true);
+ ParseResult<?> nameResult = FrameworkParsingPackageUtils.validateName(input, str,
+ true, true);
if (nameResult.isError()) {
return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID,
"<manifest> specifies bad sharedUserId name \"" + str + "\": "
@@ -1101,7 +1088,8 @@
+ " must define a public-key value on first use at "
+ parser.getPositionDescription());
} else if (encodedKey != null) {
- PublicKey currentKey = parsePublicKey(encodedKey);
+ PublicKey currentKey =
+ FrameworkParsingPackageUtils.parsePublicKey(encodedKey);
if (currentKey == null) {
Slog.w(TAG, "No recognized valid key in 'public-key' tag at "
+ parser.getPositionDescription() + " key-set "
@@ -1534,8 +1522,8 @@
targetCode = minCode;
}
- ParseResult<Integer> targetSdkVersionResult = computeTargetSdkVersion(
- targetVers, targetCode, SDK_CODENAMES, input);
+ ParseResult<Integer> targetSdkVersionResult = FrameworkParsingPackageUtils
+ .computeTargetSdkVersion(targetVers, targetCode, SDK_CODENAMES, input);
if (targetSdkVersionResult.isError()) {
return input.error(targetSdkVersionResult);
}
@@ -1548,8 +1536,8 @@
return input.error(deferResult);
}
- ParseResult<Integer> minSdkVersionResult = computeMinSdkVersion(minVers, minCode,
- SDK_VERSION, SDK_CODENAMES, input);
+ ParseResult<Integer> minSdkVersionResult = FrameworkParsingPackageUtils
+ .computeMinSdkVersion(minVers, minCode, SDK_VERSION, SDK_CODENAMES, input);
if (minSdkVersionResult.isError()) {
return input.error(minSdkVersionResult);
}
@@ -1644,146 +1632,6 @@
return input.success(minExtensionVersions);
}
- /**
- * Computes the minSdkVersion to use at runtime. If the package is not
- * compatible with this platform, populates {@code outError[0]} with an
- * error message.
- * <p>
- * If {@code minCode} is not specified, e.g. the value is {@code null},
- * then behavior varies based on the {@code platformSdkVersion}:
- * <ul>
- * <li>If the platform SDK version is greater than or equal to the
- * {@code minVers}, returns the {@code mniVers} unmodified.
- * <li>Otherwise, returns -1 to indicate that the package is not
- * compatible with this platform.
- * </ul>
- * <p>
- * Otherwise, the behavior varies based on whether the current platform
- * is a pre-release version, e.g. the {@code platformSdkCodenames} array
- * has length > 0:
- * <ul>
- * <li>If this is a pre-release platform and the value specified by
- * {@code targetCode} is contained within the array of allowed pre-release
- * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
- * <li>If this is a released platform, this method will return -1 to
- * indicate that the package is not compatible with this platform.
- * </ul>
- *
- * @param minVers minSdkVersion number, if specified in the application
- * manifest, or 1 otherwise
- * @param minCode minSdkVersion code, if specified in the application
- * manifest, or {@code null} otherwise
- * @param platformSdkVersion platform SDK version number, typically
- * Build.VERSION.SDK_INT
- * @param platformSdkCodenames array of allowed prerelease SDK codenames
- * for this platform
- * @return the minSdkVersion to use at runtime if successful
- */
- public static ParseResult<Integer> computeMinSdkVersion(@IntRange(from = 1) int minVers,
- @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
- @NonNull String[] platformSdkCodenames, @NonNull ParseInput input) {
- // If it's a release SDK, make sure we meet the minimum SDK requirement.
- if (minCode == null) {
- if (minVers <= platformSdkVersion) {
- return input.success(minVers);
- }
-
- // We don't meet the minimum SDK requirement.
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
- "Requires newer sdk version #" + minVers
- + " (current version is #" + platformSdkVersion + ")");
- }
-
- // If it's a pre-release SDK and the codename matches this platform, we
- // definitely meet the minimum SDK requirement.
- if (matchTargetCode(platformSdkCodenames, minCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
- }
-
- // Otherwise, we're looking at an incompatible pre-release SDK.
- if (platformSdkCodenames.length > 0) {
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
- "Requires development platform " + minCode
- + " (current platform is any of "
- + Arrays.toString(platformSdkCodenames) + ")");
- } else {
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
- "Requires development platform " + minCode
- + " but this is a release platform.");
- }
- }
-
- /**
- * Computes the targetSdkVersion to use at runtime. If the package is not
- * compatible with this platform, populates {@code outError[0]} with an
- * error message.
- * <p>
- * If {@code targetCode} is not specified, e.g. the value is {@code null},
- * then the {@code targetVers} will be returned unmodified.
- * <p>
- * Otherwise, the behavior varies based on whether the current platform
- * is a pre-release version, e.g. the {@code platformSdkCodenames} array
- * has length > 0:
- * <ul>
- * <li>If this is a pre-release platform and the value specified by
- * {@code targetCode} is contained within the array of allowed pre-release
- * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
- * <li>If this is a released platform, this method will return -1 to
- * indicate that the package is not compatible with this platform.
- * </ul>
- *
- * @param targetVers targetSdkVersion number, if specified in the
- * application manifest, or 0 otherwise
- * @param targetCode targetSdkVersion code, if specified in the application
- * manifest, or {@code null} otherwise
- * @param platformSdkCodenames array of allowed pre-release SDK codenames
- * for this platform
- * @return the targetSdkVersion to use at runtime if successful
- */
- public static ParseResult<Integer> computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
- @Nullable String targetCode, @NonNull String[] platformSdkCodenames,
- @NonNull ParseInput input) {
- // If it's a release SDK, return the version number unmodified.
- if (targetCode == null) {
- return input.success(targetVers);
- }
-
- // If it's a pre-release SDK and the codename matches this platform, it
- // definitely targets this SDK.
- if (matchTargetCode(platformSdkCodenames, targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
- }
-
- // Otherwise, we're looking at an incompatible pre-release SDK.
- if (platformSdkCodenames.length > 0) {
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
- "Requires development platform " + targetCode
- + " (current platform is any of "
- + Arrays.toString(platformSdkCodenames) + ")");
- } else {
- return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
- "Requires development platform " + targetCode
- + " but this is a release platform.");
- }
- }
-
- /**
- * Matches a given {@code targetCode} against a set of release codeNames. Target codes can
- * either be of the form {@code [codename]}" (e.g {@code "Q"}) or of the form
- * {@code [codename].[fingerprint]} (e.g {@code "Q.cafebc561"}).
- */
- private static boolean matchTargetCode(@NonNull String[] codeNames,
- @NonNull String targetCode) {
- final String targetCodeName;
- final int targetCodeIdx = targetCode.indexOf('.');
- if (targetCodeIdx == -1) {
- targetCodeName = targetCode;
- } else {
- targetCodeName = targetCode.substring(0, targetCodeIdx);
- }
- return ArrayUtils.contains(codeNames, targetCodeName);
- }
-
private static ParseResult<ParsingPackage> parseRestrictUpdateHash(int flags, ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser) {
if ((flags & PARSE_IS_SYSTEM_DIR) != 0) {
@@ -1925,12 +1773,11 @@
* Parse the {@code application} XML tree at the current parse location in a
* <em>base APK</em> manifest.
* <p>
- * When adding new features, carefully consider if they should also be
- * supported by split APKs.
- *
- * This method should avoid using a getter for fields set by this method. Prefer assigning
- * a local variable and using it. Otherwise there's an ordering problem which can be broken
- * if any code moves around.
+ * When adding new features, carefully consider if they should also be supported by split APKs.
+ * <p>
+ * This method should avoid using a getter for fields set by this method. Prefer assigning a
+ * local variable and using it. Otherwise there's an ordering problem which can be broken if any
+ * code moves around.
*/
private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
@@ -2276,7 +2123,7 @@
/**
* Collection of single-line, no (or little) logic assignments. Separated for readability.
- *
+ * <p>
* Flags are separated by type and by default value. They are sorted alphabetically within each
* section.
*/
@@ -2893,7 +2740,7 @@
R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyName);
String propValue = sa.getString(
R.styleable.AndroidManifestResourceOverlay_requiredSystemPropertyValue);
- if (!checkRequiredSystemProperties(propName, propValue)) {
+ if (!FrameworkParsingPackageUtils.checkRequiredSystemProperties(propName, propValue)) {
String message = "Skipping target and overlay pair " + target + " and "
+ pkg.getBaseApkPath()
+ ": overlay ignored due to required system property: "
@@ -3056,60 +2903,6 @@
}
/**
- * Check if the given name is valid.
- *
- * @param name The name to check.
- * @param requireSeparator {@code true} if the name requires containing a separator at least.
- * @param requireFilename {@code true} to apply file name validation to the given name. It also
- * limits length of the name to the {@link #MAX_FILE_NAME_SIZE}.
- * @return Success if it's valid.
- */
- public static String validateName(String name, boolean requireSeparator,
- boolean requireFilename) {
- final int N = name.length();
- boolean hasSep = false;
- boolean front = true;
- for (int i = 0; i < N; i++) {
- final char c = name.charAt(i);
- if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
- front = false;
- continue;
- }
- if (!front) {
- if ((c >= '0' && c <= '9') || c == '_') {
- continue;
- }
- }
- if (c == '.') {
- hasSep = true;
- front = true;
- continue;
- }
- return "bad character '" + c + "'";
- }
- if (requireFilename) {
- if (!FileUtils.isValidExtFilename(name)) {
- return "Invalid filename";
- } else if (N > MAX_FILE_NAME_SIZE) {
- return "the length of the name is greater than " + MAX_FILE_NAME_SIZE;
- }
- }
- return hasSep || !requireSeparator ? null : "must have at least one '.' separator";
- }
-
- /**
- * @see #validateName(String, boolean, boolean)
- */
- public static ParseResult validateName(ParseInput input, String name, boolean requireSeparator,
- boolean requireFilename) {
- final String errorMessage = validateName(name, requireSeparator, requireFilename);
- if (errorMessage != null) {
- return input.error(errorMessage);
- }
- return input.success(null);
- }
-
- /**
* Parse a meta data defined on the enclosing tag.
* <p>Meta data can be defined by either <meta-data> or <property> elements.
*/
@@ -3169,114 +2962,6 @@
}
/**
- * @return {@link PublicKey} of a given encoded public key.
- */
- public static final PublicKey parsePublicKey(final String encodedPublicKey) {
- if (encodedPublicKey == null) {
- Slog.w(TAG, "Could not parse null public key");
- return null;
- }
-
- try {
- return parsePublicKey(Base64.decode(encodedPublicKey, Base64.DEFAULT));
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
- return null;
- }
- }
-
- /**
- * @return {@link PublicKey} of the given byte array of a public key.
- */
- public static final PublicKey parsePublicKey(final byte[] publicKey) {
- if (publicKey == null) {
- Slog.w(TAG, "Could not parse null public key");
- return null;
- }
-
- final EncodedKeySpec keySpec;
- try {
- keySpec = new X509EncodedKeySpec(publicKey);
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Could not parse verifier public key; invalid Base64");
- return null;
- }
-
- /* First try the key as an RSA key. */
- try {
- final KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- return keyFactory.generatePublic(keySpec);
- } catch (NoSuchAlgorithmException e) {
- Slog.wtf(TAG, "Could not parse public key: RSA KeyFactory not included in build");
- } catch (InvalidKeySpecException e) {
- // Not a RSA public key.
- }
-
- /* Now try it as a ECDSA key. */
- try {
- final KeyFactory keyFactory = KeyFactory.getInstance("EC");
- return keyFactory.generatePublic(keySpec);
- } catch (NoSuchAlgorithmException e) {
- Slog.wtf(TAG, "Could not parse public key: EC KeyFactory not included in build");
- } catch (InvalidKeySpecException e) {
- // Not a ECDSA public key.
- }
-
- /* Now try it as a DSA key. */
- try {
- final KeyFactory keyFactory = KeyFactory.getInstance("DSA");
- return keyFactory.generatePublic(keySpec);
- } catch (NoSuchAlgorithmException e) {
- Slog.wtf(TAG, "Could not parse public key: DSA KeyFactory not included in build");
- } catch (InvalidKeySpecException e) {
- // Not a DSA public key.
- }
-
- /* Not a supported key type */
- return null;
- }
-
- /**
- * Returns {@code true} if both the property name and value are empty or if the given system
- * property is set to the specified value. Properties can be one or more, and if properties are
- * more than one, they must be separated by comma, and count of names and values must be equal,
- * and also every given system property must be set to the corresponding value.
- * In all other cases, returns {@code false}
- */
- public static boolean checkRequiredSystemProperties(@Nullable String rawPropNames,
- @Nullable String rawPropValues) {
- if (TextUtils.isEmpty(rawPropNames) || TextUtils.isEmpty(rawPropValues)) {
- if (!TextUtils.isEmpty(rawPropNames) || !TextUtils.isEmpty(rawPropValues)) {
- // malformed condition - incomplete
- Slog.w(TAG, "Disabling overlay - incomplete property :'" + rawPropNames
- + "=" + rawPropValues + "' - require both requiredSystemPropertyName"
- + " AND requiredSystemPropertyValue to be specified.");
- return false;
- }
- // no valid condition set - so no exclusion criteria, overlay will be included.
- return true;
- }
-
- final String[] propNames = rawPropNames.split(",");
- final String[] propValues = rawPropValues.split(",");
-
- if (propNames.length != propValues.length) {
- Slog.w(TAG, "Disabling overlay - property :'" + rawPropNames
- + "=" + rawPropValues + "' - require both requiredSystemPropertyName"
- + " AND requiredSystemPropertyValue lists to have the same size.");
- return false;
- }
- for (int i = 0; i < propNames.length; i++) {
- // Check property value: make sure it is both set and equal to expected value
- final String currValue = SystemProperties.get(propNames[i]);
- if (!TextUtils.equals(currValue, propValues[i])) {
- return false;
- }
- }
- return true;
- }
-
- /**
* Collect certificates from all the APKs described in the given package. Also asserts that
* all APK contents are signed correctly and consistently.
*
diff --git a/core/java/android/content/pm/parsing/ParsingUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
similarity index 92%
rename from core/java/android/content/pm/parsing/ParsingUtils.java
rename to services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
index cce984e..95fec36 100644
--- a/core/java/android/content/pm/parsing/ParsingUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingUtils.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
-import static android.content.pm.parsing.ParsingPackageUtils.RIGID_PARSER;
+import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.RIGID_PARSER;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedIntentInfoImpl;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
import android.content.pm.parsing.result.ParseInput;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.XmlResourceParser;
@@ -138,7 +138,7 @@
final List<Pair<String, ParsedIntentInfo>> list = new ArrayList<>(size);
for (int i = 0; i < size; ++i) {
list.add(Pair.create(source.readString(), source.readParcelable(
- ParsedIntentInfoImpl.class.getClassLoader())));
+ ParsedIntentInfoImpl.class.getClassLoader(), ParsedIntentInfo.class)));
}
return list;
diff --git a/core/java/android/content/pm/parsing/PkgWithoutStateAppInfo.java b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
similarity index 98%
rename from core/java/android/content/pm/parsing/PkgWithoutStateAppInfo.java
rename to services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
index 625b9d1..a323e20 100644
--- a/core/java/android/content/pm/parsing/PkgWithoutStateAppInfo.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStateAppInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import android.annotation.NonNull;
import android.annotation.Nullable;
diff --git a/core/java/android/content/pm/parsing/PkgWithoutStatePackageInfo.java b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStatePackageInfo.java
similarity index 92%
rename from core/java/android/content/pm/parsing/PkgWithoutStatePackageInfo.java
rename to services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStatePackageInfo.java
index 7d758a8..2bc4ee7 100644
--- a/core/java/android/content/pm/parsing/PkgWithoutStatePackageInfo.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/PkgWithoutStatePackageInfo.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm.parsing;
+package com.android.server.pm.pkg.parsing;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -29,14 +29,14 @@
import android.content.pm.PermissionInfo;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.pkg.FrameworkPackageUserState;
import com.android.internal.R;
+import com.android.server.pm.pkg.PackageUserState;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedService;
import java.util.List;
@@ -82,7 +82,7 @@
* provide the same information as {@link ActivityInfo}. Effective state can be queried through
* {@link android.content.pm.PackageManager#getActivityInfo(ComponentName, int)} or by
* combining state from from com.android.server.pm.pkg.PackageState and
- * {@link FrameworkPackageUserState}.
+ * {@link PackageUserState}.
*
* @see ActivityInfo
* @see PackageInfo#activities
@@ -153,7 +153,7 @@
* provide the same information as {@link ProviderInfo}. Effective state can be queried through
* {@link android.content.pm.PackageManager#getProviderInfo(ComponentName, int)} or by
* combining state from from com.android.server.pm.pkg.PackageState and
- * {@link FrameworkPackageUserState}.
+ * {@link PackageUserState}.
*
* @see ProviderInfo
* @see PackageInfo#providers
@@ -168,7 +168,7 @@
* provide the same information as {@link ActivityInfo}. Effective state can be queried through
* {@link android.content.pm.PackageManager#getReceiverInfo(ComponentName, int)} or by
* combining state from from com.android.server.pm.pkg.PackageState and
- * {@link FrameworkPackageUserState}.
+ * {@link PackageUserState}.
*
* Since they share several attributes, receivers are parsed as {@link ParsedActivity}, even
* though they represent different functionality.
@@ -222,7 +222,7 @@
* provide the same information as {@link ServiceInfo}. Effective state can be queried through
* {@link android.content.pm.PackageManager#getServiceInfo(ComponentName, int)} or by
* combining state from from com.android.server.pm.pkg.PackageState and
- * {@link FrameworkPackageUserState}.
+ * {@link PackageUserState}.
*
* @see ServiceInfo
* @see PackageInfo#services
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
similarity index 93%
rename from core/java/android/content/pm/split/DefaultSplitAssetLoader.java
rename to services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
index 47cf28b..2bd7cf8 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/services/core/java/com/android/server/pm/split/DefaultSplitAssetLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.content.pm.split;
+package com.android.server.pm.split;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.ParsingPackageUtils.ParseFlags;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.os.Build;
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
similarity index 94%
rename from core/java/android/content/pm/split/SplitAssetDependencyLoader.java
rename to services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
index a0c3f75..ae42e09 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/services/core/java/com/android/server/pm/split/SplitAssetDependencyLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -13,18 +13,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.content.pm.split;
+package com.android.server.pm.split;
import android.annotation.NonNull;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.content.pm.parsing.PackageLite;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.ParsingPackageUtils.ParseFlags;
+import android.content.pm.split.SplitDependencyLoader;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
import android.os.Build;
import android.util.SparseArray;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils.ParseFlags;
+
import libcore.io.IoUtils;
import java.io.IOException;
diff --git a/core/java/android/content/pm/split/SplitAssetLoader.java b/services/core/java/com/android/server/pm/split/SplitAssetLoader.java
similarity index 91%
rename from core/java/android/content/pm/split/SplitAssetLoader.java
rename to services/core/java/com/android/server/pm/split/SplitAssetLoader.java
index d314e06..8450159 100644
--- a/core/java/android/content/pm/split/SplitAssetLoader.java
+++ b/services/core/java/com/android/server/pm/split/SplitAssetLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016 The Android Open Source Project
+ * 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.
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.content.pm.split;
+package com.android.server.pm.split;
import android.content.res.ApkAssets;
import android.content.res.AssetManager;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
index d47f510..e078120 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationCollector.java
@@ -22,8 +22,8 @@
import android.compat.annotation.EnabledSince;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
import android.os.Build;
import android.text.TextUtils;
import android.util.ArraySet;
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index d1603f5..d0b50d27 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -31,8 +31,6 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.pkg.PackageUserStateUtils;
import android.content.pm.verify.domain.DomainOwner;
import android.content.pm.verify.domain.DomainVerificationInfo;
import android.content.pm.verify.domain.DomainVerificationManager;
@@ -63,6 +61,8 @@
import com.android.server.pm.pkg.PackageStateInternal;
import com.android.server.pm.pkg.PackageStateUtils;
import com.android.server.pm.pkg.PackageUserState;
+import com.android.server.pm.pkg.PackageUserStateUtils;
+import com.android.server.pm.pkg.component.ParsedActivity;
import com.android.server.pm.verify.domain.models.DomainVerificationInternalUserState;
import com.android.server.pm.verify.domain.models.DomainVerificationPkgState;
import com.android.server.pm.verify.domain.models.DomainVerificationStateMap;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 4b71742..fc87253 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -46,6 +46,7 @@
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
+import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
@@ -123,6 +124,8 @@
private static final int MSG_REFRESH_DEVICE_LOCKED_FOR_USER = 14;
private static final int MSG_SCHEDULE_TRUST_TIMEOUT = 15;
+ private static final String REFRESH_DEVICE_LOCKED_EXCEPT_USER = "except";
+
private static final int TRUST_USUALLY_MANAGED_FLUSH_DELAY = 2 * 60 * 1000;
private static final String TRUST_TIMEOUT_ALARM_TAG = "TrustManagerService.trustTimeoutForUser";
private static final long TRUST_TIMEOUT_IN_MILLIS = 4 * 60 * 60 * 1000;
@@ -635,11 +638,18 @@
}
}
+ private void refreshDeviceLockedForUser(int userId) {
+ refreshDeviceLockedForUser(userId, UserHandle.USER_NULL);
+ }
+
/**
* Update the user's locked state. Only applicable to users with a real keyguard
* ({@link UserInfo#supportsSwitchToByUser}) and unsecured managed profiles.
+ *
+ * If this is called due to an unlock operation set unlockedUser to prevent the lock from
+ * being prematurely reset for that user while keyguard is still in the process of going away.
*/
- private void refreshDeviceLockedForUser(int userId) {
+ private void refreshDeviceLockedForUser(int userId, int unlockedUser) {
if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_SYSTEM) {
Log.e(TAG, "refreshDeviceLockedForUser(userId=" + userId + "): Invalid user handle,"
+ " must be USER_ALL or a specific user.", new Throwable("here"));
@@ -675,6 +685,7 @@
boolean trusted = aggregateIsTrusted(id);
boolean showingKeyguard = true;
boolean biometricAuthenticated = false;
+ boolean currentUserIsUnlocked = false;
if (mCurrentUser == id) {
synchronized(mUsersUnlockedByBiometric) {
@@ -683,10 +694,17 @@
try {
showingKeyguard = wm.isKeyguardLocked();
} catch (RemoteException e) {
+ Log.w(TAG, "Unable to check keyguard lock state", e);
}
+ currentUserIsUnlocked = unlockedUser == id;
}
- boolean deviceLocked = secure && showingKeyguard && !trusted &&
- !biometricAuthenticated;
+ final boolean deviceLocked = secure && showingKeyguard && !trusted
+ && !biometricAuthenticated;
+ if (deviceLocked && currentUserIsUnlocked) {
+ // keyguard is finishing but may not have completed going away yet
+ continue;
+ }
+
setDeviceLockedForUser(id, deviceLocked);
}
}
@@ -1306,13 +1324,20 @@
}
@Override
- public void clearAllBiometricRecognized(BiometricSourceType biometricSource) {
+ public void clearAllBiometricRecognized(
+ BiometricSourceType biometricSource, int unlockedUser) {
enforceReportPermission();
synchronized(mUsersUnlockedByBiometric) {
mUsersUnlockedByBiometric.clear();
}
- mHandler.obtainMessage(MSG_REFRESH_DEVICE_LOCKED_FOR_USER, UserHandle.USER_ALL,
- 0 /* arg2 */).sendToTarget();
+ Message message = mHandler.obtainMessage(MSG_REFRESH_DEVICE_LOCKED_FOR_USER,
+ UserHandle.USER_ALL, 0 /* arg2 */);
+ if (unlockedUser >= 0) {
+ Bundle bundle = new Bundle();
+ bundle.putInt(REFRESH_DEVICE_LOCKED_EXCEPT_USER, unlockedUser);
+ message.setData(bundle);
+ }
+ message.sendToTarget();
}
};
@@ -1404,9 +1429,11 @@
break;
case MSG_REFRESH_DEVICE_LOCKED_FOR_USER:
if (msg.arg2 == 1) {
- updateTrust(msg.arg1, 0 /* flags */, true);
+ updateTrust(msg.arg1, 0 /* flags */, true /* isFromUnlock */);
}
- refreshDeviceLockedForUser(msg.arg1);
+ final int unlockedUser = msg.getData().getInt(
+ REFRESH_DEVICE_LOCKED_EXCEPT_USER, UserHandle.USER_NULL);
+ refreshDeviceLockedForUser(msg.arg1, unlockedUser);
break;
case MSG_SCHEDULE_TRUST_TIMEOUT:
handleScheduleTrustTimeout(msg.arg1, msg.arg2);
diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
index 48dd2f4..4df2e17 100644
--- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
+++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java
@@ -53,7 +53,6 @@
*/
@IntDef(suffix = { "_ORDERED_ID" }, value = {
FIRST_ORDERED_ID,
- COMMUNAL_MODE_ORDERED_ID,
PERMISSION_POLICY_ORDERED_ID,
VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
LAST_ORDERED_ID // Update this when adding new ids
@@ -67,14 +66,9 @@
static final int FIRST_ORDERED_ID = 0;
/**
- * The identifier for {@link com.android.server.communal.CommunalManagerService} interceptor.
- */
- public static final int COMMUNAL_MODE_ORDERED_ID = 1;
-
- /**
* The identifier for {@link com.android.server.policy.PermissionPolicyService} interceptor
*/
- public static final int PERMISSION_POLICY_ORDERED_ID = 2;
+ public static final int PERMISSION_POLICY_ORDERED_ID = 1;
/**
* The identifier for {@link com.android.server.companion.virtual.VirtualDeviceManagerService}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index d91f48e..b355fe7 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1050,8 +1050,6 @@
mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
mAppTransition.registerListenerLocked(mWmService.mActivityManagerAppTransitionNotifier);
- mTransitionController.registerLegacyListener(
- mWmService.mActivityManagerAppTransitionNotifier);
mAppTransition.registerListenerLocked(mFixedRotationTransitionListener);
mAppTransitionController = new AppTransitionController(mWmService, this);
mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
@@ -4103,7 +4101,7 @@
"IME-snapshot-surface");
t.setBuffer(imeSurface, buffer);
t.setColorSpace(mSurfaceControl, ColorSpace.get(ColorSpace.Named.SRGB));
- t.setRelativeLayer(imeSurface, activity.getSurfaceControl(), 1);
+ t.setLayer(imeSurface, 1);
t.setPosition(imeSurface, mInputMethodWindow.getDisplayFrame().left,
mInputMethodWindow.getDisplayFrame().top);
return imeSurface;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index f71fd1b..0745b3b 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -2851,6 +2851,7 @@
}
void release() {
+ mDisplayContent.mTransitionController.unregisterLegacyListener(mAppTransitionListener);
mHandler.post(mGestureNavigationSettingsObserver::unregister);
mImmersiveModeConfirmation.release();
}
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index a477108..b13c9a9 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -79,6 +79,7 @@
import android.window.TransitionInfo;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
import com.android.internal.protolog.ProtoLogGroup;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
@@ -1271,6 +1272,14 @@
change.setAllowEnterPip(topMostActivity != null
&& topMostActivity.checkEnterPictureInPictureAppOpsState());
}
+ final ActivityRecord activityRecord = target.asActivityRecord();
+ if (activityRecord != null) {
+ final Task arTask = activityRecord.getTask();
+ final int backgroundColor = ColorUtils.setAlphaComponent(
+ arTask.getTaskDescription().getBackgroundColor(), 255);
+ change.setBackgroundColor(backgroundColor);
+ }
+
out.addChange(change);
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index ffe1462..fe968ec 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -462,6 +462,10 @@
mLegacyListeners.add(listener);
}
+ void unregisterLegacyListener(WindowManagerInternal.AppTransitionListener listener) {
+ mLegacyListeners.remove(listener);
+ }
+
void dispatchLegacyAppTransitionPending() {
for (int i = 0; i < mLegacyListeners.size(); ++i) {
mLegacyListeners.get(i).onAppTransitionPendingLocked();
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 79dcbcb..455856c 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -139,6 +139,7 @@
void setWindowManager(WindowManagerService wms) {
mTransitionController = new TransitionController(mService, wms.mTaskSnapshotController);
+ mTransitionController.registerLegacyListener(wms.mActivityManagerAppTransitionNotifier);
}
TransitionController getTransitionController() {
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..4b21454 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -115,7 +115,6 @@
import com.android.server.broadcastradio.BroadcastRadioService;
import com.android.server.camera.CameraServiceProxy;
import com.android.server.clipboard.ClipboardService;
-import com.android.server.communal.CommunalManagerService;
import com.android.server.compat.PlatformCompat;
import com.android.server.compat.PlatformCompatNative;
import com.android.server.connectivity.PacProxyService;
@@ -152,7 +151,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 +219,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 +259,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 +1454,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 +1462,7 @@
t.traceBegin("StartTelephonyRegistry");
telephonyRegistry = new TelephonyRegistry(
- context, new TelephonyRegistry.ConfigurationProvider());
+ context, new TelephonyRegistry.ConfigurationProvider());
ServiceManager.addService("telephony.registry", telephonyRegistry);
t.traceEnd();
@@ -2547,12 +2541,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);
@@ -2758,12 +2746,6 @@
mSystemServiceManager.startService(APP_COMPAT_OVERRIDES_SERVICE_CLASS);
t.traceEnd();
- if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_COMMUNAL_MODE)) {
- t.traceBegin("CommunalManagerService");
- mSystemServiceManager.startService(CommunalManagerService.class);
- t.traceEnd();
- }
-
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
@@ -2999,9 +2981,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 +3046,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/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
index 8203c1b..5220c8f 100644
--- a/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
+++ b/services/tests/PackageManagerComponentOverrideTests/src/com/android/server/pm/test/override/PackageManagerComponentLabelIconOverrideTest.kt
@@ -20,7 +20,7 @@
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
-import android.content.pm.parsing.component.ParsedActivity
+import com.android.server.pm.pkg.component.ParsedActivity
import android.os.Binder
import android.os.UserHandle
import android.util.ArrayMap
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
index ebad5af..93d70bb 100644
--- a/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/UsesStaticLibrary/Android.bp
@@ -24,7 +24,7 @@
android_test_helper_app {
name: "PackageManagerTestAppDeclaresStaticLibrary",
manifest: "AndroidManifestDeclaresStaticLibrary.xml",
- certificate: ":FrameworksCoreTests_keyset_A_cert",
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
}
android_test_helper_app {
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 8cf6fe3..a0f3bbf 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -23,8 +23,7 @@
import android.content.pm.FeatureInfo
import android.content.pm.PackageManager
import android.content.pm.SigningDetails
-import android.content.pm.parsing.ParsingPackage
-import android.content.pm.parsing.component.*
+import com.android.server.pm.pkg.parsing.ParsingPackage
import android.net.Uri
import android.os.Bundle
import android.os.Parcelable
@@ -34,6 +33,18 @@
import com.android.internal.R
import com.android.server.pm.parsing.pkg.AndroidPackage
import com.android.server.pm.parsing.pkg.PackageImpl
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl
+import com.android.server.pm.pkg.component.ParsedAttributionImpl
+import com.android.server.pm.pkg.component.ParsedComponentImpl
+import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.server.pm.pkg.component.ParsedPermissionImpl
+import com.android.server.pm.pkg.component.ParsedProcessImpl
+import com.android.server.pm.pkg.component.ParsedProviderImpl
+import com.android.server.pm.pkg.component.ParsedServiceImpl
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
import com.android.server.testutils.mockThrowOnUnmocked
import com.android.server.testutils.whenever
import java.security.KeyPairGenerator
@@ -281,7 +292,13 @@
PackageImpl::addAttribution,
Triple("testTag", 13, listOf("testInherit")),
transformGet = { it.singleOrNull()?.let { Triple(it.tag, it.label, it.inheritFrom) } },
- transformSet = { it?.let { ParsedAttributionImpl(it.first, it.second, it.third) } }
+ transformSet = { it?.let {
+ ParsedAttributionImpl(
+ it.first,
+ it.second,
+ it.third
+ )
+ } }
),
getSetByValue2(
AndroidPackage::getKeySetMapping,
@@ -294,12 +311,14 @@
PackageImpl::addPermissionGroup,
"test.permission.GROUP",
transformGet = { it.singleOrNull()?.name },
- transformSet = { ParsedPermissionGroupImpl().apply { setName(it) } }
+ transformSet = { ParsedPermissionGroupImpl()
+ .apply { setName(it) } }
),
getSetByValue2(
AndroidPackage::getPreferredActivityFilters,
PackageImpl::addPreferredActivityFilter,
- "TestClassName" to ParsedIntentInfoImpl().apply {
+ "TestClassName" to ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
addDataScheme("http")
addDataAuthority("test.pm.server.android.com", null)
@@ -348,42 +367,48 @@
PackageImpl::addActivity,
"TestActivityName",
transformGet = { it.singleOrNull()?.name.orEmpty() },
- transformSet = { ParsedActivityImpl().apply { name = it }.withMimeGroups() }
+ transformSet = { ParsedActivityImpl()
+ .apply { name = it }.withMimeGroups() }
),
getSetByValue(
AndroidPackage::getApexSystemServices,
PackageImpl::addApexSystemService,
"TestApexSystemServiceName",
transformGet = { it.singleOrNull()?.name.orEmpty() },
- transformSet = { ParsedApexSystemServiceImpl().apply { name = it } }
+ transformSet = { ParsedApexSystemServiceImpl()
+ .apply { name = it } }
),
getSetByValue(
AndroidPackage::getReceivers,
PackageImpl::addReceiver,
"TestReceiverName",
transformGet = { it.singleOrNull()?.name.orEmpty() },
- transformSet = { ParsedActivityImpl().apply { name = it }.withMimeGroups() }
+ transformSet = { ParsedActivityImpl()
+ .apply { name = it }.withMimeGroups() }
),
getSetByValue(
AndroidPackage::getServices,
PackageImpl::addService,
"TestServiceName",
transformGet = { it.singleOrNull()?.name.orEmpty() },
- transformSet = { ParsedServiceImpl().apply { name = it }.withMimeGroups() }
+ transformSet = { ParsedServiceImpl()
+ .apply { name = it }.withMimeGroups() }
),
getSetByValue(
AndroidPackage::getProviders,
PackageImpl::addProvider,
"TestProviderName",
transformGet = { it.singleOrNull()?.name.orEmpty() },
- transformSet = { ParsedProviderImpl().apply { name = it }.withMimeGroups() }
+ transformSet = { ParsedProviderImpl()
+ .apply { name = it }.withMimeGroups() }
),
getSetByValue(
AndroidPackage::getInstrumentations,
PackageImpl::addInstrumentation,
"TestInstrumentationName",
transformGet = { it.singleOrNull()?.name.orEmpty() },
- transformSet = { ParsedInstrumentationImpl().apply { name = it } }
+ transformSet = { ParsedInstrumentationImpl()
+ .apply { name = it } }
),
getSetByValue(
AndroidPackage::getConfigPreferences,
@@ -408,7 +433,8 @@
PackageImpl::addPermission,
"test.PERMISSION",
transformGet = { it.singleOrNull()?.name.orEmpty() },
- transformSet = { ParsedPermissionImpl().apply { name = it } }
+ transformSet = { ParsedPermissionImpl()
+ .apply { name = it } }
),
getSetByValue(
AndroidPackage::getUsesPermissions,
@@ -419,7 +445,12 @@
it.filterNot { it.name == "test.implicit.PERMISSION" }
.singleOrNull()?.name.orEmpty()
},
- transformSet = { ParsedUsesPermissionImpl(it, 0) }
+ transformSet = {
+ ParsedUsesPermissionImpl(
+ it,
+ 0
+ )
+ }
),
getSetByValue(
AndroidPackage::getRequestedFeatures,
@@ -444,7 +475,8 @@
getSetByValue(
AndroidPackage::getProcesses,
PackageImpl::setProcesses,
- mapOf("testProcess" to ParsedProcessImpl().apply { name = "testProcessName" }),
+ mapOf("testProcess" to ParsedProcessImpl()
+ .apply { name = "testProcessName" }),
compare = { first, second ->
equalBy(
first, second,
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
index 8170acf..a89b717 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
@@ -17,8 +17,8 @@
package com.android.server.pm.test.parsing.parcelling
import android.content.pm.ActivityInfo
-import android.content.pm.parsing.component.ParsedActivity
-import android.content.pm.parsing.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedActivity
+import com.android.server.pm.pkg.component.ParsedActivityImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
@@ -27,7 +27,8 @@
ParsedActivityImpl::class
) {
- override val defaultImpl = ParsedActivityImpl()
+ override val defaultImpl =
+ ParsedActivityImpl()
override val creator = ParsedActivityImpl.CREATOR
override val mainComponentSubclassBaseParams = listOf(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
index 503301b..4e44e96 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedAttributionTest.kt
@@ -16,15 +16,21 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedAttribution
-import android.content.pm.parsing.component.ParsedAttributionImpl
+import com.android.server.pm.pkg.component.ParsedAttribution
+import com.android.server.pm.pkg.component.ParsedAttributionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
-class ParsedAttributionTest : ParcelableComponentTest(ParsedAttribution::class,
+class ParsedAttributionTest : ParcelableComponentTest(
+ ParsedAttribution::class,
ParsedAttributionImpl::class) {
- override val defaultImpl = ParsedAttributionImpl("", 0, emptyList())
+ override val defaultImpl =
+ ParsedAttributionImpl(
+ "",
+ 0,
+ emptyList()
+ )
override val creator = ParsedAttributionImpl.CREATOR
override val baseParams = listOf(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
index e978dd3..058f6d6 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedComponentTest.kt
@@ -17,10 +17,9 @@
package com.android.server.pm.test.parsing.parcelling
import android.content.pm.PackageManager
-import android.content.pm.parsing.component.ParsedComponent
-import android.content.pm.parsing.component.ParsedComponentImpl
-import android.content.pm.parsing.component.ParsedIntentInfo
-import android.content.pm.parsing.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedComponent
+import com.android.server.pm.pkg.component.ParsedComponentImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Bundle
import android.os.Parcelable
import kotlin.contracts.ExperimentalContracts
@@ -65,7 +64,8 @@
ParsedComponentImpl::addIntent,
"TestLabel",
transformGet = { it.singleOrNull()?.nonLocalizedLabel },
- transformSet = { ParsedIntentInfoImpl().setNonLocalizedLabel(it!!) },
+ transformSet = { ParsedIntentInfoImpl()
+ .setNonLocalizedLabel(it!!) },
),
getSetByValue(
ParsedComponent::getProperties,
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
index f15b911..eeb30b7 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedInstrumentationTest.kt
@@ -16,8 +16,8 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedInstrumentation
-import android.content.pm.parsing.component.ParsedInstrumentationImpl
+import com.android.server.pm.pkg.component.ParsedInstrumentation
+import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
@@ -26,7 +26,8 @@
ParsedInstrumentationImpl::class
) {
- override val defaultImpl = ParsedInstrumentationImpl()
+ override val defaultImpl =
+ ParsedInstrumentationImpl()
override val creator = ParsedInstrumentationImpl.CREATOR
override val subclassBaseParams = listOf(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
index f04e851..f27a51f 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedIntentInfoTest.kt
@@ -16,8 +16,8 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedIntentInfo
-import android.content.pm.parsing.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfo
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Parcelable
import android.os.PatternMatcher
import kotlin.contracts.ExperimentalContracts
@@ -28,7 +28,8 @@
ParsedIntentInfoImpl::class,
) {
- override val defaultImpl = ParsedIntentInfoImpl()
+ override val defaultImpl =
+ ParsedIntentInfoImpl()
override val creator = ParsedIntentInfoImpl.CREATOR
override val excludedMethods = listOf(
@@ -43,7 +44,8 @@
ParsedIntentInfo::getNonLocalizedLabel,
)
- override fun initialObject() = ParsedIntentInfoImpl().apply {
+ override fun initialObject() = ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
addAction("test.ACTION")
addDataAuthority("testAuthority", "404")
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
index 214734a..a0d8c44 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedMainComponentTest.kt
@@ -16,9 +16,8 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedMainComponent
-import android.content.pm.parsing.component.ParsedMainComponentImpl
-import android.content.pm.parsing.component.ParsedService
+import com.android.server.pm.pkg.component.ParsedMainComponent
+import com.android.server.pm.pkg.component.ParsedMainComponentImpl
import android.os.Parcelable
import java.util.Arrays
import kotlin.contracts.ExperimentalContracts
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
index f876ed0..57562ef 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionGroupTest.kt
@@ -16,8 +16,8 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedPermissionGroup
-import android.content.pm.parsing.component.ParsedPermissionGroupImpl
+import com.android.server.pm.pkg.component.ParsedPermissionGroup
+import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
@@ -26,7 +26,8 @@
ParsedPermissionGroupImpl::class,
) {
- override val defaultImpl = ParsedPermissionGroupImpl()
+ override val defaultImpl =
+ ParsedPermissionGroupImpl()
override val creator = ParsedPermissionGroupImpl.CREATOR
override val subclassBaseParams = listOf(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
index 6f48e24..c72a44e 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedPermissionTest.kt
@@ -16,10 +16,10 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedPermission
-import android.content.pm.parsing.component.ParsedPermissionGroup
-import android.content.pm.parsing.component.ParsedPermissionGroupImpl
-import android.content.pm.parsing.component.ParsedPermissionImpl
+import com.android.server.pm.pkg.component.ParsedPermission
+import com.android.server.pm.pkg.component.ParsedPermissionGroup
+import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.server.pm.pkg.component.ParsedPermissionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
@@ -28,7 +28,8 @@
ParsedPermissionImpl::class
) {
- override val defaultImpl = ParsedPermissionImpl()
+ override val defaultImpl =
+ ParsedPermissionImpl()
override val creator = ParsedPermissionImpl.CREATOR
override val subclassExcludedMethods = listOf(
@@ -53,7 +54,8 @@
getSetByValue(
ParsedPermission::getParsedPermissionGroup,
ParsedPermissionImpl::setParsedPermissionGroup,
- ParsedPermissionGroupImpl().apply { name = "test.permission.group" },
+ ParsedPermissionGroupImpl()
+ .apply { name = "test.permission.group" },
compare = { first, second -> equalBy(first, second, ParsedPermissionGroup::getName) }
),
)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
index 005d3e8..8b9361a 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProcessTest.kt
@@ -16,15 +16,16 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedProcess
-import android.content.pm.parsing.component.ParsedProcessImpl
+import com.android.server.pm.pkg.component.ParsedProcess
+import com.android.server.pm.pkg.component.ParsedProcessImpl
import android.util.ArrayMap
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
class ParsedProcessTest : ParcelableComponentTest(ParsedProcess::class, ParsedProcessImpl::class) {
- override val defaultImpl = ParsedProcessImpl()
+ override val defaultImpl =
+ ParsedProcessImpl()
override val creator = ParsedProcessImpl.CREATOR
override val excludedMethods = listOf(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
index 78e4b79..037da24 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedProviderTest.kt
@@ -17,15 +17,16 @@
package com.android.server.pm.test.parsing.parcelling
import android.content.pm.PathPermission
-import android.content.pm.parsing.component.ParsedProvider
-import android.content.pm.parsing.component.ParsedProviderImpl
+import com.android.server.pm.pkg.component.ParsedProvider
+import com.android.server.pm.pkg.component.ParsedProviderImpl
import android.os.PatternMatcher
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
class ParsedProviderTest : ParsedMainComponentTest(ParsedProvider::class, ParsedProviderImpl::class) {
- override val defaultImpl = ParsedProviderImpl()
+ override val defaultImpl =
+ ParsedProviderImpl()
override val creator = ParsedProviderImpl.CREATOR
override val mainComponentSubclassBaseParams = listOf(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
index 9363aa3..e2c9439 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedServiceTest.kt
@@ -16,14 +16,15 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedService
-import android.content.pm.parsing.component.ParsedServiceImpl
+import com.android.server.pm.pkg.component.ParsedService
+import com.android.server.pm.pkg.component.ParsedServiceImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
class ParsedServiceTest : ParsedMainComponentTest(ParsedService::class, ParsedServiceImpl::class) {
- override val defaultImpl = ParsedServiceImpl()
+ override val defaultImpl =
+ ParsedServiceImpl()
override val creator = ParsedServiceImpl.CREATOR
override val mainComponentSubclassBaseParams = listOf(
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
index 81e800f..ad60736 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedUsesPermissionTest.kt
@@ -16,8 +16,8 @@
package com.android.server.pm.test.parsing.parcelling
-import android.content.pm.parsing.component.ParsedUsesPermission
-import android.content.pm.parsing.component.ParsedUsesPermissionImpl
+import com.android.server.pm.pkg.component.ParsedUsesPermission
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
import kotlin.contracts.ExperimentalContracts
@ExperimentalContracts
@@ -26,7 +26,8 @@
ParsedUsesPermissionImpl::class
) {
- override val defaultImpl = ParsedUsesPermissionImpl("", 0)
+ override val defaultImpl =
+ ParsedUsesPermissionImpl("", 0)
override val creator = ParsedUsesPermissionImpl.CREATOR
override val baseParams = listOf(
@@ -34,5 +35,6 @@
ParsedUsesPermission::getUsesPermissionFlags
)
- override fun initialObject() = ParsedUsesPermissionImpl("", 0)
+ override fun initialObject() =
+ ParsedUsesPermissionImpl("", 0)
}
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
index 33234d5..652dc38 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationCollectorTest.kt
@@ -18,8 +18,8 @@
import android.content.Intent
import android.content.pm.ApplicationInfo
-import android.content.pm.parsing.component.ParsedActivityImpl
-import android.content.pm.parsing.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import android.os.Build
import android.os.PatternMatcher
import android.util.ArraySet
@@ -94,7 +94,8 @@
val activityList = listOf(
ParsedActivityImpl().apply {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
addAction(Intent.ACTION_VIEW)
addCategory(Intent.CATEGORY_BROWSABLE)
@@ -110,7 +111,8 @@
},
ParsedActivityImpl().apply {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(true)
addAction(Intent.ACTION_VIEW)
@@ -270,7 +272,8 @@
val activityList = listOf(
ParsedActivityImpl().apply {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(autoVerify)
addAction(Intent.ACTION_VIEW)
@@ -285,7 +288,8 @@
}
)
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
addAction(Intent.ACTION_VIEW)
addCategory(Intent.CATEGORY_BROWSABLE)
@@ -300,7 +304,8 @@
},
ParsedActivityImpl().apply {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(autoVerify)
addAction(Intent.ACTION_VIEW)
@@ -316,7 +321,8 @@
},
ParsedActivityImpl().apply {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(autoVerify)
addAction(Intent.ACTION_VIEW)
@@ -329,7 +335,8 @@
}
)
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(autoVerify)
addAction(Intent.ACTION_VIEW)
@@ -342,7 +349,8 @@
}
)
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(autoVerify)
addCategory(Intent.CATEGORY_BROWSABLE)
@@ -355,7 +363,8 @@
}
)
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(autoVerify)
addCategory(Intent.CATEGORY_BROWSABLE)
@@ -365,7 +374,8 @@
}
)
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(autoVerify)
addCategory(Intent.CATEGORY_BROWSABLE)
@@ -375,7 +385,8 @@
}
)
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
setAutoVerify(autoVerify)
addCategory(Intent.CATEGORY_BROWSABLE)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 089e9db..92cdb34 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -20,8 +20,8 @@
import android.content.Intent
import android.content.pm.PackageManager
import android.content.pm.SigningDetails
-import android.content.pm.parsing.component.ParsedActivityImpl
-import android.content.pm.parsing.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import android.content.pm.verify.domain.DomainVerificationManager
import android.content.pm.verify.domain.DomainVerificationState
import android.os.Build
@@ -308,7 +308,8 @@
listOf(
ParsedActivityImpl().apply {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
autoVerify = true
addAction(Intent.ACTION_VIEW)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
index 334f503..878bee0 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationManagerApiTest.kt
@@ -19,8 +19,8 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.pm.parsing.component.ParsedActivityImpl
-import android.content.pm.parsing.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageUserStateInternal
import android.content.pm.verify.domain.DomainOwner
import android.content.pm.verify.domain.DomainVerificationInfo
@@ -526,7 +526,8 @@
ParsedActivityImpl().apply {
domains.forEach {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
autoVerify = true
addAction(Intent.ACTION_VIEW)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
index fb581d7..0369bab 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationPackageTest.kt
@@ -20,8 +20,8 @@
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.content.pm.SigningDetails
-import android.content.pm.parsing.component.ParsedActivityImpl
-import android.content.pm.parsing.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageUserStateInternal
import android.content.pm.verify.domain.DomainOwner
import android.content.pm.verify.domain.DomainVerificationInfo.STATE_MODIFIABLE_VERIFIED
@@ -867,7 +867,8 @@
whenever(targetSdkVersion) { Build.VERSION_CODES.S }
whenever(isEnabled) { true }
- fun baseIntent(domain: String) = ParsedIntentInfoImpl().apply {
+ fun baseIntent(domain: String) = ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
addAction(Intent.ACTION_VIEW)
addCategory(Intent.CATEGORY_BROWSABLE)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
index a397d56..3a602a8 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationSettingsMutationTest.kt
@@ -19,8 +19,8 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.pm.parsing.component.ParsedActivityImpl
-import android.content.pm.parsing.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import com.android.server.pm.pkg.PackageUserStateInternal
import android.content.pm.verify.domain.DomainVerificationState
import android.os.Build
@@ -196,7 +196,8 @@
listOf(
ParsedActivityImpl().apply {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
autoVerify = true
addAction(Intent.ACTION_VIEW)
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
index 728da49..ffc2877 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationUserSelectionOverrideTest.kt
@@ -18,8 +18,8 @@
import android.content.Intent
import android.content.pm.PackageManager
-import android.content.pm.parsing.component.ParsedActivityImpl
-import android.content.pm.parsing.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
import android.content.pm.verify.domain.DomainVerificationManager
import android.content.pm.verify.domain.DomainVerificationState
import android.content.pm.verify.domain.DomainVerificationUserState
@@ -112,7 +112,8 @@
val activityList = listOf(
ParsedActivityImpl().apply {
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
autoVerify = true
addAction(Intent.ACTION_VIEW)
@@ -126,7 +127,8 @@
}
)
addIntent(
- ParsedIntentInfoImpl().apply {
+ ParsedIntentInfoImpl()
+ .apply {
intentFilter.apply {
autoVerify = true
addAction(Intent.ACTION_VIEW)
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/mockingservicestests/OWNERS b/services/tests/mockingservicestests/OWNERS
index 0fb0c30..2bb1649 100644
--- a/services/tests/mockingservicestests/OWNERS
+++ b/services/tests/mockingservicestests/OWNERS
@@ -1 +1,5 @@
include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
+per-file FakeGameClassifier.java = file:/GAME_MANAGER_OWNERS
+per-file FakeGameServiceProviderInstance = file:/GAME_MANAGER_OWNERS
+per-file FakeServiceConnector.java = file:/GAME_MANAGER_OWNERS
+per-file Game* = file:/GAME_MANAGER_OWNERS
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index 04a6eee..c2e0a04 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -27,8 +27,6 @@
import android.content.pm.Signature
import android.content.pm.SigningDetails
import android.content.pm.UserInfo
-import android.content.pm.parsing.ParsingPackage
-import android.content.pm.parsing.ParsingPackageUtils
import android.content.pm.parsing.result.ParseTypeImpl
import android.content.res.Resources
import android.hardware.display.DisplayManager
@@ -68,6 +66,8 @@
import com.android.server.pm.parsing.pkg.PackageImpl
import com.android.server.pm.parsing.pkg.ParsedPackage
import com.android.server.pm.permission.PermissionManagerServiceInternal
+import com.android.server.pm.pkg.parsing.ParsingPackage
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import com.android.server.pm.verify.domain.DomainVerificationManagerInternal
import com.android.server.testutils.TestHandler
import com.android.server.testutils.mock
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index c3a364e..f24059c 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",
@@ -181,18 +182,41 @@
java_genrule {
name: "FrameworksServicesTests_apks_as_resources",
srcs: [
- ":FrameworksCoreTests_install_complete_package_info",
+ ":FrameworksServicesTests_install",
+ ":FrameworksServicesTests_install_bad_dex",
+ ":FrameworksServicesTests_install_complete_package_info",
+ ":FrameworksServicesTests_install_decl_perm",
":FrameworksServicesTests_install_intent_filters",
+ ":FrameworksServicesTests_install_loc_auto",
+ ":FrameworksServicesTests_install_loc_internal",
+ ":FrameworksServicesTests_install_loc_sdcard",
+ ":FrameworksServicesTests_install_loc_unspecified",
":FrameworksServicesTests_install_split_base",
":FrameworksServicesTests_install_split_feature_a",
+ ":FrameworksServicesTests_install_use_perm_good",
+ ":FrameworksServicesTests_install_uses_feature",
":FrameworksServicesTests_install_uses_sdk_0",
":FrameworksServicesTests_install_uses_sdk_q0",
":FrameworksServicesTests_install_uses_sdk_q0_r0",
- ":FrameworksServicesTests_install_uses_sdk_r_none",
":FrameworksServicesTests_install_uses_sdk_r0",
":FrameworksServicesTests_install_uses_sdk_r5",
+ ":FrameworksServicesTests_install_uses_sdk_r_none",
":FrameworksServicesTests_install_uses_sdk_r0_s0",
":FrameworksServicesTests_install_uses_sdk_r0_s5",
+ ":FrameworksServicesTests_keyset_permdef_sa_unone",
+ ":FrameworksServicesTests_keyset_permuse_sa_ua_ub",
+ ":FrameworksServicesTests_keyset_permuse_sb_ua_ub",
+ ":FrameworksServicesTests_keyset_sa_ua",
+ ":FrameworksServicesTests_keyset_sa_ua_ub",
+ ":FrameworksServicesTests_keyset_sa_uab",
+ ":FrameworksServicesTests_keyset_sa_ub",
+ ":FrameworksServicesTests_keyset_sa_unone",
+ ":FrameworksServicesTests_keyset_sab_ua",
+ ":FrameworksServicesTests_keyset_sau_ub",
+ ":FrameworksServicesTests_keyset_sb_ua",
+ ":FrameworksServicesTests_keyset_sb_ub",
+ ":FrameworksServicesTests_keyset_splat_api",
+ ":FrameworksServicesTests_keyset_splata_api",
],
out: ["FrameworkServicesTests_apks_as_resources.res.zip"],
tools: ["soong_zip"],
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 587447a..d9f73d9 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -99,6 +99,8 @@
<uses-permission
android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"/>
+ <uses-permission android:name="android.permission.PACKAGE_VERIFICATION_AGENT" />
+
<queries>
<package android:name="com.android.servicestests.apps.suspendtestapp" />
</queries>
@@ -269,4 +271,11 @@
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.frameworks.servicestests"
android:label="Frameworks Services Tests"/>
+ <key-sets>
+ <key-set android:name="A" >
+ <public-key android:name="keyA"
+ android:value="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsMpNthdOxud7roPDZMMomOqXgJJdRfIWpkKEqmC61Mv+Nf6QY3TorEwJeghjSmqj7IbBKrtvfQq4E2XJO1HuspmQO4Ng2gvn+r+6EwNfKc9k55d6s+27SR867jKurBbHNtZMG+tjL1yH4r+tNzcuJCsgyAFqLmxFdcxEwzNvREyRpoYc5RDR0mmTwkMCUhJ6CId1EYEKiCEdNzxv+fWPEb21u+/MWpleGCILs8kglRVb2q/WOzAAvGr4FY5plfaE6N+lr7+UschQ+aMi1+uqewo2o0qPFVmZP5hnwj55K4UMzu/NhhDqQQsX4cSGES1KgHo5MTqRqZjN/I7emw5pFQIDAQAB"/>
+ </key-set>
+ <upgrade-key-set android:name="A"/>
+ </key-sets>
</manifest>
diff --git a/services/tests/servicestests/OWNERS b/services/tests/servicestests/OWNERS
index 0fb0c30..d07848e 100644
--- a/services/tests/servicestests/OWNERS
+++ b/services/tests/servicestests/OWNERS
@@ -1 +1,2 @@
include platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
+per-file GameManagerServiceSettingsTests.java = file:/GAME_MANAGER_OWNERS
diff --git a/core/tests/coretests/apks/install/Android.bp b/services/tests/servicestests/apks/install/Android.bp
similarity index 79%
rename from core/tests/coretests/apks/install/Android.bp
rename to services/tests/servicestests/apks/install/Android.bp
index 652b491..12175fd 100644
--- a/core/tests/coretests/apks/install/Android.bp
+++ b/services/tests/servicestests/apks/install/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install/AndroidManifest.xml b/services/tests/servicestests/apks/install/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install/AndroidManifest.xml
rename to services/tests/servicestests/apks/install/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install/res/values/strings.xml b/services/tests/servicestests/apks/install/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install/res/values/strings.xml
rename to services/tests/servicestests/apks/install/res/values/strings.xml
diff --git a/core/tests/coretests/apks/install_bad_dex/Android.bp b/services/tests/servicestests/apks/install_bad_dex/Android.bp
similarity index 68%
rename from core/tests/coretests/apks/install_bad_dex/Android.bp
rename to services/tests/servicestests/apks/install_bad_dex/Android.bp
index 7b96c9b4..ad75668 100644
--- a/core/tests/coretests/apks/install_bad_dex/Android.bp
+++ b/services/tests/servicestests/apks/install_bad_dex/Android.bp
@@ -8,25 +8,25 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_bad_dex_",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_bad_dex_",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["src/**/*.java"],
}
// Inject bad classes.dex file.
java_genrule {
- name: "FrameworksCoreTests_install_bad_dex",
+ name: "FrameworksServicesTests_install_bad_dex",
tools: [
"soong_zip",
"merge_zips",
],
srcs: [
- ":FrameworksCoreTests_install_bad_dex_",
+ ":FrameworksServicesTests_install_bad_dex_",
"classes.dex",
],
- out: ["FrameworksCoreTests_install_bad_dex.apk"],
+ out: ["FrameworksServicesTests_install_bad_dex.apk"],
cmd: "$(location soong_zip) -o $(genDir)/classes.dex.zip -j -f $(location classes.dex) && " +
"$(location merge_zips) -ignore-duplicates $(out) $(genDir)/classes.dex.zip " +
- "$(location :FrameworksCoreTests_install_bad_dex_)",
+ "$(location :FrameworksServicesTests_install_bad_dex_)",
}
diff --git a/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml b/services/tests/servicestests/apks/install_bad_dex/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_bad_dex/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_bad_dex/classes.dex b/services/tests/servicestests/apks/install_bad_dex/classes.dex
similarity index 100%
rename from core/tests/coretests/apks/install_bad_dex/classes.dex
rename to services/tests/servicestests/apks/install_bad_dex/classes.dex
diff --git a/core/tests/coretests/apks/install_bad_dex/res/values/strings.xml b/services/tests/servicestests/apks/install_bad_dex/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_bad_dex/res/values/strings.xml
rename to services/tests/servicestests/apks/install_bad_dex/res/values/strings.xml
diff --git a/core/tests/coretests/apks/install_bad_dex/src/com/android/frameworks/coretests/TestActivity.java b/services/tests/servicestests/apks/install_bad_dex/src/com/android/frameworks/coretests/TestActivity.java
similarity index 100%
rename from core/tests/coretests/apks/install_bad_dex/src/com/android/frameworks/coretests/TestActivity.java
rename to services/tests/servicestests/apks/install_bad_dex/src/com/android/frameworks/coretests/TestActivity.java
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/services/tests/servicestests/apks/install_complete_package_info/Android.bp
similarity index 75%
copy from core/tests/coretests/apks/install_loc_unspecified/Android.bp
copy to services/tests/servicestests/apks/install_complete_package_info/Android.bp
index 76869e9..98aa750 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.bp
+++ b/services/tests/servicestests/apks/install_complete_package_info/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_loc_unspecified",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_complete_package_info",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install_complete_package_info/AndroidManifest.xml b/services/tests/servicestests/apks/install_complete_package_info/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_complete_package_info/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_complete_package_info/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestActivity.java b/services/tests/servicestests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestActivity.java
similarity index 100%
rename from core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestActivity.java
rename to services/tests/servicestests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestActivity.java
diff --git a/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestProvider.java b/services/tests/servicestests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestProvider.java
similarity index 100%
rename from core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestProvider.java
rename to services/tests/servicestests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestProvider.java
diff --git a/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestReceiver.java b/services/tests/servicestests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestReceiver.java
similarity index 100%
rename from core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestReceiver.java
rename to services/tests/servicestests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestReceiver.java
diff --git a/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestService.java b/services/tests/servicestests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestService.java
similarity index 100%
rename from core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestService.java
rename to services/tests/servicestests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestService.java
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/services/tests/servicestests/apks/install_decl_perm/Android.bp
similarity index 77%
copy from core/tests/coretests/apks/install_loc_unspecified/Android.bp
copy to services/tests/servicestests/apks/install_decl_perm/Android.bp
index 76869e9..ef65f5d 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.bp
+++ b/services/tests/servicestests/apks/install_decl_perm/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_loc_unspecified",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_decl_perm",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install_decl_perm/AndroidManifest.xml b/services/tests/servicestests/apks/install_decl_perm/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_decl_perm/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_decl_perm/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_decl_perm/res/values/strings.xml b/services/tests/servicestests/apks/install_decl_perm/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_decl_perm/res/values/strings.xml
rename to services/tests/servicestests/apks/install_decl_perm/res/values/strings.xml
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/services/tests/servicestests/apks/install_loc_auto/Android.bp
similarity index 77%
copy from core/tests/coretests/apks/install_loc_unspecified/Android.bp
copy to services/tests/servicestests/apks/install_loc_auto/Android.bp
index 76869e9..4e4ae52 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.bp
+++ b/services/tests/servicestests/apks/install_loc_auto/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_loc_unspecified",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_loc_auto",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install_loc_auto/AndroidManifest.xml b/services/tests/servicestests/apks/install_loc_auto/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_loc_auto/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_loc_auto/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_loc_auto/res/values/strings.xml b/services/tests/servicestests/apks/install_loc_auto/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_loc_auto/res/values/strings.xml
rename to services/tests/servicestests/apks/install_loc_auto/res/values/strings.xml
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/services/tests/servicestests/apks/install_loc_internal/Android.bp
similarity index 77%
copy from core/tests/coretests/apks/install_loc_unspecified/Android.bp
copy to services/tests/servicestests/apks/install_loc_internal/Android.bp
index 76869e9..39cdd51 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.bp
+++ b/services/tests/servicestests/apks/install_loc_internal/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_loc_unspecified",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_loc_internal",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install_loc_internal/AndroidManifest.xml b/services/tests/servicestests/apks/install_loc_internal/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_loc_internal/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_loc_internal/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_loc_internal/res/values/strings.xml b/services/tests/servicestests/apks/install_loc_internal/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_loc_internal/res/values/strings.xml
rename to services/tests/servicestests/apks/install_loc_internal/res/values/strings.xml
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/services/tests/servicestests/apks/install_loc_sdcard/Android.bp
similarity index 77%
copy from core/tests/coretests/apks/install_loc_unspecified/Android.bp
copy to services/tests/servicestests/apks/install_loc_sdcard/Android.bp
index 76869e9..ed82793 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.bp
+++ b/services/tests/servicestests/apks/install_loc_sdcard/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_loc_unspecified",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_loc_sdcard",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install_loc_sdcard/AndroidManifest.xml b/services/tests/servicestests/apks/install_loc_sdcard/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_loc_sdcard/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_loc_sdcard/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml b/services/tests/servicestests/apks/install_loc_sdcard/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_loc_sdcard/res/values/strings.xml
rename to services/tests/servicestests/apks/install_loc_sdcard/res/values/strings.xml
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/services/tests/servicestests/apks/install_loc_unspecified/Android.bp
similarity index 76%
copy from core/tests/coretests/apks/install_loc_unspecified/Android.bp
copy to services/tests/servicestests/apks/install_loc_unspecified/Android.bp
index 76869e9..fd15cb8 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.bp
+++ b/services/tests/servicestests/apks/install_loc_unspecified/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_loc_unspecified",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_loc_unspecified",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install_loc_unspecified/AndroidManifest.xml b/services/tests/servicestests/apks/install_loc_unspecified/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_loc_unspecified/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_loc_unspecified/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml b/services/tests/servicestests/apks/install_loc_unspecified/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_loc_unspecified/res/values/strings.xml
rename to services/tests/servicestests/apks/install_loc_unspecified/res/values/strings.xml
diff --git a/core/tests/coretests/apks/install_use_perm_good/Android.bp b/services/tests/servicestests/apks/install_use_perm_good/Android.bp
similarity index 77%
rename from core/tests/coretests/apks/install_use_perm_good/Android.bp
rename to services/tests/servicestests/apks/install_use_perm_good/Android.bp
index 89700dd..959ffbc 100644
--- a/core/tests/coretests/apks/install_use_perm_good/Android.bp
+++ b/services/tests/servicestests/apks/install_use_perm_good/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_use_perm_good",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_use_perm_good",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install_use_perm_good/AndroidManifest.xml b/services/tests/servicestests/apks/install_use_perm_good/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_use_perm_good/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_use_perm_good/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml b/services/tests/servicestests/apks/install_use_perm_good/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_use_perm_good/res/values/strings.xml
rename to services/tests/servicestests/apks/install_use_perm_good/res/values/strings.xml
diff --git a/core/tests/coretests/apks/install_loc_unspecified/Android.bp b/services/tests/servicestests/apks/install_uses_feature/Android.bp
similarity index 77%
rename from core/tests/coretests/apks/install_loc_unspecified/Android.bp
rename to services/tests/servicestests/apks/install_uses_feature/Android.bp
index 76869e9..fa25af4 100644
--- a/core/tests/coretests/apks/install_loc_unspecified/Android.bp
+++ b/services/tests/servicestests/apks/install_uses_feature/Android.bp
@@ -8,8 +8,8 @@
}
android_test_helper_app {
- name: "FrameworksCoreTests_install_loc_unspecified",
- defaults: ["FrameworksCoreTests_apks_defaults"],
+ name: "FrameworksServicesTests_install_uses_feature",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
srcs: ["**/*.java"],
}
diff --git a/core/tests/coretests/apks/install_uses_feature/AndroidManifest.xml b/services/tests/servicestests/apks/install_uses_feature/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/install_uses_feature/AndroidManifest.xml
rename to services/tests/servicestests/apks/install_uses_feature/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/install_uses_feature/res/values/strings.xml b/services/tests/servicestests/apks/install_uses_feature/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/install_uses_feature/res/values/strings.xml
rename to services/tests/servicestests/apks/install_uses_feature/res/values/strings.xml
diff --git a/services/tests/servicestests/apks/keyset/Android.bp b/services/tests/servicestests/apks/keyset/Android.bp
new file mode 100644
index 0000000..ce7919c
--- /dev/null
+++ b/services/tests/servicestests/apks/keyset/Android.bp
@@ -0,0 +1,129 @@
+//apks signed by keyset_A
+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_helper_app {
+ name: "FrameworksServicesTests_keyset_sa_unone",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ manifest: "uNone/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_sa_ua",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ manifest: "uA/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_sa_ub",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ manifest: "uB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_sa_uab",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ manifest: "uAB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_sa_ua_ub",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ manifest: "uAuB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_permdef_sa_unone",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ manifest: "permDef/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_permuse_sa_ua_ub",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ manifest: "permUse/AndroidManifest.xml",
+}
+
+//apks signed by keyset_B
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_sb_ua",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_B_cert",
+ manifest: "uA/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_sb_ub",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_B_cert",
+ manifest: "uB/AndroidManifest.xml",
+}
+
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_permuse_sb_ua_ub",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_B_cert",
+ manifest: "permUse/AndroidManifest.xml",
+}
+
+//apks signed by keyset_A and keyset_B
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_sab_ua",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ additional_certificates: [":FrameworksServicesTests_keyset_B_cert"],
+ manifest: "uA/AndroidManifest.xml",
+}
+
+//apks signed by keyset_A and unit_test
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_sau_ub",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: ":FrameworksServicesTests_keyset_A_cert",
+ additional_certificates: [":FrameworksServicesTests_keyset_B_cert"],
+ manifest: "uB/AndroidManifest.xml",
+}
+
+//apks signed by platform only
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_splat_api",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: "platform",
+ manifest: "api_test/AndroidManifest.xml",
+}
+
+//apks signed by platform and keyset_A
+android_test_helper_app {
+ name: "FrameworksServicesTests_keyset_splata_api",
+ defaults: ["FrameworksServicesTests_apks_defaults"],
+ srcs: ["**/*.java"],
+ certificate: "platform",
+ additional_certificates: [":FrameworksServicesTests_keyset_A_cert"],
+ manifest: "api_test/AndroidManifest.xml",
+}
diff --git a/core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml b/services/tests/servicestests/apks/keyset/api_test/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/api_test/AndroidManifest.xml
rename to services/tests/servicestests/apks/keyset/api_test/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/keyset/permDef/AndroidManifest.xml b/services/tests/servicestests/apks/keyset/permDef/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/permDef/AndroidManifest.xml
rename to services/tests/servicestests/apks/keyset/permDef/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/keyset/permUse/AndroidManifest.xml b/services/tests/servicestests/apks/keyset/permUse/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/permUse/AndroidManifest.xml
rename to services/tests/servicestests/apks/keyset/permUse/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/keyset/res/values/strings.xml b/services/tests/servicestests/apks/keyset/res/values/strings.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/res/values/strings.xml
rename to services/tests/servicestests/apks/keyset/res/values/strings.xml
diff --git a/core/tests/coretests/apks/keyset/uA/AndroidManifest.xml b/services/tests/servicestests/apks/keyset/uA/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/uA/AndroidManifest.xml
rename to services/tests/servicestests/apks/keyset/uA/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/keyset/uAB/AndroidManifest.xml b/services/tests/servicestests/apks/keyset/uAB/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/uAB/AndroidManifest.xml
rename to services/tests/servicestests/apks/keyset/uAB/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/keyset/uAuB/AndroidManifest.xml b/services/tests/servicestests/apks/keyset/uAuB/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/uAuB/AndroidManifest.xml
rename to services/tests/servicestests/apks/keyset/uAuB/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/keyset/uB/AndroidManifest.xml b/services/tests/servicestests/apks/keyset/uB/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/uB/AndroidManifest.xml
rename to services/tests/servicestests/apks/keyset/uB/AndroidManifest.xml
diff --git a/core/tests/coretests/apks/keyset/uNone/AndroidManifest.xml b/services/tests/servicestests/apks/keyset/uNone/AndroidManifest.xml
similarity index 100%
rename from core/tests/coretests/apks/keyset/uNone/AndroidManifest.xml
rename to services/tests/servicestests/apks/keyset/uNone/AndroidManifest.xml
diff --git a/services/tests/servicestests/certs/Android.bp b/services/tests/servicestests/certs/Android.bp
new file mode 100644
index 0000000..61367c0
--- /dev/null
+++ b/services/tests/servicestests/certs/Android.bp
@@ -0,0 +1,20 @@
+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
+ // SPDX-license-identifier-MIT
+ // SPDX-license-identifier-Unicode-DFS
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_app_certificate {
+ name: "FrameworksServicesTests_keyset_A_cert",
+ certificate: "keyset_A",
+}
+
+android_app_certificate {
+ name: "FrameworksServicesTests_keyset_B_cert",
+ certificate: "keyset_B",
+}
diff --git a/services/tests/servicestests/certs/README b/services/tests/servicestests/certs/README
new file mode 100644
index 0000000..00917a1
--- /dev/null
+++ b/services/tests/servicestests/certs/README
@@ -0,0 +1,4 @@
+Generate with:
+
+development/tools/make_key unit_test '/CN=unit_test'
+development/tools/make_key unit_test_diff '/CN=unit_test_diff'
diff --git a/core/tests/coretests/certs/keyset_A.pk8 b/services/tests/servicestests/certs/keyset_A.pk8
similarity index 100%
rename from core/tests/coretests/certs/keyset_A.pk8
rename to services/tests/servicestests/certs/keyset_A.pk8
Binary files differ
diff --git a/core/tests/coretests/certs/keyset_A.x509.pem b/services/tests/servicestests/certs/keyset_A.x509.pem
similarity index 100%
rename from core/tests/coretests/certs/keyset_A.x509.pem
rename to services/tests/servicestests/certs/keyset_A.x509.pem
diff --git a/core/tests/coretests/certs/keyset_B.pk8 b/services/tests/servicestests/certs/keyset_B.pk8
similarity index 100%
rename from core/tests/coretests/certs/keyset_B.pk8
rename to services/tests/servicestests/certs/keyset_B.pk8
Binary files differ
diff --git a/core/tests/coretests/certs/keyset_B.x509.pem b/services/tests/servicestests/certs/keyset_B.x509.pem
similarity index 100%
rename from core/tests/coretests/certs/keyset_B.x509.pem
rename to services/tests/servicestests/certs/keyset_B.x509.pem
diff --git a/core/tests/coretests/res/raw/install_app1_cert1 b/services/tests/servicestests/res/raw/install_app1_cert1
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_cert1
rename to services/tests/servicestests/res/raw/install_app1_cert1
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert1_cert2 b/services/tests/servicestests/res/raw/install_app1_cert1_cert2
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_cert1_cert2
rename to services/tests/servicestests/res/raw/install_app1_cert1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert2 b/services/tests/servicestests/res/raw/install_app1_cert2
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_cert2
rename to services/tests/servicestests/res/raw/install_app1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert3 b/services/tests/servicestests/res/raw/install_app1_cert3
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_cert3
rename to services/tests/servicestests/res/raw/install_app1_cert3
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert3_cert4 b/services/tests/servicestests/res/raw/install_app1_cert3_cert4
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_cert3_cert4
rename to services/tests/servicestests/res/raw/install_app1_cert3_cert4
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert5 b/services/tests/servicestests/res/raw/install_app1_cert5
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_cert5
rename to services/tests/servicestests/res/raw/install_app1_cert5
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert5_rotated_cert6 b/services/tests/servicestests/res/raw/install_app1_cert5_rotated_cert6
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_cert5_rotated_cert6
rename to services/tests/servicestests/res/raw/install_app1_cert5_rotated_cert6
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_cert6 b/services/tests/servicestests/res/raw/install_app1_cert6
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_cert6
rename to services/tests/servicestests/res/raw/install_app1_cert6
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app1_unsigned b/services/tests/servicestests/res/raw/install_app1_unsigned
similarity index 100%
rename from core/tests/coretests/res/raw/install_app1_unsigned
rename to services/tests/servicestests/res/raw/install_app1_unsigned
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert1 b/services/tests/servicestests/res/raw/install_app2_cert1
similarity index 100%
rename from core/tests/coretests/res/raw/install_app2_cert1
rename to services/tests/servicestests/res/raw/install_app2_cert1
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert1_cert2 b/services/tests/servicestests/res/raw/install_app2_cert1_cert2
similarity index 100%
rename from core/tests/coretests/res/raw/install_app2_cert1_cert2
rename to services/tests/servicestests/res/raw/install_app2_cert1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert2 b/services/tests/servicestests/res/raw/install_app2_cert2
similarity index 100%
rename from core/tests/coretests/res/raw/install_app2_cert2
rename to services/tests/servicestests/res/raw/install_app2_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert3 b/services/tests/servicestests/res/raw/install_app2_cert3
similarity index 100%
rename from core/tests/coretests/res/raw/install_app2_cert3
rename to services/tests/servicestests/res/raw/install_app2_cert3
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_cert5_rotated_cert6 b/services/tests/servicestests/res/raw/install_app2_cert5_rotated_cert6
similarity index 100%
rename from core/tests/coretests/res/raw/install_app2_cert5_rotated_cert6
rename to services/tests/servicestests/res/raw/install_app2_cert5_rotated_cert6
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_app2_unsigned b/services/tests/servicestests/res/raw/install_app2_unsigned
similarity index 100%
rename from core/tests/coretests/res/raw/install_app2_unsigned
rename to services/tests/servicestests/res/raw/install_app2_unsigned
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_cert1 b/services/tests/servicestests/res/raw/install_shared1_cert1
similarity index 100%
rename from core/tests/coretests/res/raw/install_shared1_cert1
rename to services/tests/servicestests/res/raw/install_shared1_cert1
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_cert1_cert2 b/services/tests/servicestests/res/raw/install_shared1_cert1_cert2
similarity index 100%
rename from core/tests/coretests/res/raw/install_shared1_cert1_cert2
rename to services/tests/servicestests/res/raw/install_shared1_cert1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_cert2 b/services/tests/servicestests/res/raw/install_shared1_cert2
similarity index 100%
rename from core/tests/coretests/res/raw/install_shared1_cert2
rename to services/tests/servicestests/res/raw/install_shared1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared1_unsigned b/services/tests/servicestests/res/raw/install_shared1_unsigned
similarity index 100%
rename from core/tests/coretests/res/raw/install_shared1_unsigned
rename to services/tests/servicestests/res/raw/install_shared1_unsigned
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_cert1 b/services/tests/servicestests/res/raw/install_shared2_cert1
similarity index 100%
rename from core/tests/coretests/res/raw/install_shared2_cert1
rename to services/tests/servicestests/res/raw/install_shared2_cert1
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_cert1_cert2 b/services/tests/servicestests/res/raw/install_shared2_cert1_cert2
similarity index 100%
rename from core/tests/coretests/res/raw/install_shared2_cert1_cert2
rename to services/tests/servicestests/res/raw/install_shared2_cert1_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_cert2 b/services/tests/servicestests/res/raw/install_shared2_cert2
similarity index 100%
rename from core/tests/coretests/res/raw/install_shared2_cert2
rename to services/tests/servicestests/res/raw/install_shared2_cert2
Binary files differ
diff --git a/core/tests/coretests/res/raw/install_shared2_unsigned b/services/tests/servicestests/res/raw/install_shared2_unsigned
similarity index 100%
rename from core/tests/coretests/res/raw/install_shared2_unsigned
rename to services/tests/servicestests/res/raw/install_shared2_unsigned
Binary files differ
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/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index f1a63bc..6818d1f 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -16,6 +16,13 @@
package com.android.server.am;
+import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL_IN_PROFILE;
+import static android.app.ActivityManagerInternal.ALLOW_PROFILES_OR_NON_FULL;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
@@ -64,6 +71,7 @@
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.content.pm.UserInfo.UserInfoFlag;
import android.os.Binder;
@@ -617,6 +625,100 @@
assertProfileLockedOrUnlockedAfterStopping(TEST_USER_ID1, /* expectLocking= */ true);
}
+ /** Tests handleIncomingUser() for a variety of permissions and situations. */
+ @Test
+ public void testHandleIncomingUser() throws Exception {
+ final UserInfo user1a = new UserInfo(111, "user1a", 0);
+ final UserInfo user1b = new UserInfo(112, "user1b", 0);
+ final UserInfo user2 = new UserInfo(113, "user2", 0);
+ // user1a and user2b are in the same profile group; user2 is in a different one.
+ user1a.profileGroupId = 5;
+ user1b.profileGroupId = 5;
+ user2.profileGroupId = 6;
+
+ final List<UserInfo> users = Arrays.asList(user1a, user1b, user2);
+ when(mInjector.mUserManagerMock.getUsers(false)).thenReturn(users);
+ mUserController.onSystemReady(); // To set the profileGroupIds in UserController.
+
+
+ // Has INTERACT_ACROSS_USERS_FULL.
+ when(mInjector.checkComponentPermission(
+ eq(INTERACT_ACROSS_USERS_FULL), anyInt(), anyInt(), anyInt(), anyBoolean()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mInjector.checkComponentPermission(
+ eq(INTERACT_ACROSS_USERS), anyInt(), anyInt(), anyInt(), anyBoolean()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mInjector.checkPermissionForPreflight(
+ eq(INTERACT_ACROSS_PROFILES), anyInt(), anyInt(), any())).thenReturn(false);
+
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL, true);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL_IN_PROFILE, true);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_FULL_ONLY, true);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_PROFILES_OR_NON_FULL, true);
+
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL, true);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL_IN_PROFILE, true);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_FULL_ONLY, true);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_PROFILES_OR_NON_FULL, true);
+
+
+ // Has INTERACT_ACROSS_USERS.
+ when(mInjector.checkComponentPermission(
+ eq(INTERACT_ACROSS_USERS_FULL), anyInt(), anyInt(), anyInt(), anyBoolean()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mInjector.checkComponentPermission(
+ eq(INTERACT_ACROSS_USERS), anyInt(), anyInt(), anyInt(), anyBoolean()))
+ .thenReturn(PackageManager.PERMISSION_GRANTED);
+ when(mInjector.checkPermissionForPreflight(
+ eq(INTERACT_ACROSS_PROFILES), anyInt(), anyInt(), any())).thenReturn(false);
+
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL, true);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL_IN_PROFILE, false);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_FULL_ONLY, false);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_PROFILES_OR_NON_FULL, true);
+
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL, true);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL_IN_PROFILE, true);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_FULL_ONLY, false);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_PROFILES_OR_NON_FULL, true);
+
+
+ // Has INTERACT_ACROSS_PROFILES.
+ when(mInjector.checkComponentPermission(
+ eq(INTERACT_ACROSS_USERS_FULL), anyInt(), anyInt(), anyInt(), anyBoolean()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mInjector.checkComponentPermission(
+ eq(INTERACT_ACROSS_USERS), anyInt(), anyInt(), anyInt(), anyBoolean()))
+ .thenReturn(PackageManager.PERMISSION_DENIED);
+ when(mInjector.checkPermissionForPreflight(
+ eq(INTERACT_ACROSS_PROFILES), anyInt(), anyInt(), any())).thenReturn(true);
+
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL, false);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_NON_FULL_IN_PROFILE, false);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_FULL_ONLY, false);
+ checkHandleIncomingUser(user1a.id, user2.id, ALLOW_PROFILES_OR_NON_FULL, false);
+
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL, false);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_NON_FULL_IN_PROFILE, false);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_FULL_ONLY, false);
+ checkHandleIncomingUser(user1a.id, user1b.id, ALLOW_PROFILES_OR_NON_FULL, true);
+ }
+
+ private void checkHandleIncomingUser(int fromUser, int toUser, int allowMode, boolean pass) {
+ final int pid = 100;
+ final int uid = fromUser * UserHandle.PER_USER_RANGE + 34567 + fromUser;
+ final String name = "whatever";
+ final String pkg = "some.package";
+ final boolean allowAll = false;
+
+ if (pass) {
+ mUserController.handleIncomingUser(pid, uid, toUser, allowAll, allowMode, name, pkg);
+ } else {
+ assertThrows(SecurityException.class, () -> mUserController.handleIncomingUser(
+ pid, uid, toUser, allowAll, allowMode, name, pkg));
+ }
+ }
+
private void setUpAndStartUserInBackground(int userId) throws Exception {
setUpUser(userId, 0);
mUserController.startUser(userId, /* foreground= */ false);
@@ -784,6 +886,23 @@
}
@Override
+ int checkComponentPermission(String permission, int pid, int uid, int owner, boolean exp) {
+ Log.i(TAG, "checkComponentPermission " + permission);
+ return PERMISSION_GRANTED;
+ }
+
+ @Override
+ boolean checkPermissionForPreflight(String permission, int pid, int uid, String pkg) {
+ Log.i(TAG, "checkPermissionForPreflight " + permission);
+ return true;
+ }
+
+ @Override
+ boolean isCallerRecents(int uid) {
+ return false;
+ }
+
+ @Override
WindowManagerService getWindowManager() {
return mWindowManagerMock;
}
diff --git a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
index beecdad..4bb5d74 100644
--- a/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/HighBrightnessModeControllerTest.java
@@ -28,7 +28,9 @@
import static com.android.server.display.HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -504,6 +506,24 @@
}
@Test
+ public void tetHbmStats_NbmHdrNoReport() {
+ final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
+ final int displayStatsId = mDisplayUniqueId.hashCode();
+
+ hbmc.setAutoBrightnessEnabled(AUTO_BRIGHTNESS_ENABLED);
+ hbmc.onBrightnessChanged(DEFAULT_MIN);
+ hbmc.getHdrListener().onHdrInfoChanged(null /*displayToken*/, 1 /*numberOfHdrLayers*/,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT, 0 /*flags*/);
+ advanceTime(0);
+ assertEquals(HIGH_BRIGHTNESS_MODE_HDR, hbmc.getHighBrightnessMode());
+
+ // Verify Stats HBM_ON_HDR not report
+ verify(mInjectorMock, never()).reportHbmStateChange(eq(displayStatsId),
+ eq(FrameworkStatsLog.DISPLAY_HBM_STATE_CHANGED__STATE__HBM_ON_HDR),
+ anyInt());
+ }
+
+ @Test
public void testHbmStats_ThermalOff() throws Exception {
final HighBrightnessModeController hbmc = createDefaultHbm(new OffsettableClock());
final int displayStatsId = mDisplayUniqueId.hashCode();
diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
index 658f8d5..ee2bb0a 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerServiceTest.java
@@ -30,6 +30,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -58,6 +59,7 @@
@RunWith(AndroidJUnit4.class)
public class LocaleManagerServiceTest {
private static final String DEFAULT_PACKAGE_NAME = "com.android.myapp";
+ private static final String DEFAULT_INSTALLER_PACKAGE_NAME = "com.android.myapp.installer";
private static final int DEFAULT_USER_ID = 0;
private static final int DEFAULT_UID = Binder.getCallingUid() + 100;
private static final int INVALID_UID = -1;
@@ -66,7 +68,8 @@
LocaleList.forLanguageTags(DEFAULT_LOCALE_TAGS);
private static final InstallSourceInfo DEFAULT_INSTALL_SOURCE_INFO = new InstallSourceInfo(
/* initiatingPackageName = */ null, /* initiatingPackageSigningInfo = */ null,
- /* originatingPackageName = */ null, /* installingPackageName = */ null);
+ /* originatingPackageName = */ null,
+ /* installingPackageName = */ DEFAULT_INSTALLER_PACKAGE_NAME);
private LocaleManagerService mLocaleManagerService;
private LocaleManagerBackupHelper mMockBackupHelper;
@@ -89,7 +92,7 @@
mMockActivityManager = mock(ActivityManagerInternal.class);
mMockPackageManagerInternal = mock(PackageManagerInternal.class);
- // For unit tests, set the default (null) installer info
+ // For unit tests, set the default installer info
PackageManager mockPackageManager = mock(PackageManager.class);
doReturn(DEFAULT_INSTALL_SOURCE_INFO).when(mockPackageManager)
.getInstallSourceInfo(anyString());
@@ -275,6 +278,23 @@
assertEquals(DEFAULT_LOCALES, locales);
}
+ @Test
+ public void testGetApplicationLocales_callerIsInstaller_returnsLocales()
+ throws Exception {
+ doReturn(DEFAULT_UID).when(mMockPackageManagerInternal)
+ .getPackageUid(eq(DEFAULT_PACKAGE_NAME), anyLong(), anyInt());
+ doReturn(Binder.getCallingUid()).when(mMockPackageManagerInternal)
+ .getPackageUid(eq(DEFAULT_INSTALLER_PACKAGE_NAME), anyLong(), anyInt());
+ doReturn(new PackageConfig(/* nightMode = */ 0, DEFAULT_LOCALES))
+ .when(mMockActivityTaskManager).getApplicationConfig(anyString(), anyInt());
+
+ LocaleList locales =
+ mLocaleManagerService.getApplicationLocales(DEFAULT_PACKAGE_NAME, DEFAULT_USER_ID);
+
+ verify(mMockContext, never()).enforceCallingOrSelfPermission(any(), any());
+ assertEquals(DEFAULT_LOCALES, locales);
+ }
+
private static void assertNoLocalesStored(LocaleList locales) {
assertNull(locales);
}
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/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 0f6dfda..13a8f69 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -33,12 +33,12 @@
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
import android.content.pm.UserInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedActivityImpl;
-import android.content.pm.parsing.component.ParsedInstrumentationImpl;
-import android.content.pm.parsing.component.ParsedIntentInfoImpl;
-import android.content.pm.parsing.component.ParsedProviderImpl;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedActivityImpl;
+import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
+import com.android.server.pm.pkg.component.ParsedProviderImpl;
import android.os.Build;
import android.os.Process;
import android.os.UserHandle;
diff --git a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
index 54ab133..e137c37 100644
--- a/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/CompatibilityModeTest.java
@@ -29,8 +29,8 @@
import static org.mockito.Mockito.when;
import android.content.pm.ApplicationInfo;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.ParsingPackageUtils;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import android.os.Build;
import android.platform.test.annotations.Presubmit;
diff --git a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
index 6b6d84a..d7e3825 100644
--- a/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/KeySetManagerServiceTest.java
@@ -17,7 +17,7 @@
package com.android.server.pm;
-import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
+import static android.content.pm.parsing.FrameworkParsingPackageUtils.parsePublicKey;
import android.content.pm.Signature;
import android.platform.test.annotations.Presubmit;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 9d67240..6c9a60a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -22,7 +22,7 @@
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_MORE_DETAILS;
import static android.content.pm.SuspendDialogInfo.BUTTON_ACTION_UNSUSPEND;
-import static android.content.pm.parsing.ParsingPackageUtils.parsePublicKey;
+import static android.content.pm.parsing.FrameworkParsingPackageUtils.parsePublicKey;
import static android.content.res.Resources.ID_NULL;
import static org.hamcrest.CoreMatchers.equalTo;
@@ -43,6 +43,7 @@
import android.content.pm.PackageManager;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
import android.os.BaseBundle;
import android.os.PersistableBundle;
import android.os.Process;
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerTests.java
similarity index 99%
rename from core/tests/coretests/src/android/content/pm/PackageManagerTests.java
rename to services/tests/servicestests/src/com/android/server/pm/PackageManagerTests.java
index c2519ca0..b621a44 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 The Android Open Source Project
+ * 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.content.pm;
+package com.android.server.pm;
import static android.system.OsConstants.S_IFDIR;
import static android.system.OsConstants.S_IFMT;
@@ -32,10 +32,16 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageDeleteObserver;
+import android.content.pm.KeySet;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionParams;
+import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
+import android.content.pm.PermissionInfo;
+import android.content.pm.VerifierDeviceIdentity;
import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.Resources.NotFoundException;
@@ -63,8 +69,10 @@
import androidx.test.filters.SmallTest;
import androidx.test.filters.Suppress;
-import com.android.frameworks.coretests.R;
+import com.android.frameworks.servicestests.R;
import com.android.internal.content.PackageHelper;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import dalvik.system.VMRuntime;
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index c888524..d8ecf20 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -15,7 +15,7 @@
*/
package com.android.server.pm;
-import static android.content.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
+import static com.android.server.pm.permission.CompatibilityPermissionInfo.COMPAT_PERMS;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -43,27 +43,6 @@
import android.content.pm.ServiceInfo;
import android.content.pm.Signature;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.component.ParsedActivity;
-import android.content.pm.parsing.component.ParsedActivityImpl;
-import android.content.pm.parsing.component.ParsedApexSystemService;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedInstrumentation;
-import android.content.pm.parsing.component.ParsedInstrumentationImpl;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedIntentInfoImpl;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionGroup;
-import android.content.pm.parsing.component.ParsedPermissionGroupImpl;
-import android.content.pm.parsing.component.ParsedPermissionImpl;
-import android.content.pm.parsing.component.ParsedPermissionUtils;
-import android.content.pm.parsing.component.ParsedProvider;
-import android.content.pm.parsing.component.ParsedProviderImpl;
-import android.content.pm.parsing.component.ParsedService;
-import android.content.pm.parsing.component.ParsedServiceImpl;
-import android.content.pm.parsing.component.ParsedUsesPermission;
-import android.content.pm.parsing.component.ParsedUsesPermissionImpl;
-import android.content.pm.permission.CompatibilityPermissionInfo;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
@@ -85,7 +64,28 @@
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.permission.CompatibilityPermissionInfo;
import com.android.server.pm.pkg.PackageUserState;
+import com.android.server.pm.pkg.component.ParsedActivity;
+import com.android.server.pm.pkg.component.ParsedActivityImpl;
+import com.android.server.pm.pkg.component.ParsedApexSystemService;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedInstrumentation;
+import com.android.server.pm.pkg.component.ParsedInstrumentationImpl;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionGroup;
+import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl;
+import com.android.server.pm.pkg.component.ParsedPermissionImpl;
+import com.android.server.pm.pkg.component.ParsedPermissionUtils;
+import com.android.server.pm.pkg.component.ParsedProvider;
+import com.android.server.pm.pkg.component.ParsedProviderImpl;
+import com.android.server.pm.pkg.component.ParsedService;
+import com.android.server.pm.pkg.component.ParsedServiceImpl;
+import com.android.server.pm.pkg.component.ParsedUsesPermission;
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
import org.junit.Before;
import org.junit.Rule;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
index 28f24f2..7ff8eec 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ScanTests.java
@@ -43,8 +43,8 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.SharedLibraryInfo;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.component.ParsedUsesPermissionImpl;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl;
import android.content.res.TypedArray;
import android.os.Environment;
import android.os.UserHandle;
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 1dcb0b7..7c8bbec 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -23,7 +23,7 @@
import static org.junit.Assert.fail;
import android.content.pm.SharedLibraryInfo;
-import android.content.pm.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
deleted file mode 100644
index 4059a49..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageInfoFlagBehaviorTest.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 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.pm.parsing
-
-import android.Manifest
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageInfo
-import android.content.pm.PackageManager
-import android.content.pm.PackageParser
-import android.platform.test.annotations.Postsubmit
-import com.android.internal.util.ArrayUtils
-import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.appInfo
-import com.android.server.pm.parsing.AndroidPackageInfoFlagBehaviorTest.Companion.Param.Companion.pkgInfo
-import com.android.server.pm.parsing.pkg.AndroidPackage
-import com.google.common.truth.Truth.assertThat
-import com.google.common.truth.Truth.assertWithMessage
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-
-/**
- * Verifies that missing/adding [PackageManager] flags adds/remove the appropriate fields from the
- * [PackageInfo] or [ApplicationInfo] results.
- *
- * This test has to be updated manually whenever the info generation behavior changes, since
- * there's no single place where flag -> field is defined besides this test.
- */
-@Postsubmit
-@RunWith(Parameterized::class)
-class AndroidPackageInfoFlagBehaviorTest : AndroidPackageParsingTestBase() {
-
- companion object {
-
- data class Param<T> constructor(
- val flag: Int,
- val logTag: String,
- val oldPkgFunction: (pkg: PackageParser.Package, flags: Int) -> T?,
- val newPkgFunction: (pkg: AndroidPackage, flags: Int) -> T?,
- val fieldFunction: (T) -> List<Any?>
- ) {
- companion object {
- fun pkgInfo(flag: Int, fieldFunction: (PackageInfo) -> List<Any?>) = Param(
- flag, PackageInfo::class.java.simpleName,
- ::oldPackageInfo, ::newPackageInfo, fieldFunction
- )
-
- fun appInfo(flag: Int, fieldFunction: (ApplicationInfo) -> List<Any?>) = Param(
- flag, ApplicationInfo::class.java.simpleName,
- { pkg, flags -> oldAppInfo(pkg, flags) },
- { pkg, flags -> newAppInfo(pkg, flags) },
- fieldFunction
- )
- }
-
- override fun toString(): String {
- val hex = Integer.toHexString(flag)
- val fromRight = Integer.toBinaryString(flag).reversed().indexOf('1')
- return "$logTag $hex | 1 shl $fromRight"
- }
- }
-
- @JvmStatic
- @Parameterized.Parameters(name = "{0}")
- fun parameters() = arrayOf(
- pkgInfo(PackageManager.GET_ACTIVITIES) { listOf(it.activities) },
- pkgInfo(PackageManager.GET_GIDS) { listOf(it.gids) },
- pkgInfo(PackageManager.GET_INSTRUMENTATION) { listOf(it.instrumentation) },
- pkgInfo(PackageManager.GET_META_DATA) { listOf(it.applicationInfo.metaData) },
- pkgInfo(PackageManager.GET_PROVIDERS) { listOf(it.providers) },
- pkgInfo(PackageManager.GET_RECEIVERS) { listOf(it.receivers) },
- pkgInfo(PackageManager.GET_SERVICES) { listOf(it.services) },
- pkgInfo(PackageManager.GET_SIGNATURES) { listOf(it.signatures) },
- pkgInfo(PackageManager.GET_SIGNING_CERTIFICATES) { listOf(it.signingInfo) },
- pkgInfo(PackageManager.GET_SHARED_LIBRARY_FILES) {
- it.applicationInfo.run { listOf(sharedLibraryFiles, sharedLibraryFiles) }
- },
- pkgInfo(PackageManager.GET_CONFIGURATIONS) {
- listOf(it.configPreferences, it.reqFeatures, it.featureGroups)
- },
- pkgInfo(PackageManager.GET_PERMISSIONS) {
- listOf(
- it.permissions,
- // Strip compatibility permission added in T
- it.requestedPermissions?.filter { x ->
- x != Manifest.permission.POST_NOTIFICATIONS
- }?.ifEmpty { null }?.toTypedArray(),
- // Strip the flag from compatibility permission added in T
- it.requestedPermissionsFlags?.filterIndexed { index, _ ->
- index != ArrayUtils.indexOf(it.requestedPermissions,
- Manifest.permission.POST_NOTIFICATIONS)
- }?.ifEmpty { null }?.toTypedArray())
- },
- appInfo(PackageManager.GET_META_DATA) { listOf(it.metaData) },
- appInfo(PackageManager.GET_SHARED_LIBRARY_FILES) {
- listOf(it.sharedLibraryFiles, it.sharedLibraryFiles)
- }
- )
- }
-
- @Parameterized.Parameter(0)
- lateinit var param: Param<Any>
-
- @Test
- fun fieldPresence() {
- oldPackages.asSequence().zip(newPackages.asSequence())
- .forEach { (old, new) ->
- val oldWithFlag = param.oldPkgFunction(old, param.flag)
- val newWithFlag = param.newPkgFunction(new, param.flag)
- val oldFieldList = oldWithFlag?.let(param.fieldFunction).orEmpty()
- val newFieldList = newWithFlag?.let(param.fieldFunction).orEmpty()
-
- oldFieldList.zip(newFieldList).forEach {
- assertWithMessage(new.packageName).that(it.second).apply {
- // Assert same null-ness as old logic
- if (it.first == null) {
- isNull()
- } else {
- isNotNull()
- }
- }
- }
- }
- }
-
- @Test
- fun fieldAbsence() {
- newPackages.forEach {
- val newWithoutFlag = param.newPkgFunction(it, 0)
- val newFieldListWithoutFlag = newWithoutFlag?.let(param.fieldFunction).orEmpty()
- assertThat(newFieldListWithoutFlag.filterNotNull()).isEmpty()
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
deleted file mode 100644
index 574921c..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingEquivalenceTest.kt
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 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.pm.parsing
-
-import android.content.pm.PackageManager
-import android.platform.test.annotations.Postsubmit
-import androidx.test.filters.LargeTest
-import com.google.common.truth.Expect
-import org.junit.Rule
-import org.junit.Test
-
-/**
- * Collects APKs from the device and verifies that the new parsing behavior outputs
- * the same exposed Info object as the old parsing logic.
- */
-@Postsubmit
-class AndroidPackageParsingEquivalenceTest : AndroidPackageParsingTestBase() {
-
- @get:Rule
- val expect = Expect.create()
-
- @Test
- fun applicationInfoEquality() {
- val flags = PackageManager.GET_META_DATA or PackageManager.GET_SHARED_LIBRARY_FILES
- val oldAppInfo = oldPackages.asSequence().map { oldAppInfo(it, flags) }
- val newAppInfo = newPackages.asSequence().map { newAppInfo(it, flags) }
- oldAppInfo.zip(newAppInfo).forEach {
- val firstName = it.first?.packageName
- val secondName = it.second?.packageName
- val packageName = if (firstName == secondName) {
- "$firstName"
- } else {
- "$firstName | $secondName"
- }
- expect.withMessage("${it.first?.sourceDir} $packageName")
- .that(it.first?.dumpToString())
- .isEqualTo(it.second?.dumpToString())
- }
- }
-
- @LargeTest
- @Test
- fun packageInfoEquality() {
- val flags = PackageManager.GET_ACTIVITIES or
- PackageManager.GET_CONFIGURATIONS or
- PackageManager.GET_GIDS or
- PackageManager.GET_INSTRUMENTATION or
- PackageManager.GET_META_DATA or
- PackageManager.GET_PERMISSIONS or
- PackageManager.GET_PROVIDERS or
- PackageManager.GET_RECEIVERS or
- PackageManager.GET_SERVICES or
- PackageManager.GET_SHARED_LIBRARY_FILES or
- PackageManager.GET_SIGNATURES or
- PackageManager.GET_SIGNING_CERTIFICATES or
- PackageManager.MATCH_DIRECT_BOOT_UNAWARE or
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- val oldPackageInfo = oldPackages.asSequence().map { oldPackageInfo(it, flags) }
- val newPackageInfo = newPackages.asSequence().map { newPackageInfo(it, flags) }
-
- oldPackageInfo.zip(newPackageInfo).forEach {
- val firstName = it.first?.packageName
- val secondName = it.second?.packageName
- val packageName = if (firstName == secondName) {
- "$firstName"
- } else {
- "$firstName | $secondName"
- }
-
- // Main components are asserted independently to separate the failures. Otherwise the
- // comparison would include every component in one massive string.
-
- val prefix = "${it.first?.applicationInfo?.sourceDir} $packageName"
-
- expect.withMessage("$prefix PackageInfo")
- .that(it.second?.dumpToString())
- .isEqualTo(it.first?.dumpToString())
-
- expect.withMessage("$prefix ApplicationInfo")
- .that(it.second?.applicationInfo?.dumpToString())
- .isEqualTo(it.first?.applicationInfo?.dumpToString())
-
- val firstActivityNames = it.first?.activities?.map { it.name } ?: emptyList()
- val secondActivityNames = it.second?.activities?.map { it.name } ?: emptyList()
- expect.withMessage("$prefix activities")
- .that(secondActivityNames)
- .containsExactlyElementsIn(firstActivityNames)
- .inOrder()
-
- if (!it.first?.activities.isNullOrEmpty() && !it.second?.activities.isNullOrEmpty()) {
- it.first?.activities?.zip(it.second?.activities!!)?.forEach {
- expect.withMessage("$prefix ${it.first.name}")
- .that(it.second.dumpToString())
- .isEqualTo(it.first.dumpToString())
- }
- }
-
- val firstReceiverNames = it.first?.receivers?.map { it.name } ?: emptyList()
- val secondReceiverNames = it.second?.receivers?.map { it.name } ?: emptyList()
- expect.withMessage("$prefix receivers")
- .that(secondReceiverNames)
- .containsExactlyElementsIn(firstReceiverNames)
- .inOrder()
-
- if (!it.first?.receivers.isNullOrEmpty() && !it.second?.receivers.isNullOrEmpty()) {
- it.first?.receivers?.zip(it.second?.receivers!!)?.forEach {
- expect.withMessage("$prefix ${it.first.name}")
- .that(it.second.dumpToString())
- .isEqualTo(it.first.dumpToString())
- }
- }
-
- val firstProviderNames = it.first?.providers?.map { it.name } ?: emptyList()
- val secondProviderNames = it.second?.providers?.map { it.name } ?: emptyList()
- expect.withMessage("$prefix providers")
- .that(secondProviderNames)
- .containsExactlyElementsIn(firstProviderNames)
- .inOrder()
-
- if (!it.first?.providers.isNullOrEmpty() && !it.second?.providers.isNullOrEmpty()) {
- it.first?.providers?.zip(it.second?.providers!!)?.forEach {
- expect.withMessage("$prefix ${it.first.name}")
- .that(it.second.dumpToString())
- .isEqualTo(it.first.dumpToString())
- }
- }
-
- val firstServiceNames = it.first?.services?.map { it.name } ?: emptyList()
- val secondServiceNames = it.second?.services?.map { it.name } ?: emptyList()
- expect.withMessage("$prefix services")
- .that(secondServiceNames)
- .containsExactlyElementsIn(firstServiceNames)
- .inOrder()
-
- if (!it.first?.services.isNullOrEmpty() && !it.second?.services.isNullOrEmpty()) {
- it.first?.services?.zip(it.second?.services!!)?.forEach {
- expect.withMessage("$prefix ${it.first.name}")
- .that(it.second.dumpToString())
- .isEqualTo(it.first.dumpToString())
- }
- }
- }
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
deleted file mode 100644
index 122661e..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/AndroidPackageParsingTestBase.kt
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * Copyright (C) 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.pm.parsing
-
-import android.Manifest
-import android.content.Context
-import android.content.pm.ActivityInfo
-import android.content.pm.ApplicationInfo
-import android.content.pm.ConfigurationInfo
-import android.content.pm.FeatureInfo
-import android.content.pm.InstrumentationInfo
-import android.content.pm.PackageInfo
-import android.content.pm.PackageParser
-import android.content.pm.PermissionInfo
-import android.content.pm.ProviderInfo
-import android.content.pm.ServiceInfo
-import android.content.pm.parsing.ParsingPackageUtils
-import android.os.Bundle
-import android.os.Debug
-import android.os.Environment
-import android.os.Process
-import android.util.SparseArray
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.internal.util.ArrayUtils
-import com.android.server.pm.PackageManagerService
-import com.android.server.pm.parsing.pkg.AndroidPackage
-import com.android.server.pm.pkg.PackageStateInternal
-import com.android.server.pm.pkg.PackageStateUnserialized
-import com.android.server.pm.pkg.PackageUserStateImpl
-import com.android.server.testutils.mockThrowOnUnmocked
-import com.android.server.testutils.whenever
-import org.junit.BeforeClass
-import org.mockito.Mockito.anyInt
-import java.io.File
-
-open class AndroidPackageParsingTestBase {
-
- companion object {
-
- private const val VERIFY_ALL_APKS = true
-
- // For auditing memory usage differences to /sdcard/AndroidPackageParsingTestBase.hprof
- private const val DUMP_HPROF_TO_EXTERNAL = false
-
- val context: Context = InstrumentationRegistry.getInstrumentation().getContext()
- protected val packageParser = PackageParser().apply {
- setOnlyCoreApps(false)
- setDisplayMetrics(context.resources.displayMetrics)
- setCallback { false /* hasFeature */ }
- }
-
- protected val packageParser2 = PackageParser2.forParsingFileWithDefaults()
-
- /**
- * It would be difficult to mock all possibilities, so just use the APKs on device.
- * Unfortunately, this means the device must be bootable to verify potentially
- * boot-breaking behavior.
- */
- private val apks = mutableListOf(File(Environment.getRootDirectory(), "framework"))
- .apply {
- @Suppress("ConstantConditionIf")
- if (VERIFY_ALL_APKS) {
- this += (PackageManagerService.SYSTEM_PARTITIONS)
- .flatMap {
- listOfNotNull(it.privAppFolder, it.appFolder, it.overlayFolder)
- }
- }
- }
- .flatMap {
- it.walkTopDown()
- .filter { file -> file.name.endsWith(".apk") }
- .toList()
- }
- .distinct()
-
- private val dummyUserState =
- PackageUserStateImpl()
-
- val oldPackages = mutableListOf<PackageParser.Package>()
-
- val newPackages = mutableListOf<AndroidPackage>()
-
- @Suppress("ConstantConditionIf")
- @JvmStatic
- @BeforeClass
- fun setUpPackages() {
- var uid = Process.FIRST_APPLICATION_UID
- apks.mapNotNull {
- try {
- packageParser.parsePackage(it, PackageParser.PARSE_IS_SYSTEM_DIR, false) to
- packageParser2.parsePackage(it, ParsingPackageUtils.PARSE_IS_SYSTEM_DIR,
- false)
- } catch (ignored: Exception) {
- // It is intentional that a failure of either call here will result in failing
- // both. Having null on one side would mean nothing to compare. Due to the
- // nature of presubmit, this may not be caused by the change being tested, so
- // it's unhelpful to consider it a failure. Actual parsing issues will be
- // reported by SystemPartitionParseTest in postsubmit.
- null
- }
- }.forEach { (old, new) ->
- // Assign an arbitrary UID. This is normally done after parsing completes, inside
- // PackageManagerService, but since that code isn't run here, need to mock it. This
- // is equivalent to what the system would assign.
- old.applicationInfo.uid = uid
- new.uid = uid
- uid++
-
- oldPackages += old
- newPackages += new.hideAsFinal()
- }
-
- if (DUMP_HPROF_TO_EXTERNAL) {
- System.gc()
- Environment.getExternalStorageDirectory()
- .resolve(
- "${AndroidPackageParsingTestBase::class.java.simpleName}.hprof")
- .absolutePath
- .run(Debug::dumpHprofData)
- }
- }
-
- fun oldAppInfo(
- pkg: PackageParser.Package,
- flags: Int = 0,
- userId: Int = 0
- ): ApplicationInfo? {
- return PackageParser.generateApplicationInfo(pkg, flags, dummyUserState, userId)
- }
-
- fun newAppInfo(
- pkg: AndroidPackage,
- flags: Int = 0,
- userId: Int = 0
- ): ApplicationInfo? {
- return PackageInfoUtils.generateApplicationInfo(pkg, flags.toLong(), dummyUserState,
- userId, mockPkgSetting(pkg))
- }
-
- fun newAppInfoWithoutState(
- pkg: AndroidPackage,
- flags: Int = 0,
- userId: Int = 0
- ): ApplicationInfo? {
- return PackageInfoUtils.generateApplicationInfo(pkg, flags.toLong(), dummyUserState,
- userId, mockPkgSetting(pkg))
- }
-
- fun oldPackageInfo(pkg: PackageParser.Package, flags: Int = 0): PackageInfo? {
- return PackageParser.generatePackageInfo(pkg, intArrayOf(), flags, 5, 6, emptySet(),
- dummyUserState)
- }
-
- fun newPackageInfo(pkg: AndroidPackage, flags: Int = 0): PackageInfo? {
- return PackageInfoUtils.generate(pkg, intArrayOf(), flags.toLong(), 5, 6, emptySet(),
- dummyUserState, 0, mockPkgSetting(pkg))
- }
-
- private fun mockPkgSetting(aPkg: AndroidPackage) =
- mockThrowOnUnmocked<PackageStateInternal> {
- whenever(pkg) { aPkg }
- whenever(appId) { aPkg.uid }
- whenever(transientState) { PackageStateUnserialized() }
- whenever(getUserStateOrDefault(anyInt())) { dummyUserState }
- whenever(categoryOverride) { ApplicationInfo.CATEGORY_UNDEFINED }
- whenever(primaryCpuAbi) { null }
- whenever(secondaryCpuAbi) { null }
- }
- }
-
- // The following methods dump an exact set of fields from the object to compare, because
- // 1. comprehensive equals/toStrings do not exist on all of the Info objects, and
- // 2. the test must only verify fields that [PackageParser.Package] can actually fill, as
- // no new functionality will be added to it.
-
- // The following methods prepend "this." because @hide APIs can cause an IDE to auto-import
- // the R.attr constant instead of referencing the field in an attempt to fix the error.
-
- // It's difficult to comment out a line in a triple quoted string, so this is used instead
- // to ignore specific fields. A comment is required to explain why a field was ignored.
- private fun Any?.ignored(comment: String): String = "IGNORED"
-
- protected fun ApplicationInfo.dumpToString() = """
- appComponentFactory=${this.appComponentFactory}
- backupAgentName=${this.backupAgentName}
- banner=${this.banner}
- category=${this.category}
- classLoaderName=${this.classLoaderName}
- className=${this.className}
- compatibleWidthLimitDp=${this.compatibleWidthLimitDp}
- compileSdkVersion=${this.compileSdkVersion}
- compileSdkVersionCodename=${this.compileSdkVersionCodename}
- credentialProtectedDataDir=${this.credentialProtectedDataDir
- .ignored("Deferred pre-R, but assigned immediately in R")}
- crossProfile=${this.crossProfile.ignored("Added in R")}
- dataDir=${this.dataDir.ignored("Deferred pre-R, but assigned immediately in R")}
- descriptionRes=${this.descriptionRes}
- deviceProtectedDataDir=${this.deviceProtectedDataDir
- .ignored("Deferred pre-R, but assigned immediately in R")}
- enabled=${this.enabled}
- enabledSetting=${this.enabledSetting}
- flags=${Integer.toBinaryString(this.flags)}
- fullBackupContent=${this.fullBackupContent}
- gwpAsanMode=${this.gwpAsanMode.ignored("Added in R")}
- hiddenUntilInstalled=${this.hiddenUntilInstalled}
- icon=${this.icon}
- iconRes=${this.iconRes}
- installLocation=${this.installLocation}
- labelRes=${this.labelRes}
- largestWidthLimitDp=${this.largestWidthLimitDp}
- logo=${this.logo}
- longVersionCode=${this.longVersionCode}
- ${"".ignored("mHiddenApiPolicy is a private field")}
- manageSpaceActivityName=${this.manageSpaceActivityName}
- maxAspectRatio=${this.maxAspectRatio}
- metaData=${this.metaData.dumpToString()}
- minAspectRatio=${this.minAspectRatio}
- minSdkVersion=${this.minSdkVersion}
- name=${this.name}
- nativeLibraryDir=${this.nativeLibraryDir}
- nativeLibraryRootDir=${this.nativeLibraryRootDir}
- nativeLibraryRootRequiresIsa=${this.nativeLibraryRootRequiresIsa}
- networkSecurityConfigRes=${this.networkSecurityConfigRes}
- nonLocalizedLabel=${
- // Per b/184574333, v1 mistakenly trimmed the label. v2 fixed this, but for test
- // comparison, trim both so they can be matched.
- this.nonLocalizedLabel?.trim()
- }
- packageName=${this.packageName}
- permission=${this.permission}
- primaryCpuAbi=${this.primaryCpuAbi}
- privateFlags=${Integer.toBinaryString(this.privateFlags)}
- processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
- publicSourceDir=${this.publicSourceDir
- .ignored("Deferred pre-R, but assigned immediately in R")}
- requiresSmallestWidthDp=${this.requiresSmallestWidthDp}
- resourceDirs=${this.resourceDirs?.contentToString()}
- overlayPaths=${this.overlayPaths?.contentToString()}
- roundIconRes=${this.roundIconRes}
- scanPublicSourceDir=${this.scanPublicSourceDir
- .ignored("Deferred pre-R, but assigned immediately in R")}
- scanSourceDir=${this.scanSourceDir
- .ignored("Deferred pre-R, but assigned immediately in R")}
- seInfo=${this.seInfo}
- seInfoUser=${this.seInfoUser}
- secondaryCpuAbi=${this.secondaryCpuAbi}
- secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
- sharedLibraryFiles=${this.sharedLibraryFiles?.contentToString()}
- sharedLibraryInfos=${this.sharedLibraryInfos}
- showUserIcon=${this.showUserIcon}
- sourceDir=${this.sourceDir
- .ignored("Deferred pre-R, but assigned immediately in R")}
- splitClassLoaderNames=${this.splitClassLoaderNames?.contentToString()}
- splitDependencies=${this.splitDependencies.dumpToString()}
- splitNames=${this.splitNames?.contentToString()}
- splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
- splitSourceDirs=${this.splitSourceDirs?.contentToString()}
- storageUuid=${this.storageUuid}
- targetSandboxVersion=${this.targetSandboxVersion}
- targetSdkVersion=${this.targetSdkVersion}
- taskAffinity=${this.taskAffinity}
- theme=${this.theme}
- uiOptions=${this.uiOptions}
- uid=${this.uid}
- versionCode=${this.versionCode}
- volumeUuid=${this.volumeUuid}
- zygotePreloadName=${this.zygotePreloadName}
- """.trimIndent()
-
- protected fun FeatureInfo.dumpToString() = """
- flags=${Integer.toBinaryString(this.flags)}
- name=${this.name}
- reqGlEsVersion=${this.reqGlEsVersion}
- version=${this.version}
- """.trimIndent()
-
- protected fun InstrumentationInfo.dumpToString() = """
- banner=${this.banner}
- credentialProtectedDataDir=${this.credentialProtectedDataDir}
- dataDir=${this.dataDir}
- deviceProtectedDataDir=${this.deviceProtectedDataDir}
- functionalTest=${this.functionalTest}
- handleProfiling=${this.handleProfiling}
- icon=${this.icon}
- labelRes=${this.labelRes}
- logo=${this.logo}
- metaData=${this.metaData}
- name=${this.name}
- nativeLibraryDir=${this.nativeLibraryDir}
- nonLocalizedLabel=${
- // Per b/184574333, v1 mistakenly trimmed the label. v2 fixed this, but for test
- // comparison, trim both so they can be matched.
- this.nonLocalizedLabel?.trim()
- }
- packageName=${this.packageName}
- primaryCpuAbi=${this.primaryCpuAbi}
- publicSourceDir=${this.publicSourceDir}
- secondaryCpuAbi=${this.secondaryCpuAbi}
- secondaryNativeLibraryDir=${this.secondaryNativeLibraryDir}
- showUserIcon=${this.showUserIcon}
- sourceDir=${this.sourceDir}
- splitDependencies=${this.splitDependencies.dumpToString()}
- splitNames=${this.splitNames?.contentToString()}
- splitPublicSourceDirs=${this.splitPublicSourceDirs?.contentToString()}
- splitSourceDirs=${this.splitSourceDirs?.contentToString()}
- targetPackage=${this.targetPackage}
- targetProcesses=${this.targetProcesses}
- """.trimIndent()
-
- protected fun ActivityInfo.dumpToString() = """
- banner=${this.banner}
- colorMode=${this.colorMode}
- configChanges=${this.configChanges}
- descriptionRes=${this.descriptionRes}
- directBootAware=${this.directBootAware}
- documentLaunchMode=${this.documentLaunchMode
- .ignored("Update for fixing b/128526493 and the testing is no longer valid")}
- enabled=${this.enabled}
- exported=${this.exported}
- flags=${Integer.toBinaryString(
- // Strip flag added in T
- this.flags and (ActivityInfo.FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES.inv()))
- }
- icon=${this.icon}
- labelRes=${this.labelRes}
- launchMode=${this.launchMode}
- launchToken=${this.launchToken}
- lockTaskLaunchMode=${this.lockTaskLaunchMode}
- logo=${this.logo}
- maxRecents=${this.maxRecents}
- metaData=${this.metaData.dumpToString()}
- name=${this.name}
- nonLocalizedLabel=${
- // Per b/184574333, v1 mistakenly trimmed the label. v2 fixed this, but for test
- // comparison, trim both so they can be matched.
- this.nonLocalizedLabel?.trim()
- }
- packageName=${this.packageName}
- parentActivityName=${this.parentActivityName}
- permission=${this.permission}
- persistableMode=${this.persistableMode.ignored("Could be dropped pre-R, fixed in R")}
- privateFlags=${
- // Strip flag added in S
- this.privateFlags and (ActivityInfo.PRIVATE_FLAG_HOME_TRANSITION_SOUND.inv())
- }
- processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
- requestedVrComponent=${this.requestedVrComponent}
- resizeMode=${this.resizeMode}
- rotationAnimation=${this.rotationAnimation}
- screenOrientation=${this.screenOrientation}
- showUserIcon=${this.showUserIcon}
- softInputMode=${this.softInputMode}
- splitName=${this.splitName}
- targetActivity=${this.targetActivity}
- taskAffinity=${this.taskAffinity}
- theme=${this.theme}
- uiOptions=${this.uiOptions}
- windowLayout=${this.windowLayout?.dumpToString()}
- """.trimIndent()
-
- protected fun ActivityInfo.WindowLayout.dumpToString() = """
- gravity=${this.gravity}
- height=${this.height}
- heightFraction=${this.heightFraction}
- minHeight=${this.minHeight}
- minWidth=${this.minWidth}
- width=${this.width}
- widthFraction=${this.widthFraction}
- """.trimIndent()
-
- protected fun PermissionInfo.dumpToString() = """
- backgroundPermission=${this.backgroundPermission}
- banner=${this.banner}
- descriptionRes=${this.descriptionRes}
- flags=${Integer.toBinaryString(this.flags)}
- group=${this.group}
- icon=${this.icon}
- labelRes=${this.labelRes}
- logo=${this.logo}
- metaData=${this.metaData.dumpToString()}
- name=${this.name}
- nonLocalizedDescription=${this.nonLocalizedDescription}
- nonLocalizedLabel=${
- // Per b/184574333, v1 mistakenly trimmed the label. v2 fixed this, but for test
- // comparison, trim both so they can be matched.
- this.nonLocalizedLabel?.trim()
- }
- packageName=${this.packageName}
- protectionLevel=${this.protectionLevel}
- requestRes=${this.requestRes}
- showUserIcon=${this.showUserIcon}
- """.trimIndent()
-
- protected fun ProviderInfo.dumpToString() = """
- applicationInfo=${this.applicationInfo.ignored("Already checked")}
- authority=${this.authority}
- banner=${this.banner}
- descriptionRes=${this.descriptionRes}
- directBootAware=${this.directBootAware}
- enabled=${this.enabled}
- exported=${this.exported}
- flags=${Integer.toBinaryString(this.flags)}
- forceUriPermissions=${this.forceUriPermissions}
- grantUriPermissions=${this.grantUriPermissions}
- icon=${this.icon}
- initOrder=${this.initOrder}
- isSyncable=${this.isSyncable}
- labelRes=${this.labelRes}
- logo=${this.logo}
- metaData=${this.metaData.dumpToString()}
- multiprocess=${this.multiprocess}
- name=${this.name}
- nonLocalizedLabel=${
- // Per b/184574333, v1 mistakenly trimmed the label. v2 fixed this, but for test
- // comparison, trim both so they can be matched.
- this.nonLocalizedLabel?.trim()
- }
- packageName=${this.packageName}
- pathPermissions=${this.pathPermissions?.joinToString {
- "readPermission=${it.readPermission}\nwritePermission=${it.writePermission}"
- }}
- processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
- readPermission=${this.readPermission}
- showUserIcon=${this.showUserIcon}
- splitName=${this.splitName}
- uriPermissionPatterns=${this.uriPermissionPatterns?.contentToString()}
- writePermission=${this.writePermission}
- """.trimIndent()
-
- protected fun ServiceInfo.dumpToString() = """
- applicationInfo=${this.applicationInfo.ignored("Already checked")}
- banner=${this.banner}
- descriptionRes=${this.descriptionRes}
- directBootAware=${this.directBootAware}
- enabled=${this.enabled}
- exported=${this.exported}
- flags=${Integer.toBinaryString(this.flags)}
- icon=${this.icon}
- labelRes=${this.labelRes}
- logo=${this.logo}
- mForegroundServiceType"${this.mForegroundServiceType}
- metaData=${this.metaData.dumpToString()}
- name=${this.name}
- nonLocalizedLabel=${
- // Per b/184574333, v1 mistakenly trimmed the label. v2 fixed this, but for test
- // comparison, trim both so they can be matched.
- this.nonLocalizedLabel?.trim()
- }
- packageName=${this.packageName}
- permission=${this.permission}
- processName=${this.processName.ignored("Deferred pre-R, but assigned immediately in R")}
- showUserIcon=${this.showUserIcon}
- splitName=${this.splitName}
- """.trimIndent()
-
- protected fun ConfigurationInfo.dumpToString() = """
- reqGlEsVersion=${this.reqGlEsVersion}
- reqInputFeatures=${this.reqInputFeatures}
- reqKeyboardType=${this.reqKeyboardType}
- reqNavigation=${this.reqNavigation}
- reqTouchScreen=${this.reqTouchScreen}
- """.trimIndent()
-
- protected fun PackageInfo.dumpToString() = """
- activities=${this.activities?.joinToString { it.dumpToString() }
- .ignored("Checked separately in test")}
- applicationInfo=${this.applicationInfo.dumpToString()
- .ignored("Checked separately in test")}
- baseRevisionCode=${this.baseRevisionCode}
- compileSdkVersion=${this.compileSdkVersion}
- compileSdkVersionCodename=${this.compileSdkVersionCodename}
- configPreferences=${this.configPreferences?.joinToString { it.dumpToString() }}
- coreApp=${this.coreApp}
- featureGroups=${this.featureGroups?.joinToString {
- it.features?.joinToString { featureInfo -> featureInfo.dumpToString() }.orEmpty()
- }}
- firstInstallTime=${this.firstInstallTime}
- gids=${gids?.contentToString()}
- installLocation=${this.installLocation}
- instrumentation=${instrumentation?.joinToString { it.dumpToString() }}
- isApex=${this.isApex}
- isStub=${this.isStub}
- lastUpdateTime=${this.lastUpdateTime}
- mOverlayIsStatic=${this.mOverlayIsStatic}
- overlayCategory=${this.overlayCategory}
- overlayPriority=${this.overlayPriority}
- overlayTarget=${this.overlayTarget}
- packageName=${this.packageName}
- permissions=${this.permissions?.joinToString { it.dumpToString() }}
- providers=${this.providers?.joinToString { it.dumpToString() }
- .ignored("Checked separately in test")}
- receivers=${this.receivers?.joinToString { it.dumpToString() }
- .ignored("Checked separately in test")}
- reqFeatures=${this.reqFeatures?.joinToString { it.dumpToString() }}
- requestedPermissions=${
- // Strip compatibility permission added in T
- this.requestedPermissions?.filter { x ->
- x != Manifest.permission.POST_NOTIFICATIONS
- }?.ifEmpty { null }?.joinToString()
- }
- requestedPermissionsFlags=${
- // Strip the flag from compatibility permission added in T
- this.requestedPermissionsFlags?.filterIndexed { index, _ ->
- index != ArrayUtils.indexOf(requestedPermissions,
- Manifest.permission.POST_NOTIFICATIONS)
- }?.map {
- // Newer flags are stripped
- it and (PackageInfo.REQUESTED_PERMISSION_REQUIRED
- or PackageInfo.REQUESTED_PERMISSION_GRANTED)
- }?.ifEmpty { null }?.joinToString()
- }
- requiredAccountType=${this.requiredAccountType}
- requiredForAllUsers=${this.requiredForAllUsers}
- restrictedAccountType=${this.restrictedAccountType}
- services=${this.services?.joinToString { it.dumpToString() }
- .ignored("Checked separately in test")}
- sharedUserId=${this.sharedUserId}
- sharedUserLabel=${this.sharedUserLabel}
- signatures=${this.signatures?.joinToString { it.toCharsString() }}
- signingInfo=${this.signingInfo?.signingCertificateHistory
- ?.joinToString { it.toCharsString() }.orEmpty()}
- splitNames=${this.splitNames?.contentToString()}
- splitRevisionCodes=${this.splitRevisionCodes?.contentToString()}
- targetOverlayableName=${this.targetOverlayableName}
- versionCode=${this.versionCode}
- versionCodeMajor=${this.versionCodeMajor}
- versionName=${this.versionName}
- """.trimIndent()
-
- private fun Bundle?.dumpToString() = this?.keySet()?.associateWith { get(it) }?.toString()
-
- private fun <T> SparseArray<T>?.dumpToString(): String {
- if (this == null) {
- return "EMPTY"
- }
-
- val list = mutableListOf<Pair<Int, T>>()
- for (index in (0 until size())) {
- list += keyAt(index) to valueAt(index)
- }
- return list.toString()
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageInfoUserFieldsTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageInfoUserFieldsTest.kt
deleted file mode 100644
index 67b5d68..0000000
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageInfoUserFieldsTest.kt
+++ /dev/null
@@ -1,145 +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 com.android.server.pm.parsing
-
-import android.content.pm.ApplicationInfo
-import android.content.pm.PackageParser
-import android.os.Environment
-import android.os.UserHandle
-import android.platform.test.annotations.Presubmit
-import com.google.common.truth.Truth.assertWithMessage
-import org.junit.Test
-
-/**
- * As a performance optimization, the new parsing code builds the user data directories manually
- * using string concatenation. This tries to mirror the logic that [Environment] uses, but it is
- * still fragile to changes and potentially different device configurations.
- *
- * This compares the resultant values against the old [PackageParser] outputs as well as
- * [ApplicationInfo]'s own [ApplicationInfo.initForUser].
- */
-@Presubmit
-class PackageInfoUserFieldsTest : AndroidPackageParsingTestBase() {
-
- @Test
- fun userEnvironmentValues() {
- // Specifically use a large user ID to test assumptions about single character IDs
- val userId = 110
-
- oldPackages.zip(newPackages)
- .map { (old, new) ->
- (old to oldAppInfo(pkg = old, userId = userId)!!) to
- (new to newAppInfo(pkg = new, userId = userId)!!)
- }
- .forEach { (oldPair, newPair) ->
- val (oldPkg, oldInfo) = oldPair
- val (newPkg, newInfo) = newPair
-
- val oldValuesActual = extractActual(oldInfo)
- val newValuesActual = extractActual(newInfo)
- val oldValuesExpected: Values
- val newValuesExpected: Values
-
- val packageName = oldPkg.packageName
- if (packageName == "android") {
- val systemDataDir = Environment.getDataSystemDirectory().absolutePath
- oldValuesExpected = Values(
- uid = UserHandle.getUid(userId,
- UserHandle.getAppId(oldPkg.applicationInfo.uid)),
- userDe = null,
- userCe = null,
- dataDir = systemDataDir
- )
- newValuesExpected = Values(
- uid = UserHandle.getUid(userId, UserHandle.getAppId(newPkg.uid)),
- userDe = null,
- userCe = null,
- dataDir = systemDataDir
- )
- } else {
- oldValuesExpected = extractExpected(oldInfo, oldInfo.uid, userId)
- newValuesExpected = extractExpected(newInfo, newPkg.uid, userId)
- }
-
- // Calls the internal ApplicationInfo logic to compare against. This must be
- // done after saving the original values, since this will overwrite them.
- oldInfo.initForUser(userId)
- newInfo.initForUser(userId)
-
- val oldInitValues = extractActual(oldInfo)
- val newInitValues = extractActual(newInfo)
-
- // The optimization is also done for the no state API that isn't used by the
- // system. This API is still exposed publicly, so for this test we should
- // verify it.
- val newNoStateValues = extractActual(
- newAppInfoWithoutState(newPkg, 0, userId)!!)
-
- assertAllEquals(packageName,
- oldValuesActual, oldValuesExpected, oldInitValues,
- newValuesActual, newValuesExpected, newInitValues, newNoStateValues)
- }
- }
-
- private fun assertAllEquals(packageName: String, vararg values: Values) {
- // Local function to avoid accidentally calling wrong type
- fun assertAllEquals(message: String, vararg values: Any?) {
- values.forEachIndexed { index, value ->
- if (index == 0) return@forEachIndexed
- assertWithMessage("$message $index").that(values[0]).isEqualTo(value)
- }
- }
-
- assertAllEquals("$packageName mismatched uid", values.map { it.uid })
- assertAllEquals("$packageName mismatched userDe", values.map { it.userDe })
- assertAllEquals("$packageName mismatched userCe", values.map { it.userCe })
- assertAllEquals("$packageName mismatched dataDir", values.map { it.dataDir })
- }
-
- private fun extractActual(appInfo: ApplicationInfo) = Values(
- uid = appInfo.uid,
- userDe = appInfo.deviceProtectedDataDir,
- userCe = appInfo.credentialProtectedDataDir,
- dataDir = appInfo.dataDir
- )
-
- private fun extractExpected(appInfo: ApplicationInfo, appIdUid: Int, userId: Int): Values {
- val userDe = Environment.getDataUserDePackageDirectory(appInfo.volumeUuid, userId,
- appInfo.packageName).absolutePath
- val userCe = Environment.getDataUserCePackageDirectory(appInfo.volumeUuid, userId,
- appInfo.packageName).absolutePath
- val dataDir = if (appInfo.isDefaultToDeviceProtectedStorage) {
- appInfo.deviceProtectedDataDir
- } else {
- appInfo.credentialProtectedDataDir
- }
-
- return Values(
- uid = UserHandle.getUid(userId, UserHandle.getAppId(appIdUid)),
- userDe = userDe,
- userCe = userCe,
- dataDir = dataDir
- )
- }
-
- data class Values(
- val uid: Int,
- val userDe: String?,
- val userCe: String?,
- val dataDir: String?
- )
-}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
index c990342..004d7bc 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParserLegacyCoreTest.java
@@ -18,7 +18,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import android.apex.ApexInfo;
@@ -27,16 +26,9 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
import android.content.pm.PermissionInfo;
import android.content.pm.SigningDetails;
-import android.content.pm.parsing.PackageInfoWithoutStateUtils;
-import android.content.pm.parsing.ParsingPackage;
-import android.content.pm.parsing.ParsingPackageUtils;
-import android.content.pm.parsing.component.ParsedComponent;
-import android.content.pm.parsing.component.ParsedIntentInfo;
-import android.content.pm.parsing.component.ParsedPermission;
-import android.content.pm.parsing.component.ParsedPermissionUtils;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
import android.content.pm.parsing.result.ParseResult;
import android.content.pm.parsing.result.ParseTypeImpl;
import android.os.Build;
@@ -55,6 +47,14 @@
import com.android.server.pm.PackageManagerException;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.ParsedPackage;
+import com.android.server.pm.pkg.component.ParsedActivityUtils;
+import com.android.server.pm.pkg.component.ParsedComponent;
+import com.android.server.pm.pkg.component.ParsedIntentInfo;
+import com.android.server.pm.pkg.component.ParsedPermission;
+import com.android.server.pm.pkg.component.ParsedPermissionUtils;
+import com.android.server.pm.pkg.parsing.PackageInfoWithoutStateUtils;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import com.google.common.truth.Expect;
@@ -105,20 +105,19 @@
private void verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename,
boolean isPlatformReleased, int expectedMinSdk) {
- final String[] outError = new String[1];
- final int result = PackageParser.computeMinSdkVersion(
+ final ParseTypeImpl input = ParseTypeImpl.forParsingWithoutPlatformCompat();
+ final ParseResult<Integer> result = FrameworkParsingPackageUtils.computeMinSdkVersion(
minSdkVersion,
minSdkCodename,
PLATFORM_VERSION,
isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
- outError);
-
- assertEquals("Error msg: " + outError[0], expectedMinSdk, result);
+ input);
if (expectedMinSdk == -1) {
- assertNotNull(outError[0]);
+ assertTrue(result.isError());
} else {
- assertNull(outError[0]);
+ assertTrue(result.isSuccess());
+ assertEquals(expectedMinSdk, (int) result.getResult());
}
}
@@ -201,19 +200,18 @@
private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
boolean isPlatformReleased, int expectedTargetSdk) {
- final String[] outError = new String[1];
- final int result = PackageParser.computeTargetSdkVersion(
+ final ParseTypeImpl input = ParseTypeImpl.forParsingWithoutPlatformCompat();
+ final ParseResult<Integer> result = FrameworkParsingPackageUtils.computeTargetSdkVersion(
targetSdkVersion,
targetSdkCodename,
isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
- outError);
-
- assertEquals(result, expectedTargetSdk);
+ input);
if (expectedTargetSdk == -1) {
- assertNotNull(outError[0]);
+ assertTrue(result.isError());
} else {
- assertNull(outError[0]);
+ assertTrue(result.isSuccess());
+ assertEquals(expectedTargetSdk, (int) result.getResult());
}
}
@@ -306,34 +304,34 @@
// Not set in either configChanges or recreateOnConfigChanges.
int configChanges = 0x0000; // 00000000.
int recreateOnConfigChanges = 0x0000; // 00000000.
- int finalConfigChanges =
- PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges);
+ int finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
+ recreateOnConfigChanges);
assertEquals(0x0003, finalConfigChanges); // Should be 00000011.
// Not set in configChanges, but set in recreateOnConfigChanges.
configChanges = 0x0000; // 00000000.
recreateOnConfigChanges = 0x0003; // 00000011.
- finalConfigChanges =
- PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges);
+ finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
+ recreateOnConfigChanges);
assertEquals(0x0000, finalConfigChanges); // Should be 00000000.
// Set in configChanges.
configChanges = 0x0003; // 00000011.
recreateOnConfigChanges = 0X0000; // 00000000.
- finalConfigChanges =
- PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges);
+ finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
+ recreateOnConfigChanges);
assertEquals(0x0003, finalConfigChanges); // Should be 00000011.
recreateOnConfigChanges = 0x0003; // 00000011.
- finalConfigChanges =
- PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges);
+ finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
+ recreateOnConfigChanges);
assertEquals(0x0003, finalConfigChanges); // Should still be 00000011.
// Other bit set in configChanges.
configChanges = 0x0080; // 10000000, orientation.
recreateOnConfigChanges = 0x0000; // 00000000.
- finalConfigChanges =
- PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges);
+ finalConfigChanges = ParsedActivityUtils.getActivityConfigChanges(configChanges,
+ recreateOnConfigChanges);
assertEquals(0x0083, finalConfigChanges); // Should be 10000011.
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
index f530421..bb094ba 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/PackageParsingDeferErrorTest.kt
@@ -18,8 +18,8 @@
import android.annotation.RawRes
import android.content.Context
-import android.content.pm.parsing.ParsingPackage
-import android.content.pm.parsing.ParsingPackageUtils
+import com.android.server.pm.pkg.parsing.ParsingPackage
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import android.content.pm.parsing.result.ParseResult
import android.platform.test.annotations.Presubmit
import androidx.test.InstrumentationRegistry
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt b/services/tests/servicestests/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
index ffa1957..1f57b6c 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/SystemPartitionParseTest.kt
@@ -17,7 +17,7 @@
package com.android.server.pm.parsing
import android.content.pm.PackageManager
-import android.content.pm.parsing.ParsingPackageUtils
+import com.android.server.pm.pkg.parsing.ParsingPackageUtils
import android.platform.test.annotations.Postsubmit
import com.android.server.pm.PackageManagerException
import com.android.server.pm.PackageManagerService
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index 5bcd0f6..b28446b 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -23,7 +23,7 @@
import static com.google.common.truth.Truth.assertThat;
-import android.content.pm.parsing.ParsingPackage;
+import com.android.server.pm.pkg.parsing.ParsingPackage;
import android.os.Build;
import android.platform.test.annotations.Presubmit;
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6d8edc5..21967f4 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2486,6 +2486,10 @@
*
* Note: If {@code *} is specified for the original code, any ImsReasonInfo with the matching
* {@code MESSAGE} will be remapped to {@code NEW_CODE}.
+ * If {@code *} is specified for the message, any ImsReasonInfo with the matching
+ * {@code ORIGINAL_CODE} will be remapped to {@code NEW_CODE}.
+ * The wildcard for {@code ORIGINAL_CODE} takes precedence to the wildcard for {@code MESSAGE}.
+ * A mapping with both wildcards has no effect.
*
* Example: "501|call completion elsewhere|1014"
* When the {@link ImsReasonInfo#getCode()} is {@link ImsReasonInfo#CODE_USER_TERMINATED} and
@@ -8646,10 +8650,10 @@
/* Default value is 2 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000);
sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true);
- sDefaults.putInt(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000);
- sDefaults.putInt(
+ sDefaults.putLong(KEY_TIME_TO_SWITCH_BACK_TO_PRIMARY_IF_OPPORTUNISTIC_OOS_LONG, 60000L);
+ sDefaults.putLong(
KEY_OPPORTUNISTIC_TIME_TO_SCAN_AFTER_CAPABILITY_SWITCH_TO_PRIMARY_LONG,
- 120000);
+ 120000L);
sDefaults.putAll(ImsServiceEntitlement.getDefaults());
sDefaults.putAll(Gps.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 54fb65ce..cbd03c7 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -2548,6 +2548,11 @@
*/
public static final int RESULT_RIL_BLOCKED_DUE_TO_CALL = 123;
+ /**
+ * A RIL error occurred during the SMS send.
+ */
+ public static final int RESULT_RIL_GENERIC_ERROR = 124;
+
// SMS receiving results sent as a "result" extra in {@link Intents.SMS_REJECTED_ACTION}
/**
diff --git a/telephony/java/android/telephony/UiccSlotMapping.java b/telephony/java/android/telephony/UiccSlotMapping.java
index 87e7acd..08de7fd 100644
--- a/telephony/java/android/telephony/UiccSlotMapping.java
+++ b/telephony/java/android/telephony/UiccSlotMapping.java
@@ -94,7 +94,6 @@
* @param physicalSlotIndex is unique index referring to a physical SIM slot.
* @param logicalSlotIndex is unique index referring to a logical SIM slot.
*
- * @hide
*/
public UiccSlotMapping(int portIndex, int physicalSlotIndex, int logicalSlotIndex) {
this.mPortIndex = portIndex;
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 977fe33..cb112cf 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -118,11 +118,9 @@
public static final int TYPE_VSIM = 1 << 12; // TODO: Refer to ApnTypes.VSIM
/** APN type for BIP. */
public static final int TYPE_BIP = 1 << 13; // TODO: Refer to ApnTypes.BIP
- /**
- * APN type for ENTERPRISE.
- * @hide
- */
- public static final int TYPE_ENTERPRISE = TYPE_BIP << 1;
+ /** APN type for ENTERPRISE. */
+ public static final int TYPE_ENTERPRISE = 1 << 14; //TODO: In future should be referenced from
+ // hardware.interfaces.radio.data.ApnTypes
/** @hide */
@IntDef(flag = true, prefix = {"TYPE_"}, value = {
@@ -355,6 +353,7 @@
* modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
+ @SystemApi
public static final String TYPE_ENTERPRISE_STRING = "enterprise";
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 2e5402c5..a49a61b5 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -805,6 +805,13 @@
*/
public static final int ERROR_OPERATION_BUSY = 10016;
+ /**
+ * Failure due to target port is not supported.
+ * @see #switchToSubscription(int, int, PendingIntent)
+ */
+ public static final int ERROR_INVALID_PORT = 10017;
+
+
private final Context mContext;
private int mCardId;
@@ -1120,6 +1127,15 @@
* intent to prompt the user to accept the download. The caller should also be authorized to
* manage the subscription to be enabled.
*
+ * <p> From Android T, devices might support MEP(Multiple Enabled Profile), the subscription
+ * can be installed on different port from the eUICC. Calling apps with carrier privilege
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) over the currently active subscriptions
+ * can use {@link #switchToSubscription(int, int, PendingIntent)} to specify which port to
+ * enable the subscription. Otherwise, use this API to enable the subscription on the eUICC
+ * and the platform will internally resolve a port. If there is no available port,
+ * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} might be returned in the callback
+ * intent to prompt the user to disable an already-active subscription.
+ *
* @param subscriptionId the ID of the subscription to enable. May be
* {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the
* current profile without activating another profile to replace it. If it's a disable
@@ -1127,12 +1143,7 @@
* permission, or the calling app must be authorized to manage the active subscription on
* the target eUICC.
* @param callbackIntent a PendingIntent to launch when the operation completes.
- *
- * @deprecated From T, callers should use
- * {@link #switchToSubscription(int, int, PendingIntent)} instead to specify a port
- * index on the card to switch to.
*/
- @Deprecated
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
if (!isEnabled()) {
@@ -1150,20 +1161,19 @@
/**
* Switch to (enable) the given subscription.
*
- * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
- * or the calling app must be authorized to manage both the currently-active subscription and
- * the subscription to be enabled according to the subscription metadata. Without the former,
- * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
- * intent to prompt the user to accept the download.
+ * <p> Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission,
+ * or the caller must be having both the carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) over any currently active subscriptions
+ * and the subscription to be enabled according to the subscription metadata.
+ * Without the former permissions, an SecurityException is thrown.
*
- * <p>On a multi-active SIM device, requires the
- * {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, or a calling app
- * only if the targeted eUICC does not currently have an active subscription or the calling app
- * is authorized to manage the active subscription on the target eUICC, and the calling app is
- * authorized to manage any active subscription on any SIM. Without it, an
- * {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback
- * intent to prompt the user to accept the download. The caller should also be authorized to
- * manage the subscription to be enabled.
+ * <p> If the caller is passing invalid port index,
+ * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_ERROR} with detailed error code
+ * {@link #ERROR_INVALID_PORT} will be returned.
+ *
+ * <p> Depending on the target port and permission check,
+ * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} might be returned to the callback
+ * intent to prompt the user to authorize before the switch.
*
* @param subscriptionId the ID of the subscription to enable. May be
* {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID} to deactivate the
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/test-base/Android.bp b/test-base/Android.bp
index 97ebba6..8be7324 100644
--- a/test-base/Android.bp
+++ b/test-base/Android.bp
@@ -26,7 +26,19 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
// SPDX-license-identifier-CPL-1.0
- default_applicable_licenses: ["frameworks_base_license"],
+ default_applicable_licenses: ["frameworks_base_test-base_license"],
+}
+
+license {
+ name: "frameworks_base_test-base_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-CPL-1.0",
+ ],
+ license_text: [
+ "src/junit/cpl-v10.html",
+ ],
}
java_sdk_library {
diff --git a/test-runner/Android.bp b/test-runner/Android.bp
index 0f56bb3..2a19af9 100644
--- a/test-runner/Android.bp
+++ b/test-runner/Android.bp
@@ -18,12 +18,19 @@
// =====================================
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
- // SPDX-license-identifier-CPL-1.0
- default_applicable_licenses: ["frameworks_base_license"],
+ default_applicable_licenses: ["frameworks_base_test-runner_license"],
+}
+
+license {
+ name: "frameworks_base_test-runner_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ "SPDX-license-identifier-CPL-1.0",
+ ],
+ license_text: [
+ "src/junit/cpl-v10.html",
+ ],
}
java_sdk_library {
diff --git a/tools/sdkparcelables/Android.bp b/tools/sdkparcelables/Android.bp
index 9d773e4..ec2bffd 100644
--- a/tools/sdkparcelables/Android.bp
+++ b/tools/sdkparcelables/Android.bp
@@ -14,7 +14,7 @@
"src/**/*.kt",
],
static_libs: [
- "asm-6.0",
+ "asm-7.0",
],
}
diff --git a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
index 22e8d78..0fb062f 100644
--- a/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
+++ b/tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
@@ -39,7 +39,7 @@
kotlin.system.exitProcess(2)
}
- val ancestorCollector = AncestorCollector(Opcodes.ASM6, null)
+ val ancestorCollector = AncestorCollector(Opcodes.ASM7, null)
for (entry in zipFile.entries()) {
if (entry.name.endsWith(".class")) {