Loading android/app/src/com/android/bluetooth/Utils.java +112 −0 Original line number Diff line number Diff line Loading @@ -1288,6 +1288,8 @@ public final class Utils { * * <p>(copied from framework/base/core/java/android/text/TextUtils.java) * * <p>(See {@code android.text.TextUtils.truncateStringForUtf8Storage} * * @param str a string * @param maxbytes the maximum number of UTF-8 encoded bytes * @return the beginning of the string, so that it uses at most maxbytes bytes in UTF-8 Loading Loading @@ -1319,4 +1321,114 @@ public final class Utils { } return str; } /** * Simple alternative to {@link String#format} which purposefully supports only a small handful * of substitutions to improve execution speed. Benchmarking reveals this optimized alternative * performs 6.5x faster for a typical format string. * * <p>Below is a summary of the limited grammar supported by this method; if you need advanced * features, please continue using {@link String#format}. * * <ul> * <li>{@code %b} for {@code boolean} * <li>{@code %c} for {@code char} * <li>{@code %d} for {@code int} or {@code long} * <li>{@code %f} for {@code float} or {@code double} * <li>{@code %s} for {@code String} * <li>{@code %x} for hex representation of {@code int} or {@code long} * <li>{@code %%} for literal {@code %} * <li>{@code %04d} style grammar to specify the argument width, such as {@code %04d} to * prefix an {@code int} with zeros or {@code %10b} to prefix a {@code boolean} with * spaces * </ul> * * <p>(copied from framework/base/core/java/android/text/TextUtils.java) * * <p>See {@code android.text.TextUtils.formatSimple} * * @throws IllegalArgumentException if the format string or arguments don't match the supported * grammar described above. * @hide */ public static @NonNull String formatSimple(@NonNull String format, Object... args) { final StringBuilder sb = new StringBuilder(format); int j = 0; for (int i = 0; i < sb.length(); ) { if (sb.charAt(i) == '%') { char code = sb.charAt(i + 1); // Decode any argument width request char prefixChar = '\0'; int prefixLen = 0; int consume = 2; while ('0' <= code && code <= '9') { if (prefixChar == '\0') { prefixChar = (code == '0') ? '0' : ' '; } prefixLen *= 10; prefixLen += Character.digit(code, 10); consume += 1; code = sb.charAt(i + consume - 1); } final String repl; switch (code) { case 'b' -> { if (j == args.length) { throw new IllegalArgumentException("Too few arguments"); } final Object arg = args[j++]; if (arg instanceof Boolean) { repl = Boolean.toString((boolean) arg); } else { repl = Boolean.toString(arg != null); } } case 'c', 'd', 'f', 's' -> { if (j == args.length) { throw new IllegalArgumentException("Too few arguments"); } final Object arg = args[j++]; repl = String.valueOf(arg); } case 'x' -> { if (j == args.length) { throw new IllegalArgumentException("Too few arguments"); } final Object arg = args[j++]; if (arg instanceof Integer) { repl = Integer.toHexString((int) arg); } else if (arg instanceof Long) { repl = Long.toHexString((long) arg); } else { throw new IllegalArgumentException( "Unsupported hex type " + arg.getClass()); } } case '%' -> { repl = "%"; } default -> { throw new IllegalArgumentException("Unsupported format code " + code); } } sb.replace(i, i + consume, repl); // Apply any argument width request final int prefixInsert = (prefixChar == '0' && repl.charAt(0) == '-') ? 1 : 0; for (int k = repl.length(); k < prefixLen; k++) { sb.insert(i + prefixInsert, prefixChar); } i += Math.max(repl.length(), prefixLen); } else { i++; } } if (j != args.length) { throw new IllegalArgumentException("Too many arguments"); } return sb.toString(); } } android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java +5 −3 Original line number Diff line number Diff line Loading @@ -629,7 +629,8 @@ public class MediaPlayerList { int id = mMediaPlayerIds.get(browser.getPackageName()); Log.d(TAG, "getFolderItemsMediaPlayerList: Adding player " + displayName); Folder playerFolder = new Folder(String.format("%02d", id), false, displayName); Folder playerFolder = new Folder(Utils.formatSimple("%02d", id), false, displayName); playerList.add(new ListItem(playerFolder)); } } else { Loading @@ -639,7 +640,8 @@ public class MediaPlayerList { int id = mMediaPlayerIds.get(player.getPackageName()); Log.d(TAG, "getFolderItemsMediaPlayerList: Adding player " + displayName); Folder playerFolder = new Folder(String.format("%02d", id), false, displayName); Folder playerFolder = new Folder(Utils.formatSimple("%02d", id), false, displayName); playerList.add(new ListItem(playerFolder)); } } Loading Loading @@ -722,7 +724,7 @@ public class MediaPlayerList { return; } String playerPrefix = String.format("%02d", playerIndex); String playerPrefix = Utils.formatSimple("%02d", playerIndex); for (ListItem item : results) { if (item.isFolder) { item.folder.mediaId = playerPrefix.concat(item.folder.mediaId); Loading android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipDateTime.java +4 −5 Original line number Diff line number Diff line Loading @@ -16,9 +16,10 @@ package com.android.bluetooth.avrcpcontroller; import com.android.bluetooth.Utils; import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.Objects; import java.util.TimeZone; import java.util.regex.Matcher; Loading Loading @@ -134,8 +135,7 @@ public class BipDateTime { TimeZone utc = TimeZone.getTimeZone("UTC"); utc.setRawOffset(0); cal.setTimeZone(utc); return String.format( Locale.US, return Utils.formatSimple( "%04d%02d%02dT%02d%02d%02dZ", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, Loading @@ -145,8 +145,7 @@ public class BipDateTime { cal.get(Calendar.SECOND)); } else { cal.setTimeZone(TimeZone.getDefault()); return String.format( Locale.US, return Utils.formatSimple( "%04d%02d%02dT%02d%02d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +4 −13 Original line number Diff line number Diff line Loading @@ -2011,11 +2011,7 @@ public class AdapterService extends Service { private int startRfcommListener( String name, ParcelUuid uuid, PendingIntent pendingIntent, AttributionSource source) { if (mBluetoothServerSockets.containsKey(uuid.getUuid())) { Log.d( TAG, String.format( "Cannot start RFCOMM listener: UUID %s already in use.", uuid.getUuid())); Log.d(TAG, "Cannot start RFCOMM listener: UUID " + uuid.getUuid() + "already in use."); return BluetoothStatusCodes.RFCOMM_LISTENER_START_FAILED_UUID_IN_USE; } Loading @@ -2034,11 +2030,7 @@ public class AdapterService extends Service { RfcommListenerData listenerData = mBluetoothServerSockets.get(uuid.getUuid()); if (listenerData == null) { Log.d( TAG, String.format( "Cannot stop RFCOMM listener: UUID %s is not registered.", uuid.getUuid())); Log.d(TAG, "Cannot stop RFCOMM listener: UUID " + uuid.getUuid() + "is not registered"); return BluetoothStatusCodes.RFCOMM_LISTENER_OPERATION_FAILED_NO_MATCHING_SERVICE_RECORD; } Loading Loading @@ -6208,7 +6200,7 @@ public class AdapterService extends Service { + (" rxTime = " + rxTime) + (" idleTime = " + idleTime) + (" energyUsed = " + energyUsed) + (" ctrlState = " + String.format("0x%08x", ctrlState)) + (" ctrlState = " + Utils.formatSimple("0x%08x", ctrlState)) + (" traffic = " + Arrays.toString(data))); } Loading Loading @@ -6377,8 +6369,7 @@ public class AdapterService extends Service { ArrayList<String> initFlags = new ArrayList<>(); for (String property : properties.getKeyset()) { if (property.startsWith("INIT_")) { initFlags.add( String.format("%s=%s", property, properties.getString(property, null))); initFlags.add(property + "=" + properties.getString(property, null)); } } return initFlags.toArray(new String[0]); Loading android/app/src/com/android/bluetooth/btservice/CompanionManager.java +1 −5 Original line number Diff line number Diff line Loading @@ -249,11 +249,7 @@ public class CompanionManager { @Override public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { String valueStr = new String(value); Log.d( TAG, String.format( "Metadata updated in Device %s: %d = %s.", device, key, value == null ? null : valueStr)); Log.d(TAG, "Metadata updated in " + device + ": " + key + "=" + valueStr); if (key == BluetoothDevice.METADATA_SOFTWARE_VERSION && (valueStr.equals(BluetoothDevice.COMPANION_TYPE_PRIMARY) || valueStr.equals(BluetoothDevice.COMPANION_TYPE_SECONDARY))) { Loading Loading
android/app/src/com/android/bluetooth/Utils.java +112 −0 Original line number Diff line number Diff line Loading @@ -1288,6 +1288,8 @@ public final class Utils { * * <p>(copied from framework/base/core/java/android/text/TextUtils.java) * * <p>(See {@code android.text.TextUtils.truncateStringForUtf8Storage} * * @param str a string * @param maxbytes the maximum number of UTF-8 encoded bytes * @return the beginning of the string, so that it uses at most maxbytes bytes in UTF-8 Loading Loading @@ -1319,4 +1321,114 @@ public final class Utils { } return str; } /** * Simple alternative to {@link String#format} which purposefully supports only a small handful * of substitutions to improve execution speed. Benchmarking reveals this optimized alternative * performs 6.5x faster for a typical format string. * * <p>Below is a summary of the limited grammar supported by this method; if you need advanced * features, please continue using {@link String#format}. * * <ul> * <li>{@code %b} for {@code boolean} * <li>{@code %c} for {@code char} * <li>{@code %d} for {@code int} or {@code long} * <li>{@code %f} for {@code float} or {@code double} * <li>{@code %s} for {@code String} * <li>{@code %x} for hex representation of {@code int} or {@code long} * <li>{@code %%} for literal {@code %} * <li>{@code %04d} style grammar to specify the argument width, such as {@code %04d} to * prefix an {@code int} with zeros or {@code %10b} to prefix a {@code boolean} with * spaces * </ul> * * <p>(copied from framework/base/core/java/android/text/TextUtils.java) * * <p>See {@code android.text.TextUtils.formatSimple} * * @throws IllegalArgumentException if the format string or arguments don't match the supported * grammar described above. * @hide */ public static @NonNull String formatSimple(@NonNull String format, Object... args) { final StringBuilder sb = new StringBuilder(format); int j = 0; for (int i = 0; i < sb.length(); ) { if (sb.charAt(i) == '%') { char code = sb.charAt(i + 1); // Decode any argument width request char prefixChar = '\0'; int prefixLen = 0; int consume = 2; while ('0' <= code && code <= '9') { if (prefixChar == '\0') { prefixChar = (code == '0') ? '0' : ' '; } prefixLen *= 10; prefixLen += Character.digit(code, 10); consume += 1; code = sb.charAt(i + consume - 1); } final String repl; switch (code) { case 'b' -> { if (j == args.length) { throw new IllegalArgumentException("Too few arguments"); } final Object arg = args[j++]; if (arg instanceof Boolean) { repl = Boolean.toString((boolean) arg); } else { repl = Boolean.toString(arg != null); } } case 'c', 'd', 'f', 's' -> { if (j == args.length) { throw new IllegalArgumentException("Too few arguments"); } final Object arg = args[j++]; repl = String.valueOf(arg); } case 'x' -> { if (j == args.length) { throw new IllegalArgumentException("Too few arguments"); } final Object arg = args[j++]; if (arg instanceof Integer) { repl = Integer.toHexString((int) arg); } else if (arg instanceof Long) { repl = Long.toHexString((long) arg); } else { throw new IllegalArgumentException( "Unsupported hex type " + arg.getClass()); } } case '%' -> { repl = "%"; } default -> { throw new IllegalArgumentException("Unsupported format code " + code); } } sb.replace(i, i + consume, repl); // Apply any argument width request final int prefixInsert = (prefixChar == '0' && repl.charAt(0) == '-') ? 1 : 0; for (int k = repl.length(); k < prefixLen; k++) { sb.insert(i + prefixInsert, prefixChar); } i += Math.max(repl.length(), prefixLen); } else { i++; } } if (j != args.length) { throw new IllegalArgumentException("Too many arguments"); } return sb.toString(); } }
android/app/src/com/android/bluetooth/audio_util/MediaPlayerList.java +5 −3 Original line number Diff line number Diff line Loading @@ -629,7 +629,8 @@ public class MediaPlayerList { int id = mMediaPlayerIds.get(browser.getPackageName()); Log.d(TAG, "getFolderItemsMediaPlayerList: Adding player " + displayName); Folder playerFolder = new Folder(String.format("%02d", id), false, displayName); Folder playerFolder = new Folder(Utils.formatSimple("%02d", id), false, displayName); playerList.add(new ListItem(playerFolder)); } } else { Loading @@ -639,7 +640,8 @@ public class MediaPlayerList { int id = mMediaPlayerIds.get(player.getPackageName()); Log.d(TAG, "getFolderItemsMediaPlayerList: Adding player " + displayName); Folder playerFolder = new Folder(String.format("%02d", id), false, displayName); Folder playerFolder = new Folder(Utils.formatSimple("%02d", id), false, displayName); playerList.add(new ListItem(playerFolder)); } } Loading Loading @@ -722,7 +724,7 @@ public class MediaPlayerList { return; } String playerPrefix = String.format("%02d", playerIndex); String playerPrefix = Utils.formatSimple("%02d", playerIndex); for (ListItem item : results) { if (item.isFolder) { item.folder.mediaId = playerPrefix.concat(item.folder.mediaId); Loading
android/app/src/com/android/bluetooth/avrcpcontroller/bip/BipDateTime.java +4 −5 Original line number Diff line number Diff line Loading @@ -16,9 +16,10 @@ package com.android.bluetooth.avrcpcontroller; import com.android.bluetooth.Utils; import java.util.Calendar; import java.util.Date; import java.util.Locale; import java.util.Objects; import java.util.TimeZone; import java.util.regex.Matcher; Loading Loading @@ -134,8 +135,7 @@ public class BipDateTime { TimeZone utc = TimeZone.getTimeZone("UTC"); utc.setRawOffset(0); cal.setTimeZone(utc); return String.format( Locale.US, return Utils.formatSimple( "%04d%02d%02dT%02d%02d%02dZ", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, Loading @@ -145,8 +145,7 @@ public class BipDateTime { cal.get(Calendar.SECOND)); } else { cal.setTimeZone(TimeZone.getDefault()); return String.format( Locale.US, return Utils.formatSimple( "%04d%02d%02dT%02d%02d%02d", cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +4 −13 Original line number Diff line number Diff line Loading @@ -2011,11 +2011,7 @@ public class AdapterService extends Service { private int startRfcommListener( String name, ParcelUuid uuid, PendingIntent pendingIntent, AttributionSource source) { if (mBluetoothServerSockets.containsKey(uuid.getUuid())) { Log.d( TAG, String.format( "Cannot start RFCOMM listener: UUID %s already in use.", uuid.getUuid())); Log.d(TAG, "Cannot start RFCOMM listener: UUID " + uuid.getUuid() + "already in use."); return BluetoothStatusCodes.RFCOMM_LISTENER_START_FAILED_UUID_IN_USE; } Loading @@ -2034,11 +2030,7 @@ public class AdapterService extends Service { RfcommListenerData listenerData = mBluetoothServerSockets.get(uuid.getUuid()); if (listenerData == null) { Log.d( TAG, String.format( "Cannot stop RFCOMM listener: UUID %s is not registered.", uuid.getUuid())); Log.d(TAG, "Cannot stop RFCOMM listener: UUID " + uuid.getUuid() + "is not registered"); return BluetoothStatusCodes.RFCOMM_LISTENER_OPERATION_FAILED_NO_MATCHING_SERVICE_RECORD; } Loading Loading @@ -6208,7 +6200,7 @@ public class AdapterService extends Service { + (" rxTime = " + rxTime) + (" idleTime = " + idleTime) + (" energyUsed = " + energyUsed) + (" ctrlState = " + String.format("0x%08x", ctrlState)) + (" ctrlState = " + Utils.formatSimple("0x%08x", ctrlState)) + (" traffic = " + Arrays.toString(data))); } Loading Loading @@ -6377,8 +6369,7 @@ public class AdapterService extends Service { ArrayList<String> initFlags = new ArrayList<>(); for (String property : properties.getKeyset()) { if (property.startsWith("INIT_")) { initFlags.add( String.format("%s=%s", property, properties.getString(property, null))); initFlags.add(property + "=" + properties.getString(property, null)); } } return initFlags.toArray(new String[0]); Loading
android/app/src/com/android/bluetooth/btservice/CompanionManager.java +1 −5 Original line number Diff line number Diff line Loading @@ -249,11 +249,7 @@ public class CompanionManager { @Override public void onMetadataChanged(BluetoothDevice device, int key, byte[] value) { String valueStr = new String(value); Log.d( TAG, String.format( "Metadata updated in Device %s: %d = %s.", device, key, value == null ? null : valueStr)); Log.d(TAG, "Metadata updated in " + device + ": " + key + "=" + valueStr); if (key == BluetoothDevice.METADATA_SOFTWARE_VERSION && (valueStr.equals(BluetoothDevice.COMPANION_TYPE_PRIMARY) || valueStr.equals(BluetoothDevice.COMPANION_TYPE_SECONDARY))) { Loading