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