• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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