Merge "NetdEventListenerService extends BaseNetdEventListener"
diff --git a/ProtoLibraries.bp b/ProtoLibraries.bp
index c12f5b4..a0944d4 100644
--- a/ProtoLibraries.bp
+++ b/ProtoLibraries.bp
@@ -100,6 +100,8 @@
],
type: "full",
},
+ // b/267831518: Pin tradefed and dependencies to Java 11.
+ java_version: "11",
// Protos have lots of MissingOverride and similar.
errorprone: {
enabled: false,
diff --git a/StubLibraries.bp b/StubLibraries.bp
index fc046fb..d043464 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -530,11 +530,17 @@
extensions_info_file: ":sdk-extensions-info",
}
+// This module can be built with:
+// m out/soong/.intermediates/frameworks/base/api_versions_module_lib/android_common/metalava/api-versions.xml
droidstubs {
name: "api_versions_module_lib",
srcs: [":android_module_stubs_current_with_test_libs{.jar}"],
generate_stubs: false,
api_levels_annotations_enabled: true,
+ // this only has the non-updatable portions of the module lib sdk,
+ // which can reference classes from updatable apexes, so remove references to them
+ // from this api_versions file.
+ flags: ["--remove-missing-class-references-in-api-levels"],
api_levels_annotations_dirs: [
"sdk-dir",
"api-versions-jars-dir",
@@ -548,6 +554,10 @@
srcs: [":android_system_server_stubs_current_with_test_libs{.jar}"],
generate_stubs: false,
api_levels_annotations_enabled: true,
+ // this only has the non-updatable portions of the system server sdk,
+ // which can reference classes from updatable apexes, so remove references to them
+ // from this api_versions file.
+ flags: ["--remove-missing-class-references-in-api-levels"],
api_levels_annotations_dirs: [
"sdk-dir",
"api-versions-jars-dir",
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index 20869e0..eea607b 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -4,12 +4,12 @@
# ActivityManager
per-file ActivityManager* = file:/services/core/java/com/android/server/am/OWNERS
+per-file *ApplicationStartInfo* = file:/services/core/java/com/android/server/am/OWNERS
per-file ApplicationErrorReport* = file:/services/core/java/com/android/server/am/OWNERS
per-file ApplicationExitInfo* = file:/services/core/java/com/android/server/am/OWNERS
per-file Application.java = file:/services/core/java/com/android/server/am/OWNERS
per-file ApplicationLoaders.java = file:/services/core/java/com/android/server/am/OWNERS
per-file ApplicationThreadConstants.java = file:/services/core/java/com/android/server/am/OWNERS
-per-file BroadcastOptions.java = file:/services/core/java/com/android/server/am/OWNERS
per-file ContentProviderHolder* = file:/services/core/java/com/android/server/am/OWNERS
per-file *ForegroundService* = file:/services/core/java/com/android/server/am/OWNERS
per-file IActivityController.aidl = file:/services/core/java/com/android/server/am/OWNERS
@@ -50,6 +50,10 @@
# Backup and Restore
per-file IBackupAgent.aidl = file:/services/backup/OWNERS
+# Broadcasts
+per-file Broadcast* = file:/BROADCASTS_OWNERS
+per-file ReceiverInfo* = file:/BROADCASTS_OWNERS
+
# LocaleManager
per-file *Locale* = file:/services/core/java/com/android/server/locales/OWNERS
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 861a850..331a5ab 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -3467,7 +3467,7 @@
* <p>An array of mandatory stream combinations which are applicable when device support the
* 10-bit output capability
* {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT }
- * This is an app-readable conversion of the maximum resolution mandatory stream combination
+ * This is an app-readable conversion of the 10 bit output mandatory stream combination
* {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
@@ -3492,7 +3492,7 @@
/**
* <p>An array of mandatory stream combinations which are applicable when device lists
* {@code PREVIEW_STABILIZATION} in {@link CameraCharacteristics#CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES android.control.availableVideoStabilizationModes}.
- * This is an app-readable conversion of the maximum resolution mandatory stream combination
+ * This is an app-readable conversion of the preview stabilization mandatory stream combination
* {@link android.hardware.camera2.CameraDevice#createCaptureSession tables}.</p>
* <p>The array of
* {@link android.hardware.camera2.params.MandatoryStreamCombination combinations} is
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index c8dc2d0..b52daab 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -528,8 +528,15 @@
boolean status = true;
synchronized (mInterfaceLock) {
try {
- mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
- mInitialized = true;
+ if (mSessionProcessor != null) {
+ mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
+ mInitialized = true;
+ } else {
+ Log.v(TAG, "Failed to start capture session, session released before " +
+ "extension start!");
+ status = false;
+ mCaptureSession.close();
+ }
} catch (RemoteException e) {
Log.e(TAG, "Failed to start capture session,"
+ " extension service does not respond!");
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 6a42091..ac3344e 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -265,12 +265,16 @@
* @return whether AIDs in the category can be handled by a service
* specified by the foreground app.
*/
+ @SuppressWarnings("NonUserGetterCalled")
public boolean categoryAllowsForegroundPreference(String category) {
if (CATEGORY_PAYMENT.equals(category)) {
boolean preferForeground = false;
+ Context contextAsUser = mContext.createContextAsUser(
+ UserHandle.of(UserHandle.myUserId()), 0);
try {
- preferForeground = Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NFC_PAYMENT_FOREGROUND, UserHandle.myUserId()) != 0;
+ preferForeground = Settings.Secure.getInt(
+ contextAsUser.getContentResolver(),
+ Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
} catch (SettingNotFoundException e) {
}
return preferForeground;
diff --git a/core/java/android/service/notification/OWNERS b/core/java/android/service/notification/OWNERS
index debb493..bb0e6ab 100644
--- a/core/java/android/service/notification/OWNERS
+++ b/core/java/android/service/notification/OWNERS
@@ -1,6 +1,7 @@
# Bug component: 34005
juliacr@google.com
-pixel@google.com
+yurilin@google.com
+jeffdq@google.com
dsandler@android.com
dsandler@google.com
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index c218a0b..754178ab 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -77,6 +77,16 @@
"settings_app_allow_dark_theme_activation_at_bedtime";
/**
+ * Flag to decouple bluetooth LE Audio Broadcast from Unicast
+ * If the flag is true, the broadcast feature will be enabled when the phone
+ * is connected to the BLE device.
+ * If the flag is false, it is not necessary to connect the BLE device.
+ * @hide
+ */
+ public static final String SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST =
+ "settings_need_connected_ble_device_for_broadcast";
+
+ /**
* Hide back key in the Settings two pane design.
* @hide
*/
@@ -110,6 +120,7 @@
DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "true");
DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
+ DEFAULT_FLAGS.put(SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, "true");
}
private static final Set<String> PERSISTENT_FLAGS;
diff --git a/core/java/com/android/internal/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index 69660ae..0d02683 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -6,6 +6,8 @@
per-file *EmptyStateProvider.java = file:/packages/SystemUI/OWNERS
per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
per-file *BatteryStats* = file:/BATTERY_STATS_OWNERS
+per-file *SoundTrigger* = file:/media/java/android/media/soundtrigger/OWNERS
+
# Voice Interaction
per-file *Assist* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/com/android/internal/expresslog/Histogram.java b/core/java/com/android/internal/expresslog/Histogram.java
index fe950c4..db70cac 100644
--- a/core/java/com/android/internal/expresslog/Histogram.java
+++ b/core/java/com/android/internal/expresslog/Histogram.java
@@ -20,7 +20,7 @@
import com.android.internal.util.FrameworkStatsLog;
-/** CounterHistogram encapsulates StatsD write API calls */
+/** Histogram encapsulates StatsD write API calls */
public final class Histogram {
private final long mMetricIdHash;
@@ -42,10 +42,10 @@
/*count*/ 1, binIndex);
}
- /** Used by CounterHistogram to map data sample to corresponding bin */
+ /** Used by Histogram to map data sample to corresponding bin */
public interface BinOptions {
/**
- * Returns bins count to be used by counter histogram
+ * Returns bins count to be used by a histogram
*
* @return bins count used to initialize Options, including overflow & underflow bins
* @hide
@@ -62,7 +62,7 @@
int getBinForSample(float sample);
}
- /** Used by CounterHistogram to map data sample to corresponding bin for on uniform bins */
+ /** Used by Histogram to map data sample to corresponding bin for uniform bins */
public static final class UniformOptions implements BinOptions {
private final int mBinCount;
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 1fd0410..d192ad9 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -39,8 +39,7 @@
import java.util.function.IntFunction;
/**
- * ArrayUtils contains some methods that you can call to find out
- * the most efficient increments by which to grow arrays.
+ * Static utility methods for arrays that aren't already included in {@link java.util.Arrays}.
*/
public class ArrayUtils {
private static final int CACHE_SIZE = 73;
@@ -341,15 +340,16 @@
}
/**
- * Combine multiple arrays into a single array.
+ * Returns the concatenation of the given arrays. Only works for object arrays, not for
+ * primitive arrays. See {@link #concat(byte[]...)} for a variant that works on byte arrays.
*
* @param kind The class of the array elements
- * @param arrays The arrays to combine
+ * @param arrays The arrays to concatenate. Null arrays are treated as empty.
* @param <T> The class of the array elements (inferred from kind).
* @return A single array containing all the elements of the parameter arrays.
*/
@SuppressWarnings("unchecked")
- public static @NonNull <T> T[] concatElements(Class<T> kind, @Nullable T[]... arrays) {
+ public static @NonNull <T> T[] concat(Class<T> kind, @Nullable T[]... arrays) {
if (arrays == null || arrays.length == 0) {
return createEmptyArray(kind);
}
@@ -390,6 +390,29 @@
return (T[]) Array.newInstance(kind, 0);
}
+ /**
+ * Returns the concatenation of the given byte arrays. Null arrays are treated as empty.
+ */
+ public static @NonNull byte[] concat(@Nullable byte[]... arrays) {
+ if (arrays == null) {
+ return new byte[0];
+ }
+ int totalLength = 0;
+ for (byte[] a : arrays) {
+ if (a != null) {
+ totalLength += a.length;
+ }
+ }
+ final byte[] result = new byte[totalLength];
+ int pos = 0;
+ for (byte[] a : arrays) {
+ if (a != null) {
+ System.arraycopy(a, 0, result, pos, a.length);
+ pos += a.length;
+ }
+ }
+ return result;
+ }
/**
* Adds value to given array if not already present, providing set-like
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 963a83e..fad9e0e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1923,15 +1923,16 @@
const char* nice_name_ptr = nice_name.has_value() ? nice_name.value().c_str() : nullptr;
android_mallopt_gwp_asan_options_t gwp_asan_options;
+ const char* kGwpAsanAppRecoverableSysprop =
+ "persist.device_config.memory_safety_native.gwp_asan_recoverable_apps";
// The system server doesn't have its nice name set by the time SpecializeCommon is called.
gwp_asan_options.program_name = nice_name_ptr ?: process_name;
switch (runtime_flags & RuntimeFlags::GWP_ASAN_LEVEL_MASK) {
default:
case RuntimeFlags::GWP_ASAN_LEVEL_DEFAULT:
- // TODO(b/247012630): Switch this to Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING once
- // performance and syshealth testing is completed, making the default for non-system
- // apps that don't specify a `gwpAsanMode` in their manifest to be sampled-recoverable.
- gwp_asan_options.desire = Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
+ gwp_asan_options.desire = GetBoolProperty(kGwpAsanAppRecoverableSysprop, true)
+ ? Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING
+ : Action::DONT_TURN_ON_UNLESS_OVERRIDDEN;
android_mallopt(M_INITIALIZE_GWP_ASAN, &gwp_asan_options, sizeof(gwp_asan_options));
break;
case RuntimeFlags::GWP_ASAN_LEVEL_NEVER:
diff --git a/core/proto/android/app/OWNERS b/core/proto/android/app/OWNERS
index 4d76aee..a137ea9 100644
--- a/core/proto/android/app/OWNERS
+++ b/core/proto/android/app/OWNERS
@@ -1,2 +1,3 @@
+per-file appstartinfo.proto = file:/services/core/java/com/android/server/am/OWNERS
per-file location_time_zone_manager.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
per-file time_zone_detector.proto = file:platform/frameworks/base:/services/core/java/com/android/server/timezonedetector/OWNERS
diff --git a/core/proto/android/server/OWNERS b/core/proto/android/server/OWNERS
index 72d39bf..c6d3cda 100644
--- a/core/proto/android/server/OWNERS
+++ b/core/proto/android/server/OWNERS
@@ -1 +1,2 @@
+per-file activitymanagerservice.proto = file:/services/core/java/com/android/server/am/OWNERS
per-file window*.proto = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/android/credentials/OWNERS b/core/tests/coretests/src/android/credentials/OWNERS
new file mode 100644
index 0000000..00b5e06
--- /dev/null
+++ b/core/tests/coretests/src/android/credentials/OWNERS
@@ -0,0 +1,2 @@
+include /core/java/android/credentials/OWNERS
+
diff --git a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
index cb30b3f..c66a743 100644
--- a/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
@@ -16,8 +16,6 @@
package com.android.internal.util;
-import static com.android.internal.util.ArrayUtils.concatElements;
-
import static org.junit.Assert.assertArrayEquals;
import junit.framework.TestCase;
@@ -156,61 +154,107 @@
ArrayUtils.removeLong(new long[] { 1, 2, 3, 1 }, 1));
}
- public void testConcatEmpty() throws Exception {
- assertArrayEquals(new Long[] {},
- concatElements(Long.class, null, null));
- assertArrayEquals(new Long[] {},
- concatElements(Long.class, new Long[] {}, null));
- assertArrayEquals(new Long[] {},
- concatElements(Long.class, null, new Long[] {}));
- assertArrayEquals(new Long[] {},
- concatElements(Long.class, new Long[] {}, new Long[] {}));
+ public void testConcat_zeroObjectArrays() {
+ // empty varargs array
+ assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class));
+ // null varargs array
+ assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, (String[][]) null));
}
- public void testconcatElements() throws Exception {
+ public void testConcat_oneObjectArray() {
+ assertArrayEquals(new String[] { "1", "2" },
+ ArrayUtils.concat(String.class, new String[] { "1", "2" }));
+ }
+
+ public void testConcat_oneEmptyObjectArray() {
+ assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, (String[]) null));
+ assertArrayEquals(new String[] {}, ArrayUtils.concat(String.class, new String[] {}));
+ }
+
+ public void testConcat_twoObjectArrays() {
assertArrayEquals(new Long[] { 1L },
- concatElements(Long.class, new Long[] { 1L }, new Long[] {}));
+ ArrayUtils.concat(Long.class, new Long[] { 1L }, new Long[] {}));
assertArrayEquals(new Long[] { 1L },
- concatElements(Long.class, new Long[] {}, new Long[] { 1L }));
+ ArrayUtils.concat(Long.class, new Long[] {}, new Long[] { 1L }));
assertArrayEquals(new Long[] { 1L, 2L },
- concatElements(Long.class, new Long[] { 1L }, new Long[] { 2L }));
+ ArrayUtils.concat(Long.class, new Long[] { 1L }, new Long[] { 2L }));
assertArrayEquals(new Long[] { 1L, 2L, 3L, 4L },
- concatElements(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L }));
+ ArrayUtils.concat(Long.class, new Long[] { 1L, 2L }, new Long[] { 3L, 4L }));
}
- public void testConcatElements_threeWay() {
+ public void testConcat_twoEmptyObjectArrays() {
+ assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, null, null));
+ assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, new Long[] {}, null));
+ assertArrayEquals(new Long[] {}, ArrayUtils.concat(Long.class, null, new Long[] {}));
+ assertArrayEquals(new Long[] {},
+ ArrayUtils.concat(Long.class, new Long[] {}, new Long[] {}));
+ }
+
+ public void testConcat_threeObjectArrays() {
String[] array1 = { "1", "2" };
String[] array2 = { "3", "4" };
String[] array3 = { "5", "6" };
- String[] expectation = {"1", "2", "3", "4", "5", "6"};
+ String[] expectation = { "1", "2", "3", "4", "5", "6" };
- String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3);
- assertArrayEquals(expectation, concatResult);
+ assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3));
}
-
- public void testConcatElements_threeWayWithNull() {
+ public void testConcat_threeObjectArraysWithNull() {
String[] array1 = { "1", "2" };
String[] array2 = null;
String[] array3 = { "5", "6" };
- String[] expectation = {"1", "2", "5", "6"};
+ String[] expectation = { "1", "2", "5", "6" };
- String[] concatResult = ArrayUtils.concatElements(String.class, array1, array2, array3);
- assertArrayEquals(expectation, concatResult);
+ assertArrayEquals(expectation, ArrayUtils.concat(String.class, array1, array2, array3));
}
- public void testConcatElements_zeroElements() {
- String[] expectation = new String[0];
-
- String[] concatResult = ArrayUtils.concatElements(String.class);
- assertArrayEquals(expectation, concatResult);
+ public void testConcat_zeroByteArrays() {
+ // empty varargs array
+ assertArrayEquals(new byte[] {}, ArrayUtils.concat());
+ // null varargs array
+ assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[][]) null));
}
- public void testConcatElements_oneNullElement() {
- String[] expectation = new String[0];
-
- String[] concatResult = ArrayUtils.concatElements(String.class, null);
- assertArrayEquals(expectation, concatResult);
+ public void testConcat_oneByteArray() {
+ assertArrayEquals(new byte[] { 1, 2 }, ArrayUtils.concat(new byte[] { 1, 2 }));
}
+ public void testConcat_oneEmptyByteArray() {
+ assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null));
+ assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}));
+ }
+
+ public void testConcat_twoByteArrays() {
+ assertArrayEquals(new byte[] { 1 }, ArrayUtils.concat(new byte[] { 1 }, new byte[] {}));
+ assertArrayEquals(new byte[] { 1 }, ArrayUtils.concat(new byte[] {}, new byte[] { 1 }));
+ assertArrayEquals(new byte[] { 1, 2 },
+ ArrayUtils.concat(new byte[] { 1 }, new byte[] { 2 }));
+ assertArrayEquals(new byte[] { 1, 2, 3, 4 },
+ ArrayUtils.concat(new byte[] { 1, 2 }, new byte[] { 3, 4 }));
+ }
+
+ public void testConcat_twoEmptyByteArrays() {
+ assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null, null));
+ assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}, null));
+ assertArrayEquals(new byte[] {}, ArrayUtils.concat((byte[]) null, new byte[] {}));
+ assertArrayEquals(new byte[] {}, ArrayUtils.concat(new byte[] {}, new byte[] {}));
+ }
+
+ public void testConcat_threeByteArrays() {
+ byte[] array1 = { 1, 2 };
+ byte[] array2 = { 3, 4 };
+ byte[] array3 = { 5, 6 };
+ byte[] expectation = { 1, 2, 3, 4, 5, 6 };
+
+ assertArrayEquals(expectation, ArrayUtils.concat(array1, array2, array3));
+ }
+
+ public void testConcat_threeByteArraysWithNull() {
+ byte[] array1 = { 1, 2 };
+ byte[] array2 = null;
+ byte[] array3 = { 5, 6 };
+ byte[] expectation = { 1, 2, 5, 6 };
+
+ assertArrayEquals(expectation, ArrayUtils.concat(array1, array2, array3));
+ }
}
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 663e8e4..9108449 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -116,6 +116,36 @@
<item>full</item>
</string-array>
+ <!-- Titles for Bluetooth HCI Snoop Filtered Logging -->
+ <string-array name="bt_hci_snoop_log_filters_entries">
+ <item>Headers Filtered</item>
+ <item>A2DP Media Packets Filtered</item>
+ <item>RFCOMM Channel Filtered</item>
+ </string-array>
+
+ <!-- Values for Bluetooth HCI Snoop Filtered Logging -->
+ <string-array name="bt_hci_snoop_log_filters_values" translatable="false">
+ <item>headers</item>
+ <item>profiles.a2dp</item>
+ <item>profiles.rfcomm</item>
+ </string-array>
+
+ <!-- Titles for Bluetooth HCI Snoop Filtered Logging -->
+ <string-array name="bt_hci_snoop_log_profile_filter_entries">
+ <item>Disabled</item>
+ <item>Magic</item>
+ <item>Header</item>
+ <item>Full Filter</item>
+ </string-array>
+
+ <!-- Values for Bluetooth HCI Snoop Filtered Logging -->
+ <string-array name="bt_hci_snoop_log_profile_filter_values" translatable="false">
+ <item>disabled</item>
+ <item>magic</item>
+ <item>header</item>
+ <item>fullfilter</item>
+ </string-array>
+
<!-- Titles for Bluetooth AVRCP Versions -->
<string-array name="bluetooth_avrcp_versions">
<item>AVRCP 1.5 (Default)</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
index 1a65717..1940986 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -236,7 +236,7 @@
/**
* @return whether high quality audio is enabled or not
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public boolean isHighQualityAudioEnabled(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
if (bluetoothDevice == null) {
@@ -288,7 +288,7 @@
* @param device to get codec label from
* @return the label associated with the device codec
*/
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
public String getHighQualityAudioOptionLabel(BluetoothDevice device) {
BluetoothDevice bluetoothDevice = (device != null) ? device : getActiveDevice();
int unknownCodecId = R.string.bluetooth_profile_a2dp_high_quality_unknown_codec;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index d3afccc..6aa08f2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -875,16 +875,16 @@
String[] whitelist;
Map<String, Validator> validators = null;
if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
- whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP,
+ whitelist = ArrayUtils.concat(String.class, SecureSettings.SETTINGS_TO_BACKUP,
Settings.Secure.LEGACY_RESTORE_SETTINGS,
DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
validators = SecureSettingsValidators.VALIDATORS;
} else if (contentUri.equals(Settings.System.CONTENT_URI)) {
- whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP,
+ whitelist = ArrayUtils.concat(String.class, SystemSettings.SETTINGS_TO_BACKUP,
Settings.System.LEGACY_RESTORE_SETTINGS);
validators = SystemSettingsValidators.VALIDATORS;
} else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
- whitelist = ArrayUtils.concatElements(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
+ whitelist = ArrayUtils.concat(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
Settings.Global.LEGACY_RESTORE_SETTINGS);
validators = GlobalSettingsValidators.VALIDATORS;
} else {
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 53f1227..422b049 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2348,7 +2348,10 @@
<string name="media_output_broadcast_update_error">Can\u2019t save. Try again.</string>
<!-- The error message when Broadcast name/code update failed and can't change again[CHAR LIMIT=60] -->
<string name="media_output_broadcast_last_update_error">Can\u2019t save.</string>
-
+ <!-- The hint message when Broadcast code is less than 4 characters [CHAR LIMIT=60] -->
+ <string name="media_output_broadcast_code_hint_no_less_than_min">Use at least 4 characters</string>
+ <!-- The hint message when Broadcast code is more than 16 characters [CHAR LIMIT=60] -->
+ <string name="media_output_broadcast_code_hint_no_more_than_max">Use fewer than 16 characters</string>
<!-- Label for clip data when copying the build number off QS [CHAR LIMIT=NONE]-->
<string name="build_number_clip_data_label">Build number</string>
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
index 35baf013..12d6b7c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialog.java
@@ -20,6 +20,8 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
import android.text.method.HideReturnsTransformationMethod;
import android.text.method.PasswordTransformationMethod;
import android.util.Log;
@@ -64,11 +66,51 @@
private String mCurrentBroadcastName;
private String mCurrentBroadcastCode;
private boolean mIsStopbyUpdateBroadcastCode = false;
+ private TextWatcher mTextWatcher = new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // Do nothing
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ // Do nothing
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ if (mAlertDialog == null || mBroadcastErrorMessage == null) {
+ return;
+ }
+ boolean breakBroadcastCodeRuleTextLengthLessThanMin =
+ s.length() > 0 && s.length() < BROADCAST_CODE_MIN_LENGTH;
+ boolean breakBroadcastCodeRuleTextLengthMoreThanMax =
+ s.length() > BROADCAST_CODE_MAX_LENGTH;
+ boolean breakRule = breakBroadcastCodeRuleTextLengthLessThanMin
+ || breakBroadcastCodeRuleTextLengthMoreThanMax;
+
+ if (breakBroadcastCodeRuleTextLengthLessThanMin) {
+ mBroadcastErrorMessage.setText(
+ R.string.media_output_broadcast_code_hint_no_less_than_min);
+ } else if (breakBroadcastCodeRuleTextLengthMoreThanMax) {
+ mBroadcastErrorMessage.setText(
+ R.string.media_output_broadcast_code_hint_no_more_than_max);
+ }
+
+ mBroadcastErrorMessage.setVisibility(breakRule ? View.VISIBLE : View.INVISIBLE);
+ Button positiveBtn = mAlertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
+ if (positiveBtn != null) {
+ positiveBtn.setEnabled(breakRule ? false : true);
+ }
+ }
+ };
static final int METADATA_BROADCAST_NAME = 0;
static final int METADATA_BROADCAST_CODE = 1;
private static final int MAX_BROADCAST_INFO_UPDATE = 3;
+ private static final int BROADCAST_CODE_MAX_LENGTH = 16;
+ private static final int BROADCAST_CODE_MIN_LENGTH = 4;
MediaOutputBroadcastDialog(Context context, boolean aboveStatusbar,
BroadcastSender broadcastSender, MediaOutputController mediaOutputController) {
@@ -219,6 +261,9 @@
R.layout.media_output_broadcast_update_dialog, null);
final EditText editText = layout.requireViewById(R.id.broadcast_edit_text);
editText.setText(editString);
+ if (isBroadcastCode) {
+ editText.addTextChangedListener(mTextWatcher);
+ }
mBroadcastErrorMessage = layout.requireViewById(R.id.broadcast_error_message);
mAlertDialog = new Builder(mContext)
.setTitle(isBroadcastCode ? R.string.media_output_broadcast_code
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index fbd0079..a174b45 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.Bundle;
+import android.util.FeatureFlagUtils;
import android.view.View;
import android.view.WindowManager;
@@ -99,10 +100,18 @@
@Override
public boolean isBroadcastSupported() {
boolean isBluetoothLeDevice = false;
- if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
- isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
+ if (FeatureFlagUtils.isEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST)) {
+ if (mMediaOutputController.getCurrentConnectedMediaDevice() != null) {
+ isBluetoothLeDevice = mMediaOutputController.isBluetoothLeDevice(
mMediaOutputController.getCurrentConnectedMediaDevice());
+ }
+ } else {
+ // To decouple LE Audio Broadcast and Unicast, it always displays the button when there
+ // is no LE Audio device connected to the phone
+ isBluetoothLeDevice = true;
}
+
return mMediaOutputController.isBroadcastSupported() && isBluetoothLeDevice;
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 198d022..c63b3b3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1128,13 +1128,13 @@
rescheduleTimeoutH();
}
- if (mODICaptionsTooltipView != null) {
- mODICaptionsTooltipView.setAlpha(0.0f);
+ // We need to wait for layout and then center the caption view. Since the height of the
+ // dialog is now dynamic (with the variable ringer drawer height changing the height of
+ // the dialog), we need to do this here in code vs. in XML.
+ mHandler.post(() -> {
+ if (mODICaptionsTooltipView != null) {
+ mODICaptionsTooltipView.setAlpha(0.0f);
- // We need to wait for layout and then center the caption view. Since the height of the
- // dialog is now dynamic (with the variable ringer drawer height changing the height of
- // the dialog), we need to do this here in code vs. in XML.
- mHandler.post(() -> {
final int[] odiTooltipLocation = mODICaptionsTooltipView.getLocationOnScreen();
final int[] odiButtonLocation = mODICaptionsIcon.getLocationOnScreen();
@@ -1160,8 +1160,8 @@
}
})
.start();
- });
- }
+ }
+ });
}
private void hideCaptionsTooltip() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
index bae3569..a9246f7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -36,6 +36,7 @@
import android.os.PowerExemptionManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.util.FeatureFlagUtils;
import android.view.View;
import androidx.test.filters.SmallTest;
@@ -169,6 +170,8 @@
mLocalBluetoothLeBroadcast);
when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
when(mPlaybackState.getState()).thenReturn(PlaybackState.STATE_PLAYING);
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
when(mMediaDevice.isBLEDevice()).thenReturn(false);
assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.GONE);
@@ -182,6 +185,62 @@
}
@Test
+ public void isBroadcastSupported_flagOnAndConnectBleDevice_returnsTrue() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+ when(mMediaDevice.isBLEDevice()).thenReturn(true);
+
+ assertThat(mMediaOutputDialog.isBroadcastSupported()).isTrue();
+ }
+
+ @Test
+ public void isBroadcastSupported_flagOnAndNoBleDevice_returnsFalse() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+ when(mMediaDevice.isBLEDevice()).thenReturn(false);
+
+ assertThat(mMediaOutputDialog.isBroadcastSupported()).isFalse();
+ }
+
+ @Test
+ public void isBroadcastSupported_notSupportBroadcastAndflagOn_returnsFalse() {
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, true);
+
+ assertThat(mMediaOutputDialog.isBroadcastSupported()).isFalse();
+ }
+
+ @Test
+ public void isBroadcastSupported_flagOffAndConnectToBleDevice_returnsTrue() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, false);
+ when(mMediaDevice.isBLEDevice()).thenReturn(true);
+
+ assertThat(mMediaOutputDialog.isBroadcastSupported()).isTrue();
+ }
+
+ @Test
+ public void isBroadcastSupported_flagOffAndNoBleDevice_returnsTrue() {
+ when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
+ mLocalBluetoothLeBroadcast);
+ when(mLocalBluetoothLeBroadcast.isEnabled(any())).thenReturn(false);
+ FeatureFlagUtils.setEnabled(mContext,
+ FeatureFlagUtils.SETTINGS_NEED_CONNECTED_BLE_DEVICE_FOR_BROADCAST, false);
+ when(mMediaDevice.isBLEDevice()).thenReturn(false);
+
+ assertThat(mMediaOutputDialog.isBroadcastSupported()).isTrue();
+ }
+
+ @Test
public void getBroadcastIconVisibility_isBroadcasting_returnVisible() {
when(mLocalBluetoothProfileManager.getLeAudioBroadcastProfile()).thenReturn(
mLocalBluetoothLeBroadcast);
diff --git a/rs/java/android/renderscript/package.html b/rs/java/android/renderscript/package.html
index eb178c1..8179928 100644
--- a/rs/java/android/renderscript/package.html
+++ b/rs/java/android/renderscript/package.html
@@ -1,9 +1,9 @@
<HTML>
<BODY>
-<p>RenderScript provides support for high-performance computation across heterogeneous processors.</p>
+<p>Renderscript is deprecated since API level 31. Please refer to the
+<a href="https://developer.android.com/guide/topics/renderscript/migration-guide">migration guide</a>
+for alternatives.
-<p>For more information, see the
-<a href="{@docRoot}guide/topics/renderscript/index.html">RenderScript</a> developer guide.</p>
{@more}
</BODY>
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5c11e2c..9c1933d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -3840,8 +3840,7 @@
&& (mSessionFlags.mAugmentedAutofillOnly
|| !mSessionFlags.mInlineSupportedByService
|| mSessionFlags.mExpiredResponse)
- && isViewFocusedLocked(flags)
- || isFillDialogUiEnabled()) {
+ && (isViewFocusedLocked(flags) || isRequestSupportFillDialog(flags))) {
if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill");
remoteRenderService.getInlineSuggestionsRendererInfo(new RemoteCallback(
(extras) -> {
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 1d457aa..2fa18af 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -693,7 +693,7 @@
out.append(file.getPath()).append("\n");
}
- if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && (doPrint || !doFile)) {
+ if ((entry.flags & DropBoxManager.IS_TEXT) != 0 && doPrint) {
DropBoxManager.Entry dbe = null;
InputStreamReader isr = null;
try {
@@ -717,17 +717,6 @@
}
}
if (!newline) out.append("\n");
- } else {
- String text = dbe.getText(70);
- out.append(" ");
- if (text == null) {
- out.append("[null]");
- } else {
- boolean truncated = (text.length() == 70);
- out.append(text.trim().replace('\n', '/'));
- if (truncated) out.append(" ...");
- }
- out.append("\n");
}
} catch (IOException e) {
out.append("*** ").append(e.toString()).append("\n");
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 1fab28e..c7d8ab2 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -160,13 +160,21 @@
public static final String[] AIDL_INTERFACE_PREFIXES_OF_INTEREST = new String[] {
"android.hardware.biometrics.face.IFace/",
"android.hardware.biometrics.fingerprint.IFingerprint/",
+ "android.hardware.bluetooth.IBluetoothHci/",
+ "android.hardware.camera.provider.ICameraProvider/",
+ "android.hardware.gnss.IGnss/",
+ "android.hardware.graphics.allocator.IAllocator/",
"android.hardware.graphics.composer3.IComposer/",
+ "android.hardware.health.IHealth/",
"android.hardware.input.processor.IInputProcessor/",
"android.hardware.light.ILights/",
+ "android.hardware.neuralnetworks.IDevice/",
"android.hardware.power.IPower/",
"android.hardware.power.stats.IPowerStats/",
+ "android.hardware.sensors.ISensors/",
"android.hardware.vibrator.IVibrator/",
- "android.hardware.vibrator.IVibratorManager/"
+ "android.hardware.vibrator.IVibratorManager/",
+ "android.system.suspend.ISystemSuspend/",
};
private static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e0d324a..05915d9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2329,10 +2329,6 @@
Log.w(TAG, "audioFormat to enable is not a surround format.");
return false;
}
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Missing WRITE_SETTINGS permission");
- }
final long token = Binder.clearCallingIdentity();
try {
@@ -2400,11 +2396,6 @@
/** @see AudioManager#getEncodedSurroundMode() */
@Override
public int getEncodedSurroundMode(int targetSdkVersion) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Missing WRITE_SETTINGS permission");
- }
-
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSettingsLock) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
index c22091b..2c0e909 100644
--- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -34,6 +34,7 @@
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -46,6 +47,7 @@
import com.android.internal.os.ByteTransferPipe;
import com.android.internal.protolog.ProtoLogImpl;
+import com.android.server.IoThread;
import com.android.server.wm.LetterboxConfiguration.LetterboxBackgroundType;
import com.android.server.wm.LetterboxConfiguration.LetterboxHorizontalReachabilityPosition;
import com.android.server.wm.LetterboxConfiguration.LetterboxVerticalReachabilityPosition;
@@ -571,8 +573,22 @@
ByteTransferPipe pipe = null;
try {
pipe = new ByteTransferPipe();
- w.mClient.executeCommand(ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null,
- pipe.getWriteFd());
+ final ParcelFileDescriptor pfd = pipe.getWriteFd();
+ if (w.isClientLocal()) {
+ // Make it asynchronous to avoid writer from being blocked
+ // by waiting for the buffer to be consumed in the same process.
+ IoThread.getExecutor().execute(() -> {
+ try {
+ w.mClient.executeCommand(
+ ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null, pfd);
+ } catch (RemoteException e) {
+ // Ignore for local call.
+ }
+ });
+ } else {
+ w.mClient.executeCommand(
+ ViewDebug.REMOTE_COMMAND_DUMP_ENCODED, null, pfd);
+ }
requestList.add(Pair.create(w.getName(), pipe));
} catch (IOException | RemoteException e) {
// Skip this window
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 432af3a..9c1e8dd 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -1839,8 +1839,15 @@
/**
* Instructs this {@code Call} to play a dual-tone multi-frequency signaling (DTMF) tone.
- *
- * Any other currently playing DTMF tone in the specified call is immediately stopped.
+ * <p>
+ * Tones are both played locally for the user to hear and sent to the network to be relayed
+ * to the remote device.
+ * <p>
+ * You must ensure that any call to {@link #playDtmfTone(char}) is followed by a matching
+ * call to {@link #stopDtmfTone()} and that each tone is stopped before a new one is started.
+ * The play and stop commands are relayed to the underlying
+ * {@link android.telecom.ConnectionService} as executed; implementations may not correctly
+ * handle out of order commands.
*
* @param digit A character representing the DTMF digit for which to play the tone. This
* value must be one of {@code '0'} through {@code '9'}, {@code '*'} or {@code '#'}.
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index bce6809..6afc400 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -2330,7 +2330,7 @@
}
private void playDtmfTone(String callId, char digit) {
- Log.i(this, "playDtmfTone %s %c", callId, digit);
+ Log.i(this, "playDtmfTone %s %s", callId, Log.pii(digit));
if (mConnectionById.containsKey(callId)) {
findConnectionForAction(callId, "playDtmfTone").onPlayDtmfTone(digit);
} else {