1 /* 2 * Copyright (C) 2019 The Linux Foundation 3 * Copyright (C) 2023 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package android.bluetooth; 19 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.SystemApi; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.util.Log; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 import java.nio.ByteBuffer; 31 import java.nio.ByteOrder; 32 import java.util.Objects; 33 34 /** 35 * This class provides the System APIs to access the data of BQR event reported from firmware side. 36 * Currently it supports five event types: Quality monitor event, Approaching LSTO event, A2DP 37 * choppy event, SCO choppy event and Connect fail event. To know which kind of event is wrapped in 38 * this {@link BluetoothQualityReport} object, you need to call {@link #getQualityReportId}. 39 * 40 * <ul> 41 * <li>For Quality monitor event, you can call {@link #getBqrCommon} to get a {@link 42 * BluetoothQualityReport.BqrCommon} object. 43 * <li>For Approaching LSTO event, you can call {@link #getBqrCommon} to get a {@link 44 * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link 45 * BluetoothQualityReport.BqrVsLsto} object. 46 * <li>For A2DP choppy event, you can call {@link #getBqrCommon} to get a {@link 47 * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link 48 * BluetoothQualityReport.BqrVsA2dpChoppy} object. 49 * <li>For SCO choppy event, you can call {@link #getBqrCommon} to get a {@link 50 * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link 51 * BluetoothQualityReport.BqrVsScoChoppy} object. 52 * <li>For Connect fail event, you can call {@link #getBqrCommon} to get a {@link 53 * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link 54 * BluetoothQualityReport.BqrConnectFail} object. 55 * </ul> 56 * 57 * @hide 58 */ 59 @SystemApi 60 public final class BluetoothQualityReport implements Parcelable { 61 private static final String TAG = BluetoothQualityReport.class.getSimpleName(); 62 63 /** 64 * Quality report ID: Monitor. 65 * 66 * @hide 67 */ 68 @SystemApi public static final int QUALITY_REPORT_ID_MONITOR = 0x01; 69 70 /** 71 * Quality report ID: Approaching LSTO. 72 * 73 * @hide 74 */ 75 @SystemApi public static final int QUALITY_REPORT_ID_APPROACH_LSTO = 0x02; 76 77 /** 78 * Quality report ID: A2DP choppy. 79 * 80 * @hide 81 */ 82 @SystemApi public static final int QUALITY_REPORT_ID_A2DP_CHOPPY = 0x03; 83 84 /** 85 * Quality report ID: SCO choppy. 86 * 87 * @hide 88 */ 89 @SystemApi public static final int QUALITY_REPORT_ID_SCO_CHOPPY = 0x04; 90 91 /** 92 * Quality report ID: Connect Fail. 93 * 94 * @hide 95 */ 96 @SystemApi public static final int QUALITY_REPORT_ID_CONN_FAIL = 0x08; 97 98 /** @hide */ 99 @Retention(RetentionPolicy.SOURCE) 100 @IntDef( 101 prefix = {"QUALITY_REPORT_ID"}, 102 value = { 103 QUALITY_REPORT_ID_MONITOR, 104 QUALITY_REPORT_ID_APPROACH_LSTO, 105 QUALITY_REPORT_ID_A2DP_CHOPPY, 106 QUALITY_REPORT_ID_SCO_CHOPPY, 107 QUALITY_REPORT_ID_CONN_FAIL, 108 }) 109 public @interface QualityReportId {} 110 111 private String mAddr; 112 private int mLmpVer; 113 private int mLmpSubVer; 114 private int mManufacturerId; 115 private String mName; 116 private BluetoothClass mBluetoothClass; 117 118 private BqrCommon mBqrCommon; 119 private BqrVsLsto mBqrVsLsto; 120 private BqrVsA2dpChoppy mBqrVsA2dpChoppy; 121 private BqrVsScoChoppy mBqrVsScoChoppy; 122 private BqrConnectFail mBqrConnectFail; 123 124 enum PacketType { 125 INVALID, 126 TYPE_ID, 127 TYPE_NULL, 128 TYPE_POLL, 129 TYPE_FHS, 130 TYPE_HV1, 131 TYPE_HV2, 132 TYPE_HV3, 133 TYPE_DV, 134 TYPE_EV3, 135 TYPE_EV4, 136 TYPE_EV5, 137 TYPE_2EV3, 138 TYPE_2EV5, 139 TYPE_3EV3, 140 TYPE_3EV5, 141 TYPE_DM1, 142 TYPE_DH1, 143 TYPE_DM3, 144 TYPE_DH3, 145 TYPE_DM5, 146 TYPE_DH5, 147 TYPE_AUX1, 148 TYPE_2DH1, 149 TYPE_2DH3, 150 TYPE_2DH5, 151 TYPE_3DH1, 152 TYPE_3DH3, 153 TYPE_3DH5; 154 155 private static PacketType[] sAllValues = values(); 156 fromOrdinal(int n)157 static PacketType fromOrdinal(int n) { 158 if (n < sAllValues.length) { 159 return sAllValues[n]; 160 } 161 return INVALID; 162 } 163 } 164 165 enum ConnState { 166 CONN_IDLE(0x00), 167 CONN_ACTIVE(0x81), 168 CONN_HOLD(0x02), 169 CONN_SNIFF_IDLE(0x03), 170 CONN_SNIFF_ACTIVE(0x84), 171 CONN_SNIFF_MASTER_TRANSITION(0x85), 172 CONN_PARK(0x06), 173 CONN_PARK_PEND(0x47), 174 CONN_UNPARK_PEND(0x08), 175 CONN_UNPARK_ACTIVE(0x89), 176 CONN_DISCONNECT_PENDING(0x4A), 177 CONN_PAGING(0x0B), 178 CONN_PAGE_SCAN(0x0C), 179 CONN_LOCAL_LOOPBACK(0x0D), 180 CONN_LE_ACTIVE(0x0E), 181 CONN_ANT_ACTIVE(0x0F), 182 CONN_TRIGGER_SCAN(0x10), 183 CONN_RECONNECTING(0x11), 184 CONN_SEMI_CONN(0x12); 185 186 private final int mValue; 187 private static ConnState[] sAllStates = values(); 188 ConnState(int val)189 ConnState(int val) { 190 mValue = val; 191 } 192 toString(int val)193 public static String toString(int val) { 194 for (ConnState state : sAllStates) { 195 if (state.mValue == val) { 196 return state.toString(); 197 } 198 } 199 return "INVALID"; 200 } 201 } 202 203 enum LinkQuality { 204 ULTRA_HIGH, 205 HIGH, 206 STANDARD, 207 MEDIUM, 208 LOW, 209 INVALID; 210 211 private static LinkQuality[] sAllValues = values(); 212 fromOrdinal(int n)213 static LinkQuality fromOrdinal(int n) { 214 if (n < sAllValues.length - 1) { 215 return sAllValues[n]; 216 } 217 return INVALID; 218 } 219 } 220 221 enum AirMode { 222 uLaw, 223 aLaw, 224 CVSD, 225 transparent_msbc, 226 INVALID; 227 228 private static AirMode[] sAllValues = values(); 229 fromOrdinal(int n)230 static AirMode fromOrdinal(int n) { 231 if (n < sAllValues.length - 1) { 232 return sAllValues[n]; 233 } 234 return INVALID; 235 } 236 } 237 BluetoothQualityReport( String remoteAddr, int lmpVer, int lmpSubVer, int manufacturerId, String remoteName, BluetoothClass bluetoothClass, byte[] rawData)238 private BluetoothQualityReport( 239 String remoteAddr, 240 int lmpVer, 241 int lmpSubVer, 242 int manufacturerId, 243 String remoteName, 244 BluetoothClass bluetoothClass, 245 byte[] rawData) { 246 mAddr = remoteAddr; 247 mLmpVer = lmpVer; 248 mLmpSubVer = lmpSubVer; 249 mManufacturerId = manufacturerId; 250 mName = remoteName; 251 mBluetoothClass = bluetoothClass; 252 253 mBqrCommon = new BqrCommon(rawData, 0); 254 int id = mBqrCommon.getQualityReportId(); 255 if (id == QUALITY_REPORT_ID_MONITOR) return; 256 257 int vsPartOffset = BqrCommon.BQR_COMMON_LEN; 258 if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { 259 mBqrVsLsto = new BqrVsLsto(rawData, vsPartOffset); 260 } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { 261 mBqrVsA2dpChoppy = new BqrVsA2dpChoppy(rawData, vsPartOffset); 262 } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { 263 mBqrVsScoChoppy = new BqrVsScoChoppy(rawData, vsPartOffset); 264 } else if (id == QUALITY_REPORT_ID_CONN_FAIL) { 265 mBqrConnectFail = new BqrConnectFail(rawData, vsPartOffset); 266 } else { 267 throw new IllegalArgumentException(TAG + ": unknown quality report id:" + id); 268 } 269 } 270 BluetoothQualityReport(Parcel in)271 private BluetoothQualityReport(Parcel in) { 272 mAddr = in.readString(); 273 mLmpVer = in.readInt(); 274 mLmpSubVer = in.readInt(); 275 mManufacturerId = in.readInt(); 276 mName = in.readString(); 277 mBluetoothClass = new BluetoothClass(in.readInt()); 278 279 mBqrCommon = new BqrCommon(in); 280 int id = mBqrCommon.getQualityReportId(); 281 if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { 282 mBqrVsLsto = new BqrVsLsto(in); 283 } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { 284 mBqrVsA2dpChoppy = new BqrVsA2dpChoppy(in); 285 } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { 286 mBqrVsScoChoppy = new BqrVsScoChoppy(in); 287 } else if (id == QUALITY_REPORT_ID_CONN_FAIL) { 288 mBqrConnectFail = new BqrConnectFail(in); 289 } 290 } 291 292 /** 293 * Get the quality report id. 294 * 295 * @hide 296 */ 297 @SystemApi 298 @QualityReportId getQualityReportId()299 public int getQualityReportId() { 300 return mBqrCommon.getQualityReportId(); 301 } 302 303 /** 304 * Get the string of the quality report id. 305 * 306 * @return the string of the id 307 * @hide 308 */ 309 @SystemApi qualityReportIdToString(@ualityReportId int id)310 public static @NonNull String qualityReportIdToString(@QualityReportId int id) { 311 return BqrCommon.qualityReportIdToString(id); 312 } 313 314 /** 315 * Get bluetooth address of remote device in this report. 316 * 317 * @return bluetooth address of remote device 318 * @hide 319 */ 320 @SystemApi getRemoteAddress()321 public @Nullable String getRemoteAddress() { 322 return mAddr; 323 } 324 325 /** 326 * Get LMP version of remote device in this report. 327 * 328 * @return LMP version of remote device 329 * @hide 330 */ 331 @SystemApi getLmpVersion()332 public int getLmpVersion() { 333 return mLmpVer; 334 } 335 336 /** 337 * Get LMP subVersion of remote device in this report. 338 * 339 * @return LMP subVersion of remote device 340 * @hide 341 */ 342 @SystemApi getLmpSubVersion()343 public int getLmpSubVersion() { 344 return mLmpSubVer; 345 } 346 347 /** 348 * Get manufacturer id of remote device in this report. 349 * 350 * @return manufacturer id of remote device 351 * @hide 352 */ 353 @SystemApi getManufacturerId()354 public int getManufacturerId() { 355 return mManufacturerId; 356 } 357 358 /** 359 * Get the name of remote device in this report. 360 * 361 * @return the name of remote device 362 * @hide 363 */ 364 @SystemApi getRemoteName()365 public @Nullable String getRemoteName() { 366 return mName; 367 } 368 369 /** 370 * Get the class of remote device in this report. 371 * 372 * @return the class of remote device 373 * @hide 374 */ 375 @SystemApi getBluetoothClass()376 public @Nullable BluetoothClass getBluetoothClass() { 377 return mBluetoothClass; 378 } 379 380 /** 381 * Get the {@link BluetoothQualityReport.BqrCommon} object. 382 * 383 * @return the {@link BluetoothQualityReport.BqrCommon} object. 384 * @hide 385 */ 386 @SystemApi getBqrCommon()387 public @Nullable BqrCommon getBqrCommon() { 388 return mBqrCommon; 389 } 390 391 /** 392 * Get the event data object based on current Quality Report Id. If the report id is {@link 393 * #QUALITY_REPORT_ID_MONITOR}, this returns a {@link BluetoothQualityReport.BqrCommon} object. 394 * If the report id is {@link #QUALITY_REPORT_ID_APPROACH_LSTO}, this returns a {@link 395 * BluetoothQualityReport.BqrVsLsto} object. If the report id is {@link 396 * #QUALITY_REPORT_ID_A2DP_CHOPPY}, this returns a {@link 397 * BluetoothQualityReport.BqrVsA2dpChoppy} object. If the report id is {@link 398 * #QUALITY_REPORT_ID_SCO_CHOPPY}, this returns a {@link BluetoothQualityReport.BqrVsScoChoppy} 399 * object. If the report id is {@link #QUALITY_REPORT_ID_CONN_FAIL}, this returns a {@link 400 * BluetoothQualityReport.BqrConnectFail} object. If the report id is none of the above, this 401 * returns {@code null}. 402 * 403 * @return the event data object based on the quality report id 404 * @hide 405 */ 406 @SystemApi getBqrEvent()407 public @Nullable Parcelable getBqrEvent() { 408 if (mBqrCommon == null) { 409 return null; 410 } 411 switch (mBqrCommon.getQualityReportId()) { 412 case QUALITY_REPORT_ID_MONITOR: 413 return mBqrCommon; 414 case QUALITY_REPORT_ID_APPROACH_LSTO: 415 return mBqrVsLsto; 416 case QUALITY_REPORT_ID_A2DP_CHOPPY: 417 return mBqrVsA2dpChoppy; 418 case QUALITY_REPORT_ID_SCO_CHOPPY: 419 return mBqrVsScoChoppy; 420 case QUALITY_REPORT_ID_CONN_FAIL: 421 return mBqrConnectFail; 422 default: 423 return null; 424 } 425 } 426 427 /** @hide */ 428 @SystemApi 429 public static final @NonNull Parcelable.Creator<BluetoothQualityReport> CREATOR = 430 new Parcelable.Creator<BluetoothQualityReport>() { 431 public BluetoothQualityReport createFromParcel(Parcel in) { 432 return new BluetoothQualityReport(in); 433 } 434 435 public BluetoothQualityReport[] newArray(int size) { 436 return new BluetoothQualityReport[size]; 437 } 438 }; 439 440 /** 441 * Describe contents. 442 * 443 * @return 0 444 * @hide 445 */ describeContents()446 public int describeContents() { 447 return 0; 448 } 449 450 /** 451 * Write BluetoothQualityReport to parcel. 452 * 453 * @hide 454 */ 455 @SystemApi 456 @Override writeToParcel(@onNull Parcel out, int flags)457 public void writeToParcel(@NonNull Parcel out, int flags) { 458 out.writeString(mAddr); 459 out.writeInt(mLmpVer); 460 out.writeInt(mLmpSubVer); 461 out.writeInt(mManufacturerId); 462 out.writeString(mName); 463 out.writeInt(mBluetoothClass.getClassOfDevice()); 464 mBqrCommon.writeToParcel(out, flags); 465 int id = mBqrCommon.getQualityReportId(); 466 if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { 467 mBqrVsLsto.writeToParcel(out, flags); 468 } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { 469 mBqrVsA2dpChoppy.writeToParcel(out, flags); 470 } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { 471 mBqrVsScoChoppy.writeToParcel(out, flags); 472 } else if (id == QUALITY_REPORT_ID_CONN_FAIL) { 473 mBqrConnectFail.writeToParcel(out, flags); 474 } 475 } 476 477 /** BluetoothQualityReport to String. */ 478 @Override 479 @NonNull toString()480 public String toString() { 481 String str; 482 str = 483 "BQR: {\n" 484 + " mAddr: " 485 + mAddr 486 + ", mLmpVer: " 487 + String.format("0x%02X", mLmpVer) 488 + ", mLmpSubVer: " 489 + String.format("0x%04X", mLmpSubVer) 490 + ", mManufacturerId: " 491 + String.format("0x%04X", mManufacturerId) 492 + ", mName: " 493 + mName 494 + ", mBluetoothClass: " 495 + mBluetoothClass.toString() 496 + ",\n" 497 + mBqrCommon 498 + "\n"; 499 500 int id = mBqrCommon.getQualityReportId(); 501 if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { 502 str += mBqrVsLsto + "\n}"; 503 } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { 504 str += mBqrVsA2dpChoppy + "\n}"; 505 } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { 506 str += mBqrVsScoChoppy + "\n}"; 507 } else if (id == QUALITY_REPORT_ID_CONN_FAIL) { 508 str += mBqrConnectFail + "\n}"; 509 } else if (id == QUALITY_REPORT_ID_MONITOR) { 510 str += "}"; 511 } 512 513 return str; 514 } 515 516 /** 517 * Builder for new instances of {@link BluetoothQualityReport}. 518 * 519 * @hide 520 */ 521 @SystemApi 522 public static final class Builder { 523 private String remoteAddr = "00:00:00:00:00:00"; 524 private int lmpVer; 525 private int lmpSubVer; 526 private int manufacturerId; 527 private String remoteName = ""; 528 private BluetoothClass bluetoothClass = new BluetoothClass(0); 529 private byte[] rawData; 530 531 /** 532 * Creates a new instance of {@link Builder}. 533 * 534 * @return The new instance 535 * @throws NullPointerException if rawData is null 536 * @hide 537 */ 538 @SystemApi Builder(@onNull byte[] rawData)539 public Builder(@NonNull byte[] rawData) { 540 this.rawData = Objects.requireNonNull(rawData); 541 } 542 543 /** 544 * Sets the Remote Device Address (big-endian) attribute for the new instance of {@link 545 * BluetoothQualityReport}. 546 * 547 * @param remoteAddr the Remote Device Address (big-endian) attribute 548 * @hide 549 */ 550 @NonNull 551 @SystemApi setRemoteAddress(@ullable String remoteAddr)552 public Builder setRemoteAddress(@Nullable String remoteAddr) { 553 if (!BluetoothAdapter.checkBluetoothAddress(remoteAddr)) { 554 Log.d(TAG, "remote address is not a valid bluetooth address: " + remoteAddr); 555 } else { 556 this.remoteAddr = remoteAddr; 557 } 558 return this; 559 } 560 561 /** 562 * Sets the Link Manager Protocol Version attribute for the new instance of {@link 563 * BluetoothQualityReport}. 564 * 565 * @param lmpVer the Link Manager Protocol Version attribute 566 * @hide 567 */ 568 @NonNull 569 @SystemApi setLmpVersion(int lmpVer)570 public Builder setLmpVersion(int lmpVer) { 571 this.lmpVer = lmpVer; 572 return this; 573 } 574 575 /** 576 * Sets the Link Manager Protocol SubVersion attribute for the new instance of {@link 577 * BluetoothQualityReport}. 578 * 579 * @param lmpSubVer the Link Manager Protocol SubVersion attribute 580 * @hide 581 */ 582 @NonNull 583 @SystemApi setLmpSubVersion(int lmpSubVer)584 public Builder setLmpSubVersion(int lmpSubVer) { 585 this.lmpSubVer = lmpSubVer; 586 return this; 587 } 588 589 /** 590 * Sets the Manufacturer Id attribute for the new instance of {@link 591 * BluetoothQualityReport}. 592 * 593 * @param manufacturerId the Manufacturer Id attribute 594 * @hide 595 */ 596 @NonNull 597 @SystemApi setManufacturerId(int manufacturerId)598 public Builder setManufacturerId(int manufacturerId) { 599 this.manufacturerId = manufacturerId; 600 return this; 601 } 602 603 /** 604 * Sets the Remote Device Name attribute for the new instance of {@link 605 * BluetoothQualityReport}. 606 * 607 * @param remoteName the Remote Device Name attribute 608 * @hide 609 */ 610 @NonNull 611 @SystemApi setRemoteName(@ullable String remoteName)612 public Builder setRemoteName(@Nullable String remoteName) { 613 if (remoteName == null) { 614 Log.d(TAG, "remote name is null"); 615 } else { 616 this.remoteName = remoteName; 617 } 618 return this; 619 } 620 621 /** 622 * Sets the Bluetooth Class of Remote Device attribute for the new instance of {@link 623 * BluetoothQualityReport}. 624 * 625 * @param bluetoothClass the Remote Class of Device attribute 626 * @hide 627 */ 628 @NonNull 629 @SystemApi setBluetoothClass(@ullable BluetoothClass bluetoothClass)630 public Builder setBluetoothClass(@Nullable BluetoothClass bluetoothClass) { 631 if (bluetoothClass == null) { 632 Log.d(TAG, "remote bluetooth class is null"); 633 } else { 634 this.bluetoothClass = bluetoothClass; 635 } 636 return this; 637 } 638 639 /** 640 * Creates a new instance of {@link BluetoothQualityReport}. 641 * 642 * @return The new instance 643 * @throws IllegalArgumentException Unsupported Quality Report Id or invalid raw data 644 * @hide 645 */ 646 @NonNull 647 @SystemApi build()648 public BluetoothQualityReport build() { 649 return new BluetoothQualityReport( 650 remoteAddr, 651 lmpVer, 652 lmpSubVer, 653 manufacturerId, 654 remoteName, 655 bluetoothClass, 656 rawData); 657 } 658 } 659 660 /** 661 * This class provides the System APIs to access the common part of BQR event. 662 * 663 * @hide 664 */ 665 @SystemApi 666 public static final class BqrCommon implements Parcelable { 667 private static final String TAG = BluetoothQualityReport.TAG + ".BqrCommon"; 668 static final int BQR_COMMON_LEN = 55; 669 670 private int mQualityReportId; 671 private int mPacketType; 672 private int mConnectionHandle; 673 private int mConnectionRole; 674 private int mTxPowerLevel; 675 private int mRssi; 676 private int mSnr; 677 private int mUnusedAfhChannelCount; 678 private int mAfhSelectUnidealChannelCount; 679 private int mLsto; 680 private long mPiconetClock; 681 private long mRetransmissionCount; 682 private long mNoRxCount; 683 private long mNakCount; 684 private long mLastTxAckTimestamp; 685 private long mFlowOffCount; 686 private long mLastFlowOnTimestamp; 687 private long mOverflowCount; 688 private long mUnderflowCount; 689 private String mAddr; 690 private int mCalFailedItemCount; 691 BqrCommon(byte[] rawData, int offset)692 private BqrCommon(byte[] rawData, int offset) { 693 if (rawData == null || rawData.length < offset + BQR_COMMON_LEN) { 694 throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); 695 } 696 697 ByteBuffer bqrBuf = 698 ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); 699 bqrBuf.order(ByteOrder.LITTLE_ENDIAN); 700 701 mQualityReportId = bqrBuf.get() & 0xFF; 702 mPacketType = bqrBuf.get() & 0xFF; 703 mConnectionHandle = bqrBuf.getShort() & 0xFFFF; 704 mConnectionRole = bqrBuf.get() & 0xFF; 705 mTxPowerLevel = bqrBuf.get() & 0xFF; 706 mRssi = bqrBuf.get(); 707 mSnr = bqrBuf.get(); 708 mUnusedAfhChannelCount = bqrBuf.get() & 0xFF; 709 mAfhSelectUnidealChannelCount = bqrBuf.get() & 0xFF; 710 mLsto = bqrBuf.getShort() & 0xFFFF; 711 mPiconetClock = bqrBuf.getInt() & 0xFFFFFFFFL; 712 mRetransmissionCount = bqrBuf.getInt() & 0xFFFFFFFFL; 713 mNoRxCount = bqrBuf.getInt() & 0xFFFFFFFFL; 714 mNakCount = bqrBuf.getInt() & 0xFFFFFFFFL; 715 mLastTxAckTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; 716 mFlowOffCount = bqrBuf.getInt() & 0xFFFFFFFFL; 717 mLastFlowOnTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; 718 mOverflowCount = bqrBuf.getInt() & 0xFFFFFFFFL; 719 mUnderflowCount = bqrBuf.getInt() & 0xFFFFFFFFL; 720 int currentOffset = bqrBuf.position(); 721 mAddr = 722 String.format( 723 "%02X:%02X:%02X:%02X:%02X:%02X", 724 bqrBuf.get(currentOffset + 5), 725 bqrBuf.get(currentOffset + 4), 726 bqrBuf.get(currentOffset + 3), 727 bqrBuf.get(currentOffset + 2), 728 bqrBuf.get(currentOffset + 1), 729 bqrBuf.get(currentOffset + 0)); 730 bqrBuf.position(currentOffset + 6); 731 mCalFailedItemCount = bqrBuf.get() & 0xFF; 732 } 733 BqrCommon(Parcel in)734 private BqrCommon(Parcel in) { 735 mQualityReportId = in.readInt(); 736 mPacketType = in.readInt(); 737 mConnectionHandle = in.readInt(); 738 mConnectionRole = in.readInt(); 739 mTxPowerLevel = in.readInt(); 740 mRssi = in.readInt(); 741 mSnr = in.readInt(); 742 mUnusedAfhChannelCount = in.readInt(); 743 mAfhSelectUnidealChannelCount = in.readInt(); 744 mLsto = in.readInt(); 745 mPiconetClock = in.readLong(); 746 mRetransmissionCount = in.readLong(); 747 mNoRxCount = in.readLong(); 748 mNakCount = in.readLong(); 749 mLastTxAckTimestamp = in.readLong(); 750 mFlowOffCount = in.readLong(); 751 mLastFlowOnTimestamp = in.readLong(); 752 mOverflowCount = in.readLong(); 753 mUnderflowCount = in.readLong(); 754 mAddr = in.readString(); 755 mCalFailedItemCount = in.readInt(); 756 } 757 getQualityReportId()758 int getQualityReportId() { 759 return mQualityReportId; 760 } 761 qualityReportIdToString(@ualityReportId int id)762 static String qualityReportIdToString(@QualityReportId int id) { 763 switch (id) { 764 case QUALITY_REPORT_ID_MONITOR: 765 return "Quality monitor"; 766 case QUALITY_REPORT_ID_APPROACH_LSTO: 767 return "Approaching LSTO"; 768 case QUALITY_REPORT_ID_A2DP_CHOPPY: 769 return "A2DP choppy"; 770 case QUALITY_REPORT_ID_SCO_CHOPPY: 771 return "SCO choppy"; 772 case QUALITY_REPORT_ID_CONN_FAIL: 773 return "Connect fail"; 774 default: 775 return "INVALID"; 776 } 777 } 778 779 /** 780 * Get the packet type of the connection. 781 * 782 * @return the packet type 783 * @hide 784 */ 785 @SystemApi getPacketType()786 public int getPacketType() { 787 return mPacketType; 788 } 789 790 /** 791 * Get the string of packet type. 792 * 793 * @param packetType packet type of the connection 794 * @return the string of packet type 795 * @hide 796 */ 797 @SystemApi packetTypeToString(int packetType)798 public static @Nullable String packetTypeToString(int packetType) { 799 PacketType type = PacketType.fromOrdinal(packetType); 800 return type.toString(); 801 } 802 803 /** 804 * Get the connection handle of the connection. 805 * 806 * @return the connection handle 807 * @hide 808 */ 809 @SystemApi getConnectionHandle()810 public int getConnectionHandle() { 811 return mConnectionHandle; 812 } 813 814 /** 815 * Connection role: central. 816 * 817 * @hide 818 */ 819 @SystemApi public static final int CONNECTION_ROLE_CENTRAL = 0; 820 821 /** 822 * Connection role: peripheral. 823 * 824 * @hide 825 */ 826 @SystemApi public static final int CONNECTION_ROLE_PERIPHERAL = 1; 827 828 /** @hide */ 829 @Retention(RetentionPolicy.SOURCE) 830 @IntDef( 831 prefix = {"CONNECTION_ROLE"}, 832 value = { 833 CONNECTION_ROLE_CENTRAL, 834 CONNECTION_ROLE_PERIPHERAL, 835 }) 836 public @interface ConnectionRole {} 837 838 /** 839 * Get the connection Role of the connection. 840 * 841 * @return the connection Role 842 * @hide 843 */ 844 @SystemApi 845 @ConnectionRole getConnectionRole()846 public int getConnectionRole() { 847 return mConnectionRole; 848 } 849 850 /** 851 * Get the connection Role of the connection, "Central" or "Peripheral". 852 * 853 * @param connectionRole connection Role of the connection 854 * @return the connection Role String 855 * @hide 856 */ 857 @SystemApi connectionRoleToString(int connectionRole)858 public static @NonNull String connectionRoleToString(int connectionRole) { 859 if (connectionRole == CONNECTION_ROLE_CENTRAL) { 860 return "Central"; 861 } else if (connectionRole == CONNECTION_ROLE_PERIPHERAL) { 862 return "Peripheral"; 863 } else { 864 return "INVALID:" + connectionRole; 865 } 866 } 867 868 /** 869 * Get the current transmit power level for the connection. 870 * 871 * @return the TX power level 872 * @hide 873 */ 874 @SystemApi getTxPowerLevel()875 public int getTxPowerLevel() { 876 return mTxPowerLevel; 877 } 878 879 /** 880 * Get the Received Signal Strength Indication (RSSI) value for the connection. 881 * 882 * @return the RSSI 883 * @hide 884 */ 885 @SystemApi getRssi()886 public int getRssi() { 887 return mRssi; 888 } 889 890 /** 891 * Get the Signal-to-Noise Ratio (SNR) value for the connection. 892 * 893 * @return the SNR 894 * @hide 895 */ 896 @SystemApi getSnr()897 public int getSnr() { 898 return mSnr; 899 } 900 901 /** 902 * Get the number of unused channels in AFH_channel_map. 903 * 904 * @return the number of unused channels 905 * @hide 906 */ 907 @SystemApi getUnusedAfhChannelCount()908 public int getUnusedAfhChannelCount() { 909 return mUnusedAfhChannelCount; 910 } 911 912 /** 913 * Get the number of the channels which are interfered and quality is bad but are still 914 * selected for AFH. 915 * 916 * @return the number of the selected unideal channels 917 * @hide 918 */ 919 @SystemApi getAfhSelectUnidealChannelCount()920 public int getAfhSelectUnidealChannelCount() { 921 return mAfhSelectUnidealChannelCount; 922 } 923 924 /** 925 * Get the current link supervision timeout setting. time_ms: N * 0.625 ms (1 slot). 926 * 927 * @return link supervision timeout value 928 * @hide 929 */ 930 @SystemApi getLsto()931 public int getLsto() { 932 return mLsto; 933 } 934 935 /** 936 * Get the piconet clock for the specified Connection_Handle. time_ms: N * 0.3125 ms (1 937 * Bluetooth Clock). 938 * 939 * @return the piconet clock 940 * @hide 941 */ 942 @SystemApi getPiconetClock()943 public long getPiconetClock() { 944 return mPiconetClock; 945 } 946 947 /** 948 * Get the count of retransmission. 949 * 950 * @return the count of retransmission 951 * @hide 952 */ 953 @SystemApi getRetransmissionCount()954 public long getRetransmissionCount() { 955 return mRetransmissionCount; 956 } 957 958 /** 959 * Get the count of no RX. 960 * 961 * @return the count of no RX 962 * @hide 963 */ 964 @SystemApi getNoRxCount()965 public long getNoRxCount() { 966 return mNoRxCount; 967 } 968 969 /** 970 * Get the count of NAK(Negative Acknowledge). 971 * 972 * @return the count of NAK 973 * @hide 974 */ 975 @SystemApi getNakCount()976 public long getNakCount() { 977 return mNakCount; 978 } 979 980 /** 981 * Get the timestamp of last TX ACK. time_ms: N * 0.3125 ms (1 Bluetooth Clock). 982 * 983 * @return the timestamp of last TX ACK 984 * @hide 985 */ 986 @SystemApi getLastTxAckTimestamp()987 public long getLastTxAckTimestamp() { 988 return mLastTxAckTimestamp; 989 } 990 991 /** 992 * Get the count of flow-off. 993 * 994 * @return the count of flow-off 995 * @hide 996 */ 997 @SystemApi getFlowOffCount()998 public long getFlowOffCount() { 999 return mFlowOffCount; 1000 } 1001 1002 /** 1003 * Get the timestamp of last flow-on. 1004 * 1005 * @return the timestamp of last flow-on 1006 * @hide 1007 */ 1008 @SystemApi getLastFlowOnTimestamp()1009 public long getLastFlowOnTimestamp() { 1010 return mLastFlowOnTimestamp; 1011 } 1012 1013 /** 1014 * Get the buffer overflow count (how many bytes of TX data are dropped) since the last 1015 * event. 1016 * 1017 * @return the buffer overflow count 1018 * @hide 1019 */ 1020 @SystemApi getOverflowCount()1021 public long getOverflowCount() { 1022 return mOverflowCount; 1023 } 1024 1025 /** 1026 * Get the buffer underflow count (in byte). 1027 * 1028 * @return the buffer underflow count 1029 * @hide 1030 */ 1031 @SystemApi getUnderflowCount()1032 public long getUnderflowCount() { 1033 return mUnderflowCount; 1034 } 1035 1036 /** 1037 * Get the count of calibration failed items. 1038 * 1039 * @return the count of calibration failure 1040 * @hide 1041 */ 1042 @SystemApi getCalFailedItemCount()1043 public int getCalFailedItemCount() { 1044 return mCalFailedItemCount; 1045 } 1046 1047 /** 1048 * Describe contents. 1049 * 1050 * @return 0 1051 * @hide 1052 */ describeContents()1053 public int describeContents() { 1054 return 0; 1055 } 1056 1057 /** 1058 * Write BqrCommon to parcel. 1059 * 1060 * @hide 1061 */ 1062 @SystemApi 1063 @Override writeToParcel(@onNull Parcel dest, int flags)1064 public void writeToParcel(@NonNull Parcel dest, int flags) { 1065 dest.writeInt(mQualityReportId); 1066 dest.writeInt(mPacketType); 1067 dest.writeInt(mConnectionHandle); 1068 dest.writeInt(mConnectionRole); 1069 dest.writeInt(mTxPowerLevel); 1070 dest.writeInt(mRssi); 1071 dest.writeInt(mSnr); 1072 dest.writeInt(mUnusedAfhChannelCount); 1073 dest.writeInt(mAfhSelectUnidealChannelCount); 1074 dest.writeInt(mLsto); 1075 dest.writeLong(mPiconetClock); 1076 dest.writeLong(mRetransmissionCount); 1077 dest.writeLong(mNoRxCount); 1078 dest.writeLong(mNakCount); 1079 dest.writeLong(mLastTxAckTimestamp); 1080 dest.writeLong(mFlowOffCount); 1081 dest.writeLong(mLastFlowOnTimestamp); 1082 dest.writeLong(mOverflowCount); 1083 dest.writeLong(mUnderflowCount); 1084 dest.writeString(mAddr); 1085 dest.writeInt(mCalFailedItemCount); 1086 } 1087 1088 /** @hide */ 1089 @SystemApi 1090 public static final @NonNull Parcelable.Creator<BqrCommon> CREATOR = 1091 new Parcelable.Creator<BqrCommon>() { 1092 public BqrCommon createFromParcel(Parcel in) { 1093 return new BqrCommon(in); 1094 } 1095 1096 public BqrCommon[] newArray(int size) { 1097 return new BqrCommon[size]; 1098 } 1099 }; 1100 1101 /** BqrCommon to String. */ 1102 @Override 1103 @NonNull toString()1104 public String toString() { 1105 String str; 1106 str = 1107 " BqrCommon: {\n" 1108 + " mQualityReportId: " 1109 + qualityReportIdToString(getQualityReportId()) 1110 + "(" 1111 + String.format("0x%02X", mQualityReportId) 1112 + ")" 1113 + ", mPacketType: " 1114 + packetTypeToString(mPacketType) 1115 + "(" 1116 + String.format("0x%02X", mPacketType) 1117 + ")" 1118 + ", mConnectionHandle: " 1119 + String.format("0x%04X", mConnectionHandle) 1120 + ", mConnectionRole: " 1121 + getConnectionRole() 1122 + "(" 1123 + mConnectionRole 1124 + ")" 1125 + ", mTxPowerLevel: " 1126 + mTxPowerLevel 1127 + ", mRssi: " 1128 + mRssi 1129 + ", mSnr: " 1130 + mSnr 1131 + ", mUnusedAfhChannelCount: " 1132 + mUnusedAfhChannelCount 1133 + ",\n" 1134 + " mAfhSelectUnidealChannelCount: " 1135 + mAfhSelectUnidealChannelCount 1136 + ", mLsto: " 1137 + mLsto 1138 + ", mPiconetClock: " 1139 + String.format("0x%08X", mPiconetClock) 1140 + ", mRetransmissionCount: " 1141 + mRetransmissionCount 1142 + ", mNoRxCount: " 1143 + mNoRxCount 1144 + ", mNakCount: " 1145 + mNakCount 1146 + ", mLastTxAckTimestamp: " 1147 + String.format("0x%08X", mLastTxAckTimestamp) 1148 + ", mFlowOffCount: " 1149 + mFlowOffCount 1150 + ",\n" 1151 + " mLastFlowOnTimestamp: " 1152 + String.format("0x%08X", mLastFlowOnTimestamp) 1153 + ", mOverflowCount: " 1154 + mOverflowCount 1155 + ", mUnderflowCount: " 1156 + mUnderflowCount 1157 + ", mAddr: " 1158 + mAddr 1159 + ", mCalFailedItemCount: " 1160 + mCalFailedItemCount 1161 + "\n }"; 1162 1163 return str; 1164 } 1165 } 1166 1167 /** 1168 * This class provides the System APIs to access the vendor specific part of Approaching LSTO 1169 * event. 1170 * 1171 * @hide 1172 */ 1173 @SystemApi 1174 public static final class BqrVsLsto implements Parcelable { 1175 private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsLsto"; 1176 1177 private int mConnState; 1178 private long mBasebandStats; 1179 private long mSlotsUsed; 1180 private int mCxmDenials; 1181 private int mTxSkipped; 1182 private int mRfLoss; 1183 private long mNativeClock; 1184 private long mLastTxAckTimestamp; 1185 BqrVsLsto(byte[] rawData, int offset)1186 private BqrVsLsto(byte[] rawData, int offset) { 1187 if (rawData == null || rawData.length <= offset) { 1188 throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); 1189 } 1190 1191 ByteBuffer bqrBuf = 1192 ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); 1193 bqrBuf.order(ByteOrder.LITTLE_ENDIAN); 1194 1195 mConnState = bqrBuf.get() & 0xFF; 1196 mBasebandStats = bqrBuf.getInt() & 0xFFFFFFFFL; 1197 mSlotsUsed = bqrBuf.getInt() & 0xFFFFFFFFL; 1198 mCxmDenials = bqrBuf.getShort() & 0xFFFF; 1199 mTxSkipped = bqrBuf.getShort() & 0xFFFF; 1200 mRfLoss = bqrBuf.getShort() & 0xFFFF; 1201 mNativeClock = bqrBuf.getInt() & 0xFFFFFFFFL; 1202 mLastTxAckTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; 1203 } 1204 BqrVsLsto(Parcel in)1205 private BqrVsLsto(Parcel in) { 1206 mConnState = in.readInt(); 1207 mBasebandStats = in.readLong(); 1208 mSlotsUsed = in.readLong(); 1209 mCxmDenials = in.readInt(); 1210 mTxSkipped = in.readInt(); 1211 mRfLoss = in.readInt(); 1212 mNativeClock = in.readLong(); 1213 mLastTxAckTimestamp = in.readLong(); 1214 } 1215 1216 /** 1217 * Get the conn state of sco. 1218 * 1219 * @return the conn state 1220 * @hide 1221 */ 1222 @SystemApi getConnState()1223 public int getConnState() { 1224 return mConnState; 1225 } 1226 1227 /** 1228 * Get the string of conn state of sco. 1229 * 1230 * @param connectionState connection state of sco 1231 * @return the string of conn state 1232 * @hide 1233 */ 1234 @SystemApi connStateToString(int connectionState)1235 public static @Nullable String connStateToString(int connectionState) { 1236 return ConnState.toString(connectionState); 1237 } 1238 1239 /** 1240 * Get the baseband statistics. 1241 * 1242 * @return the baseband statistics 1243 * @hide 1244 */ 1245 @SystemApi getBasebandStats()1246 public long getBasebandStats() { 1247 return mBasebandStats; 1248 } 1249 1250 /** 1251 * Get the count of slots allocated for current connection. 1252 * 1253 * @return the count of slots allocated for current connection 1254 * @hide 1255 */ 1256 @SystemApi getSlotsUsed()1257 public long getSlotsUsed() { 1258 return mSlotsUsed; 1259 } 1260 1261 /** 1262 * Get the count of Coex denials. 1263 * 1264 * @return the count of CXM denials 1265 * @hide 1266 */ 1267 @SystemApi getCxmDenials()1268 public int getCxmDenials() { 1269 return mCxmDenials; 1270 } 1271 1272 /** 1273 * Get the count of TX skipped when no poll from remote device. 1274 * 1275 * @return the count of TX skipped 1276 * @hide 1277 */ 1278 @SystemApi getTxSkipped()1279 public int getTxSkipped() { 1280 return mTxSkipped; 1281 } 1282 1283 /** 1284 * Get the count of RF loss. 1285 * 1286 * @return the count of RF loss 1287 * @hide 1288 */ 1289 @SystemApi getRfLoss()1290 public int getRfLoss() { 1291 return mRfLoss; 1292 } 1293 1294 /** 1295 * Get the timestamp when issue happened. time_ms: N * 0.3125 ms (1 Bluetooth Clock). 1296 * 1297 * @return the timestamp when issue happened 1298 * @hide 1299 */ 1300 @SystemApi getNativeClock()1301 public long getNativeClock() { 1302 return mNativeClock; 1303 } 1304 1305 /** 1306 * Get the timestamp of last TX ACK. time_ms: N * 0.3125 ms (1 Bluetooth Clock). 1307 * 1308 * @return the timestamp of last TX ACK 1309 * @hide 1310 */ 1311 @SystemApi getLastTxAckTimestamp()1312 public long getLastTxAckTimestamp() { 1313 return mLastTxAckTimestamp; 1314 } 1315 1316 /** 1317 * Describe contents. 1318 * 1319 * @return 0 1320 * @hide 1321 */ describeContents()1322 public int describeContents() { 1323 return 0; 1324 } 1325 1326 /** 1327 * Write BqrVsLsto to parcel. 1328 * 1329 * @hide 1330 */ 1331 @SystemApi 1332 @Override writeToParcel(@onNull Parcel dest, int flags)1333 public void writeToParcel(@NonNull Parcel dest, int flags) { 1334 dest.writeInt(mConnState); 1335 dest.writeLong(mBasebandStats); 1336 dest.writeLong(mSlotsUsed); 1337 dest.writeInt(mCxmDenials); 1338 dest.writeInt(mTxSkipped); 1339 dest.writeInt(mRfLoss); 1340 dest.writeLong(mNativeClock); 1341 dest.writeLong(mLastTxAckTimestamp); 1342 } 1343 1344 /** @hide */ 1345 @SystemApi 1346 public static final @NonNull Parcelable.Creator<BqrVsLsto> CREATOR = 1347 new Parcelable.Creator<BqrVsLsto>() { 1348 public BqrVsLsto createFromParcel(Parcel in) { 1349 return new BqrVsLsto(in); 1350 } 1351 1352 public BqrVsLsto[] newArray(int size) { 1353 return new BqrVsLsto[size]; 1354 } 1355 }; 1356 1357 /** BqrVsLsto to String. */ 1358 @Override 1359 @NonNull toString()1360 public String toString() { 1361 String str; 1362 str = 1363 " BqrVsLsto: {\n" 1364 + " mConnState: " 1365 + connStateToString(getConnState()) 1366 + "(" 1367 + String.format("0x%02X", mConnState) 1368 + ")" 1369 + ", mBasebandStats: " 1370 + String.format("0x%08X", mBasebandStats) 1371 + ", mSlotsUsed: " 1372 + mSlotsUsed 1373 + ", mCxmDenials: " 1374 + mCxmDenials 1375 + ", mTxSkipped: " 1376 + mTxSkipped 1377 + ", mRfLoss: " 1378 + mRfLoss 1379 + ", mNativeClock: " 1380 + String.format("0x%08X", mNativeClock) 1381 + ", mLastTxAckTimestamp: " 1382 + String.format("0x%08X", mLastTxAckTimestamp) 1383 + "\n }"; 1384 1385 return str; 1386 } 1387 } 1388 1389 /** 1390 * This class provides the System APIs to access the vendor specific part of A2dp choppy event. 1391 * 1392 * @hide 1393 */ 1394 @SystemApi 1395 public static final class BqrVsA2dpChoppy implements Parcelable { 1396 private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsA2dpChoppy"; 1397 1398 private long mArrivalTime; 1399 private long mScheduleTime; 1400 private int mGlitchCount; 1401 private int mTxCxmDenials; 1402 private int mRxCxmDenials; 1403 private int mAclTxQueueLength; 1404 private int mLinkQuality; 1405 BqrVsA2dpChoppy(byte[] rawData, int offset)1406 private BqrVsA2dpChoppy(byte[] rawData, int offset) { 1407 if (rawData == null || rawData.length <= offset) { 1408 throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); 1409 } 1410 1411 ByteBuffer bqrBuf = 1412 ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); 1413 bqrBuf.order(ByteOrder.LITTLE_ENDIAN); 1414 1415 mArrivalTime = bqrBuf.getInt() & 0xFFFFFFFFL; 1416 mScheduleTime = bqrBuf.getInt() & 0xFFFFFFFFL; 1417 mGlitchCount = bqrBuf.getShort() & 0xFFFF; 1418 mTxCxmDenials = bqrBuf.getShort() & 0xFFFF; 1419 mRxCxmDenials = bqrBuf.getShort() & 0xFFFF; 1420 mAclTxQueueLength = bqrBuf.get() & 0xFF; 1421 mLinkQuality = bqrBuf.get() & 0xFF; 1422 } 1423 BqrVsA2dpChoppy(Parcel in)1424 private BqrVsA2dpChoppy(Parcel in) { 1425 mArrivalTime = in.readLong(); 1426 mScheduleTime = in.readLong(); 1427 mGlitchCount = in.readInt(); 1428 mTxCxmDenials = in.readInt(); 1429 mRxCxmDenials = in.readInt(); 1430 mAclTxQueueLength = in.readInt(); 1431 mLinkQuality = in.readInt(); 1432 } 1433 1434 /** 1435 * Get the timestamp of a2dp packet arrived. time_ms: N * 0.3125 ms (1 Bluetooth Clock). 1436 * 1437 * @return the timestamp of a2dp packet arrived 1438 * @hide 1439 */ 1440 @SystemApi getArrivalTime()1441 public long getArrivalTime() { 1442 return mArrivalTime; 1443 } 1444 1445 /** 1446 * Get the timestamp of a2dp packet scheduled. time_ms: N * 0.3125 ms (1 Bluetooth Clock). 1447 * 1448 * @return the timestamp of a2dp packet scheduled 1449 * @hide 1450 */ 1451 @SystemApi getScheduleTime()1452 public long getScheduleTime() { 1453 return mScheduleTime; 1454 } 1455 1456 /** 1457 * Get the a2dp glitch count since the last event. 1458 * 1459 * @return the a2dp glitch count 1460 * @hide 1461 */ 1462 @SystemApi getGlitchCount()1463 public int getGlitchCount() { 1464 return mGlitchCount; 1465 } 1466 1467 /** 1468 * Get the count of Coex TX denials. 1469 * 1470 * @return the count of Coex TX denials 1471 * @hide 1472 */ 1473 @SystemApi getTxCxmDenials()1474 public int getTxCxmDenials() { 1475 return mTxCxmDenials; 1476 } 1477 1478 /** 1479 * Get the count of Coex RX denials. 1480 * 1481 * @return the count of Coex RX denials 1482 * @hide 1483 */ 1484 @SystemApi getRxCxmDenials()1485 public int getRxCxmDenials() { 1486 return mRxCxmDenials; 1487 } 1488 1489 /** 1490 * Get the ACL queue length which are pending TX in FW. 1491 * 1492 * @return the ACL queue length 1493 * @hide 1494 */ 1495 @SystemApi getAclTxQueueLength()1496 public int getAclTxQueueLength() { 1497 return mAclTxQueueLength; 1498 } 1499 1500 /** 1501 * Get the link quality for the current connection. 1502 * 1503 * @return the link quality 1504 * @hide 1505 */ 1506 @SystemApi getLinkQuality()1507 public int getLinkQuality() { 1508 return mLinkQuality; 1509 } 1510 1511 /** 1512 * Get the string of link quality for the current connection. 1513 * 1514 * @param linkQuality link quality for the current connection 1515 * @return the string of link quality 1516 * @hide 1517 */ 1518 @SystemApi linkQualityToString(int linkQuality)1519 public static @Nullable String linkQualityToString(int linkQuality) { 1520 LinkQuality q = LinkQuality.fromOrdinal(linkQuality); 1521 return q.toString(); 1522 } 1523 1524 /** 1525 * Describe contents. 1526 * 1527 * @return 0 1528 * @hide 1529 */ describeContents()1530 public int describeContents() { 1531 return 0; 1532 } 1533 1534 /** 1535 * Write BqrVsA2dpChoppy to parcel. 1536 * 1537 * @hide 1538 */ 1539 @SystemApi 1540 @Override writeToParcel(@onNull Parcel dest, int flags)1541 public void writeToParcel(@NonNull Parcel dest, int flags) { 1542 dest.writeLong(mArrivalTime); 1543 dest.writeLong(mScheduleTime); 1544 dest.writeInt(mGlitchCount); 1545 dest.writeInt(mTxCxmDenials); 1546 dest.writeInt(mRxCxmDenials); 1547 dest.writeInt(mAclTxQueueLength); 1548 dest.writeInt(mLinkQuality); 1549 } 1550 1551 /** @hide */ 1552 @SystemApi 1553 public static final @NonNull Parcelable.Creator<BqrVsA2dpChoppy> CREATOR = 1554 new Parcelable.Creator<BqrVsA2dpChoppy>() { 1555 public BqrVsA2dpChoppy createFromParcel(Parcel in) { 1556 return new BqrVsA2dpChoppy(in); 1557 } 1558 1559 public BqrVsA2dpChoppy[] newArray(int size) { 1560 return new BqrVsA2dpChoppy[size]; 1561 } 1562 }; 1563 1564 /** BqrVsA2dpChoppy to String. */ 1565 @Override 1566 @NonNull toString()1567 public String toString() { 1568 String str; 1569 str = 1570 " BqrVsA2dpChoppy: {\n" 1571 + " mArrivalTime: " 1572 + String.format("0x%08X", mArrivalTime) 1573 + ", mScheduleTime: " 1574 + String.format("0x%08X", mScheduleTime) 1575 + ", mGlitchCount: " 1576 + mGlitchCount 1577 + ", mTxCxmDenials: " 1578 + mTxCxmDenials 1579 + ", mRxCxmDenials: " 1580 + mRxCxmDenials 1581 + ", mAclTxQueueLength: " 1582 + mAclTxQueueLength 1583 + ", mLinkQuality: " 1584 + linkQualityToString(mLinkQuality) 1585 + "(" 1586 + String.format("0x%02X", mLinkQuality) 1587 + ")" 1588 + "\n }"; 1589 1590 return str; 1591 } 1592 } 1593 1594 /** 1595 * This class provides the System APIs to access the vendor specific part of SCO choppy event. 1596 * 1597 * @hide 1598 */ 1599 @SystemApi 1600 public static final class BqrVsScoChoppy implements Parcelable { 1601 private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsScoChoppy"; 1602 1603 private int mGlitchCount; 1604 private int mIntervalEsco; 1605 private int mWindowEsco; 1606 private int mAirFormat; 1607 private int mInstanceCount; 1608 private int mTxCxmDenials; 1609 private int mRxCxmDenials; 1610 private int mTxAbortCount; 1611 private int mLateDispatch; 1612 private int mMicIntrMiss; 1613 private int mLpaIntrMiss; 1614 private int mSprIntrMiss; 1615 private int mPlcFillCount; 1616 private int mPlcDiscardCount; 1617 private int mMissedInstanceCount; 1618 private int mTxRetransmitSlotCount; 1619 private int mRxRetransmitSlotCount; 1620 private int mGoodRxFrameCount; 1621 BqrVsScoChoppy(byte[] rawData, int offset)1622 private BqrVsScoChoppy(byte[] rawData, int offset) { 1623 if (rawData == null || rawData.length <= offset) { 1624 throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); 1625 } 1626 1627 ByteBuffer bqrBuf = 1628 ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); 1629 bqrBuf.order(ByteOrder.LITTLE_ENDIAN); 1630 1631 mGlitchCount = bqrBuf.getShort() & 0xFFFF; 1632 mIntervalEsco = bqrBuf.get() & 0xFF; 1633 mWindowEsco = bqrBuf.get() & 0xFF; 1634 mAirFormat = bqrBuf.get() & 0xFF; 1635 mInstanceCount = bqrBuf.getShort() & 0xFFFF; 1636 mTxCxmDenials = bqrBuf.getShort() & 0xFFFF; 1637 mRxCxmDenials = bqrBuf.getShort() & 0xFFFF; 1638 mTxAbortCount = bqrBuf.getShort() & 0xFFFF; 1639 mLateDispatch = bqrBuf.getShort() & 0xFFFF; 1640 mMicIntrMiss = bqrBuf.getShort() & 0xFFFF; 1641 mLpaIntrMiss = bqrBuf.getShort() & 0xFFFF; 1642 mSprIntrMiss = bqrBuf.getShort() & 0xFFFF; 1643 mPlcFillCount = bqrBuf.getShort() & 0xFFFF; 1644 mPlcDiscardCount = bqrBuf.getShort() & 0xFFFF; 1645 mMissedInstanceCount = bqrBuf.getShort() & 0xFFFF; 1646 mTxRetransmitSlotCount = bqrBuf.getShort() & 0xFFFF; 1647 mRxRetransmitSlotCount = bqrBuf.getShort() & 0xFFFF; 1648 mGoodRxFrameCount = bqrBuf.getShort() & 0xFFFF; 1649 } 1650 BqrVsScoChoppy(Parcel in)1651 private BqrVsScoChoppy(Parcel in) { 1652 mGlitchCount = in.readInt(); 1653 mIntervalEsco = in.readInt(); 1654 mWindowEsco = in.readInt(); 1655 mAirFormat = in.readInt(); 1656 mInstanceCount = in.readInt(); 1657 mTxCxmDenials = in.readInt(); 1658 mRxCxmDenials = in.readInt(); 1659 mTxAbortCount = in.readInt(); 1660 mLateDispatch = in.readInt(); 1661 mMicIntrMiss = in.readInt(); 1662 mLpaIntrMiss = in.readInt(); 1663 mSprIntrMiss = in.readInt(); 1664 mPlcFillCount = in.readInt(); 1665 mPlcDiscardCount = in.readInt(); 1666 mMissedInstanceCount = in.readInt(); 1667 mTxRetransmitSlotCount = in.readInt(); 1668 mRxRetransmitSlotCount = in.readInt(); 1669 mGoodRxFrameCount = in.readInt(); 1670 } 1671 1672 /** 1673 * Get the sco glitch count since the last event. 1674 * 1675 * @return the sco glitch count 1676 * @hide 1677 */ 1678 @SystemApi getGlitchCount()1679 public int getGlitchCount() { 1680 return mGlitchCount; 1681 } 1682 1683 /** 1684 * Get ESCO interval in slots. It is the value of Transmission_Interval parameter in 1685 * Synchronous Connection Complete event. 1686 * 1687 * @return ESCO interval in slots 1688 * @hide 1689 */ 1690 @SystemApi getIntervalEsco()1691 public int getIntervalEsco() { 1692 return mIntervalEsco; 1693 } 1694 1695 /** 1696 * Get ESCO window in slots. It is the value of Retransmission Window parameter in 1697 * Synchronous Connection Complete event. 1698 * 1699 * @return ESCO window in slots 1700 * @hide 1701 */ 1702 @SystemApi getWindowEsco()1703 public int getWindowEsco() { 1704 return mWindowEsco; 1705 } 1706 1707 /** 1708 * Get the air mode. It is the value of Air Mode parameter in Synchronous Connection 1709 * Complete event. 1710 * 1711 * @return the air mode 1712 * @hide 1713 */ 1714 @SystemApi getAirFormat()1715 public int getAirFormat() { 1716 return mAirFormat; 1717 } 1718 1719 /** 1720 * Get the string of air mode. 1721 * 1722 * @param airFormat the value of Air Mode parameter in Synchronous Connection Complete event 1723 * @return the string of air mode 1724 * @hide 1725 */ 1726 @SystemApi airFormatToString(int airFormat)1727 public static @Nullable String airFormatToString(int airFormat) { 1728 AirMode m = AirMode.fromOrdinal(airFormat); 1729 return m.toString(); 1730 } 1731 1732 /** 1733 * Get the xSCO instance count. 1734 * 1735 * @return the xSCO instance count 1736 * @hide 1737 */ 1738 @SystemApi getInstanceCount()1739 public int getInstanceCount() { 1740 return mInstanceCount; 1741 } 1742 1743 /** 1744 * Get the count of Coex TX denials. 1745 * 1746 * @return the count of Coex TX denials 1747 * @hide 1748 */ 1749 @SystemApi getTxCxmDenials()1750 public int getTxCxmDenials() { 1751 return mTxCxmDenials; 1752 } 1753 1754 /** 1755 * Get the count of Coex RX denials. 1756 * 1757 * @return the count of Coex RX denials 1758 * @hide 1759 */ 1760 @SystemApi getRxCxmDenials()1761 public int getRxCxmDenials() { 1762 return mRxCxmDenials; 1763 } 1764 1765 /** 1766 * Get the count of sco packets aborted. 1767 * 1768 * @return the count of sco packets aborted 1769 * @hide 1770 */ 1771 @SystemApi getTxAbortCount()1772 public int getTxAbortCount() { 1773 return mTxAbortCount; 1774 } 1775 1776 /** 1777 * Get the count of sco packets dispatched late. 1778 * 1779 * @return the count of sco packets dispatched late 1780 * @hide 1781 */ 1782 @SystemApi getLateDispatch()1783 public int getLateDispatch() { 1784 return mLateDispatch; 1785 } 1786 1787 /** 1788 * Get the count of missed Mic interrupts. 1789 * 1790 * @return the count of missed Mic interrupts 1791 * @hide 1792 */ 1793 @SystemApi getMicIntrMiss()1794 public int getMicIntrMiss() { 1795 return mMicIntrMiss; 1796 } 1797 1798 /** 1799 * Get the count of missed LPA interrupts. 1800 * 1801 * @return the count of missed LPA interrupts 1802 * @hide 1803 */ 1804 @SystemApi getLpaIntrMiss()1805 public int getLpaIntrMiss() { 1806 return mLpaIntrMiss; 1807 } 1808 1809 /** 1810 * Get the count of missed Speaker interrupts. 1811 * 1812 * @return the count of missed Speaker interrupts 1813 * @hide 1814 */ 1815 @SystemApi getSprIntrMiss()1816 public int getSprIntrMiss() { 1817 return mSprIntrMiss; 1818 } 1819 1820 /** 1821 * Get the count of packet loss concealment filled. 1822 * 1823 * @return the count of packet loss concealment filled 1824 * @hide 1825 */ 1826 @SystemApi getPlcFillCount()1827 public int getPlcFillCount() { 1828 return mPlcFillCount; 1829 } 1830 1831 /** 1832 * Get the count of packet loss concealment discarded. 1833 * 1834 * @return the count of packet loss concealment discarded 1835 * @hide 1836 */ 1837 @SystemApi getPlcDiscardCount()1838 public int getPlcDiscardCount() { 1839 return mPlcDiscardCount; 1840 } 1841 1842 /** 1843 * Get the count of sco instances missed. 1844 * 1845 * @return the count of sco instances missed 1846 * @hide 1847 */ 1848 @SystemApi getMissedInstanceCount()1849 public int getMissedInstanceCount() { 1850 return mMissedInstanceCount; 1851 } 1852 1853 /** 1854 * Get the count of slots for Tx retransmission. 1855 * 1856 * @return the count of slots for Tx retransmission 1857 * @hide 1858 */ 1859 @SystemApi getTxRetransmitSlotCount()1860 public int getTxRetransmitSlotCount() { 1861 return mTxRetransmitSlotCount; 1862 } 1863 1864 /** 1865 * Get the count of slots for Rx retransmission. 1866 * 1867 * @return the count of slots for Rx retransmission 1868 * @hide 1869 */ 1870 @SystemApi getRxRetransmitSlotCount()1871 public int getRxRetransmitSlotCount() { 1872 return mRxRetransmitSlotCount; 1873 } 1874 1875 /** 1876 * Get the count of Rx good packets 1877 * 1878 * @return the count of Rx good packets 1879 * @hide 1880 */ 1881 @SystemApi getGoodRxFrameCount()1882 public int getGoodRxFrameCount() { 1883 return mGoodRxFrameCount; 1884 } 1885 1886 /** 1887 * Describe contents. 1888 * 1889 * @return 0 1890 * @hide 1891 */ describeContents()1892 public int describeContents() { 1893 return 0; 1894 } 1895 1896 /** 1897 * Write BqrVsScoChoppy to parcel. 1898 * 1899 * @hide 1900 */ 1901 @SystemApi 1902 @Override writeToParcel(@onNull Parcel dest, int flags)1903 public void writeToParcel(@NonNull Parcel dest, int flags) { 1904 dest.writeInt(mGlitchCount); 1905 dest.writeInt(mIntervalEsco); 1906 dest.writeInt(mWindowEsco); 1907 dest.writeInt(mAirFormat); 1908 dest.writeInt(mInstanceCount); 1909 dest.writeInt(mTxCxmDenials); 1910 dest.writeInt(mRxCxmDenials); 1911 dest.writeInt(mTxAbortCount); 1912 dest.writeInt(mLateDispatch); 1913 dest.writeInt(mMicIntrMiss); 1914 dest.writeInt(mLpaIntrMiss); 1915 dest.writeInt(mSprIntrMiss); 1916 dest.writeInt(mPlcFillCount); 1917 dest.writeInt(mPlcDiscardCount); 1918 dest.writeInt(mMissedInstanceCount); 1919 dest.writeInt(mTxRetransmitSlotCount); 1920 dest.writeInt(mRxRetransmitSlotCount); 1921 dest.writeInt(mGoodRxFrameCount); 1922 } 1923 1924 /** @hide */ 1925 @SystemApi 1926 public static final @NonNull Parcelable.Creator<BqrVsScoChoppy> CREATOR = 1927 new Parcelable.Creator<BqrVsScoChoppy>() { 1928 public BqrVsScoChoppy createFromParcel(Parcel in) { 1929 return new BqrVsScoChoppy(in); 1930 } 1931 1932 public BqrVsScoChoppy[] newArray(int size) { 1933 return new BqrVsScoChoppy[size]; 1934 } 1935 }; 1936 1937 /** BqrVsScoChoppy to String. */ 1938 @Override 1939 @NonNull toString()1940 public String toString() { 1941 String str; 1942 str = 1943 " BqrVsScoChoppy: {\n" 1944 + " mGlitchCount: " 1945 + mGlitchCount 1946 + ", mIntervalEsco: " 1947 + mIntervalEsco 1948 + ", mWindowEsco: " 1949 + mWindowEsco 1950 + ", mAirFormat: " 1951 + airFormatToString(mAirFormat) 1952 + "(" 1953 + String.format("0x%02X", mAirFormat) 1954 + ")" 1955 + ", mInstanceCount: " 1956 + mInstanceCount 1957 + ", mTxCxmDenials: " 1958 + mTxCxmDenials 1959 + ", mRxCxmDenials: " 1960 + mRxCxmDenials 1961 + ", mTxAbortCount: " 1962 + mTxAbortCount 1963 + ",\n" 1964 + " mLateDispatch: " 1965 + mLateDispatch 1966 + ", mMicIntrMiss: " 1967 + mMicIntrMiss 1968 + ", mLpaIntrMiss: " 1969 + mLpaIntrMiss 1970 + ", mSprIntrMiss: " 1971 + mSprIntrMiss 1972 + ", mPlcFillCount: " 1973 + mPlcFillCount 1974 + ", mPlcDiscardCount: " 1975 + mPlcDiscardCount 1976 + ", mMissedInstanceCount: " 1977 + mMissedInstanceCount 1978 + ", mTxRetransmitSlotCount: " 1979 + mTxRetransmitSlotCount 1980 + ",\n" 1981 + " mRxRetransmitSlotCount: " 1982 + mRxRetransmitSlotCount 1983 + ", mGoodRxFrameCount: " 1984 + mGoodRxFrameCount 1985 + "\n }"; 1986 1987 return str; 1988 } 1989 } 1990 1991 /** 1992 * This class provides the System APIs to access the Connect fail event. 1993 * 1994 * @hide 1995 */ 1996 @SystemApi 1997 public static final class BqrConnectFail implements Parcelable { 1998 private static final String TAG = BluetoothQualityReport.TAG + ".BqrConnectFail"; 1999 2000 /** 2001 * Connect Fail reason: No error. 2002 * 2003 * @hide 2004 */ 2005 @SystemApi public static final int CONNECT_FAIL_ID_NO_ERROR = 0x00; 2006 2007 /** 2008 * Connect Fail reason: Page timeout. 2009 * 2010 * @hide 2011 */ 2012 @SystemApi public static final int CONNECT_FAIL_ID_PAGE_TIMEOUT = 0x04; 2013 2014 /** 2015 * Connect Fail reason: Connection timeout. 2016 * 2017 * @hide 2018 */ 2019 @SystemApi public static final int CONNECT_FAIL_ID_CONNECTION_TIMEOUT = 0x08; 2020 2021 /** 2022 * Connect Fail reason: ACL already exists. 2023 * 2024 * @hide 2025 */ 2026 @SystemApi public static final int CONNECT_FAIL_ID_ACL_ALREADY_EXIST = 0x0b; 2027 2028 /** 2029 * Connect Fail reason: Controller busy. 2030 * 2031 * @hide 2032 */ 2033 @SystemApi public static final int CONNECT_FAIL_ID_CONTROLLER_BUSY = 0x3a; 2034 2035 /** @hide */ 2036 @Retention(RetentionPolicy.SOURCE) 2037 @IntDef( 2038 prefix = {"CONNECT_FAIL_ID"}, 2039 value = { 2040 CONNECT_FAIL_ID_NO_ERROR, 2041 CONNECT_FAIL_ID_PAGE_TIMEOUT, 2042 CONNECT_FAIL_ID_CONNECTION_TIMEOUT, 2043 CONNECT_FAIL_ID_ACL_ALREADY_EXIST, 2044 CONNECT_FAIL_ID_CONTROLLER_BUSY, 2045 }) 2046 public @interface ConnectFailId {} 2047 2048 private int mFailReason; 2049 BqrConnectFail(byte[] rawData, int offset)2050 private BqrConnectFail(byte[] rawData, int offset) { 2051 if (rawData == null || rawData.length <= offset) { 2052 throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); 2053 } 2054 2055 ByteBuffer bqrBuf = 2056 ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); 2057 bqrBuf.order(ByteOrder.LITTLE_ENDIAN); 2058 2059 mFailReason = bqrBuf.get() & 0xFF; 2060 } 2061 BqrConnectFail(Parcel in)2062 private BqrConnectFail(Parcel in) { 2063 mFailReason = in.readInt(); 2064 } 2065 2066 /** 2067 * Get the fail reason. 2068 * 2069 * @return the fail reason 2070 * @hide 2071 */ 2072 @SystemApi 2073 @ConnectFailId getFailReason()2074 public int getFailReason() { 2075 return mFailReason; 2076 } 2077 2078 /** 2079 * Describe contents. 2080 * 2081 * @return 0 2082 * @hide 2083 */ describeContents()2084 public int describeContents() { 2085 return 0; 2086 } 2087 2088 /** 2089 * Write BqrConnectFail to parcel. 2090 * 2091 * @hide 2092 */ 2093 @SystemApi 2094 @Override writeToParcel(@onNull Parcel dest, int flags)2095 public void writeToParcel(@NonNull Parcel dest, int flags) { 2096 dest.writeInt(mFailReason); 2097 } 2098 2099 /** @hide */ 2100 @SystemApi 2101 public static final @NonNull Parcelable.Creator<BqrConnectFail> CREATOR = 2102 new Parcelable.Creator<BqrConnectFail>() { 2103 public BqrConnectFail createFromParcel(Parcel in) { 2104 return new BqrConnectFail(in); 2105 } 2106 2107 public BqrConnectFail[] newArray(int size) { 2108 return new BqrConnectFail[size]; 2109 } 2110 }; 2111 2112 /** 2113 * Get the string of the Connect Fail ID. 2114 * 2115 * @param id the connect fail reason 2116 * @return the string of the id 2117 * @hide 2118 */ 2119 @SystemApi connectFailIdToString(@onnectFailId int id)2120 public static @NonNull String connectFailIdToString(@ConnectFailId int id) { 2121 switch (id) { 2122 case CONNECT_FAIL_ID_NO_ERROR: 2123 return "No error"; 2124 case CONNECT_FAIL_ID_PAGE_TIMEOUT: 2125 return "Page Timeout"; 2126 case CONNECT_FAIL_ID_CONNECTION_TIMEOUT: 2127 return "Connection Timeout"; 2128 case CONNECT_FAIL_ID_ACL_ALREADY_EXIST: 2129 return "ACL already exists"; 2130 case CONNECT_FAIL_ID_CONTROLLER_BUSY: 2131 return "Controller busy"; 2132 default: 2133 return "INVALID"; 2134 } 2135 } 2136 2137 /** BqrConnectFail to String. */ 2138 @Override 2139 @NonNull toString()2140 public String toString() { 2141 String str; 2142 str = 2143 " BqrConnectFail: {\n" 2144 + " mFailReason: " 2145 + connectFailIdToString(mFailReason) 2146 + " (" 2147 + String.format("0x%02X", mFailReason) 2148 + ")" 2149 + "\n }"; 2150 2151 return str; 2152 } 2153 } 2154 } 2155