| /* |
| * Copyright (C) 2019 The Linux Foundation |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package android.bluetooth; |
| |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.SystemApi; |
| import android.os.Parcel; |
| import android.os.Parcelable; |
| import android.util.Log; |
| |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.nio.ByteBuffer; |
| import java.nio.ByteOrder; |
| import java.util.Objects; |
| |
| /** |
| * This class provides the System APIs to access the data of BQR event reported from firmware side. |
| * Currently it supports five event types: Quality monitor event, Approaching LSTO event, A2DP |
| * choppy event, SCO choppy event and Connect fail event. To know which kind of event is wrapped in |
| * this {@link BluetoothQualityReport} object, you need to call {@link #getQualityReportId}. |
| * |
| * <ul> |
| * <li>For Quality monitor event, you can call {@link #getBqrCommon} to get a {@link |
| * BluetoothQualityReport.BqrCommon} object. |
| * <li>For Approaching LSTO event, you can call {@link #getBqrCommon} to get a {@link |
| * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link |
| * BluetoothQualityReport.BqrVsLsto} object. |
| * <li>For A2DP choppy event, you can call {@link #getBqrCommon} to get a {@link |
| * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link |
| * BluetoothQualityReport.BqrVsA2dpChoppy} object. |
| * <li>For SCO choppy event, you can call {@link #getBqrCommon} to get a {@link |
| * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link |
| * BluetoothQualityReport.BqrVsScoChoppy} object. |
| * <li>For Connect fail event, you can call {@link #getBqrCommon} to get a {@link |
| * BluetoothQualityReport.BqrCommon} object, and call {@link #getBqrEvent} to get a {@link |
| * BluetoothQualityReport.BqrConnectFail} object. |
| * </ul> |
| * |
| * @hide |
| */ |
| @SystemApi |
| public final class BluetoothQualityReport implements Parcelable { |
| private static final String TAG = BluetoothQualityReport.class.getSimpleName(); |
| |
| /** |
| * Quality report ID: Monitor. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int QUALITY_REPORT_ID_MONITOR = 0x01; |
| |
| /** |
| * Quality report ID: Approaching LSTO. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int QUALITY_REPORT_ID_APPROACH_LSTO = 0x02; |
| |
| /** |
| * Quality report ID: A2DP choppy. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int QUALITY_REPORT_ID_A2DP_CHOPPY = 0x03; |
| |
| /** |
| * Quality report ID: SCO choppy. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int QUALITY_REPORT_ID_SCO_CHOPPY = 0x04; |
| |
| /** |
| * Quality report ID: Connect Fail. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int QUALITY_REPORT_ID_CONN_FAIL = 0x08; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"QUALITY_REPORT_ID"}, |
| value = { |
| QUALITY_REPORT_ID_MONITOR, |
| QUALITY_REPORT_ID_APPROACH_LSTO, |
| QUALITY_REPORT_ID_A2DP_CHOPPY, |
| QUALITY_REPORT_ID_SCO_CHOPPY, |
| QUALITY_REPORT_ID_CONN_FAIL, |
| }) |
| public @interface QualityReportId {} |
| |
| private String mAddr; |
| private int mLmpVer; |
| private int mLmpSubVer; |
| private int mManufacturerId; |
| private String mName; |
| private BluetoothClass mBluetoothClass; |
| |
| private BqrCommon mBqrCommon; |
| private BqrVsLsto mBqrVsLsto; |
| private BqrVsA2dpChoppy mBqrVsA2dpChoppy; |
| private BqrVsScoChoppy mBqrVsScoChoppy; |
| private BqrConnectFail mBqrConnectFail; |
| |
| enum PacketType { |
| INVALID, |
| TYPE_ID, |
| TYPE_NULL, |
| TYPE_POLL, |
| TYPE_FHS, |
| TYPE_HV1, |
| TYPE_HV2, |
| TYPE_HV3, |
| TYPE_DV, |
| TYPE_EV3, |
| TYPE_EV4, |
| TYPE_EV5, |
| TYPE_2EV3, |
| TYPE_2EV5, |
| TYPE_3EV3, |
| TYPE_3EV5, |
| TYPE_DM1, |
| TYPE_DH1, |
| TYPE_DM3, |
| TYPE_DH3, |
| TYPE_DM5, |
| TYPE_DH5, |
| TYPE_AUX1, |
| TYPE_2DH1, |
| TYPE_2DH3, |
| TYPE_2DH5, |
| TYPE_3DH1, |
| TYPE_3DH3, |
| TYPE_3DH5; |
| |
| private static PacketType[] sAllValues = values(); |
| |
| static PacketType fromOrdinal(int n) { |
| if (n < sAllValues.length) { |
| return sAllValues[n]; |
| } |
| return INVALID; |
| } |
| } |
| |
| enum ConnState { |
| CONN_IDLE(0x00), |
| CONN_ACTIVE(0x81), |
| CONN_HOLD(0x02), |
| CONN_SNIFF_IDLE(0x03), |
| CONN_SNIFF_ACTIVE(0x84), |
| CONN_SNIFF_MASTER_TRANSITION(0x85), |
| CONN_PARK(0x06), |
| CONN_PARK_PEND(0x47), |
| CONN_UNPARK_PEND(0x08), |
| CONN_UNPARK_ACTIVE(0x89), |
| CONN_DISCONNECT_PENDING(0x4A), |
| CONN_PAGING(0x0B), |
| CONN_PAGE_SCAN(0x0C), |
| CONN_LOCAL_LOOPBACK(0x0D), |
| CONN_LE_ACTIVE(0x0E), |
| CONN_ANT_ACTIVE(0x0F), |
| CONN_TRIGGER_SCAN(0x10), |
| CONN_RECONNECTING(0x11), |
| CONN_SEMI_CONN(0x12); |
| |
| private final int mValue; |
| private static ConnState[] sAllStates = values(); |
| |
| ConnState(int val) { |
| mValue = val; |
| } |
| |
| public static String toString(int val) { |
| for (ConnState state : sAllStates) { |
| if (state.mValue == val) { |
| return state.toString(); |
| } |
| } |
| return "INVALID"; |
| } |
| } |
| |
| enum LinkQuality { |
| ULTRA_HIGH, |
| HIGH, |
| STANDARD, |
| MEDIUM, |
| LOW, |
| INVALID; |
| |
| private static LinkQuality[] sAllValues = values(); |
| |
| static LinkQuality fromOrdinal(int n) { |
| if (n < sAllValues.length - 1) { |
| return sAllValues[n]; |
| } |
| return INVALID; |
| } |
| } |
| |
| enum AirMode { |
| uLaw, |
| aLaw, |
| CVSD, |
| transparent_msbc, |
| INVALID; |
| |
| private static AirMode[] sAllValues = values(); |
| |
| static AirMode fromOrdinal(int n) { |
| if (n < sAllValues.length - 1) { |
| return sAllValues[n]; |
| } |
| return INVALID; |
| } |
| } |
| |
| private BluetoothQualityReport( |
| String remoteAddr, |
| int lmpVer, |
| int lmpSubVer, |
| int manufacturerId, |
| String remoteName, |
| BluetoothClass bluetoothClass, |
| byte[] rawData) { |
| mAddr = remoteAddr; |
| mLmpVer = lmpVer; |
| mLmpSubVer = lmpSubVer; |
| mManufacturerId = manufacturerId; |
| mName = remoteName; |
| mBluetoothClass = bluetoothClass; |
| |
| mBqrCommon = new BqrCommon(rawData, 0); |
| int id = mBqrCommon.getQualityReportId(); |
| if (id == QUALITY_REPORT_ID_MONITOR) return; |
| |
| int vsPartOffset = BqrCommon.BQR_COMMON_LEN; |
| if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { |
| mBqrVsLsto = new BqrVsLsto(rawData, vsPartOffset); |
| } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { |
| mBqrVsA2dpChoppy = new BqrVsA2dpChoppy(rawData, vsPartOffset); |
| } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { |
| mBqrVsScoChoppy = new BqrVsScoChoppy(rawData, vsPartOffset); |
| } else if (id == QUALITY_REPORT_ID_CONN_FAIL) { |
| mBqrConnectFail = new BqrConnectFail(rawData, vsPartOffset); |
| } else { |
| throw new IllegalArgumentException(TAG + ": unknown quality report id:" + id); |
| } |
| } |
| |
| private BluetoothQualityReport(Parcel in) { |
| mAddr = in.readString(); |
| mLmpVer = in.readInt(); |
| mLmpSubVer = in.readInt(); |
| mManufacturerId = in.readInt(); |
| mName = in.readString(); |
| mBluetoothClass = new BluetoothClass(in.readInt()); |
| |
| mBqrCommon = new BqrCommon(in); |
| int id = mBqrCommon.getQualityReportId(); |
| if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { |
| mBqrVsLsto = new BqrVsLsto(in); |
| } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { |
| mBqrVsA2dpChoppy = new BqrVsA2dpChoppy(in); |
| } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { |
| mBqrVsScoChoppy = new BqrVsScoChoppy(in); |
| } else if (id == QUALITY_REPORT_ID_CONN_FAIL) { |
| mBqrConnectFail = new BqrConnectFail(in); |
| } |
| } |
| |
| /** |
| * Get the quality report id. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @QualityReportId |
| public int getQualityReportId() { |
| return mBqrCommon.getQualityReportId(); |
| } |
| |
| /** |
| * Get the string of the quality report id. |
| * |
| * @return the string of the id |
| * @hide |
| */ |
| @SystemApi |
| public static @NonNull String qualityReportIdToString(@QualityReportId int id) { |
| return BqrCommon.qualityReportIdToString(id); |
| } |
| |
| /** |
| * Get bluetooth address of remote device in this report. |
| * |
| * @return bluetooth address of remote device |
| * @hide |
| */ |
| @SystemApi |
| public @Nullable String getRemoteAddress() { |
| return mAddr; |
| } |
| |
| /** |
| * Get LMP version of remote device in this report. |
| * |
| * @return LMP version of remote device |
| * @hide |
| */ |
| @SystemApi |
| public int getLmpVersion() { |
| return mLmpVer; |
| } |
| |
| /** |
| * Get LMP subVersion of remote device in this report. |
| * |
| * @return LMP subVersion of remote device |
| * @hide |
| */ |
| @SystemApi |
| public int getLmpSubVersion() { |
| return mLmpSubVer; |
| } |
| |
| /** |
| * Get manufacturer id of remote device in this report. |
| * |
| * @return manufacturer id of remote device |
| * @hide |
| */ |
| @SystemApi |
| public int getManufacturerId() { |
| return mManufacturerId; |
| } |
| |
| /** |
| * Get the name of remote device in this report. |
| * |
| * @return the name of remote device |
| * @hide |
| */ |
| @SystemApi |
| public @Nullable String getRemoteName() { |
| return mName; |
| } |
| |
| /** |
| * Get the class of remote device in this report. |
| * |
| * @return the class of remote device |
| * @hide |
| */ |
| @SystemApi |
| public @Nullable BluetoothClass getBluetoothClass() { |
| return mBluetoothClass; |
| } |
| |
| /** |
| * Get the {@link BluetoothQualityReport.BqrCommon} object. |
| * |
| * @return the {@link BluetoothQualityReport.BqrCommon} object. |
| * @hide |
| */ |
| @SystemApi |
| public @Nullable BqrCommon getBqrCommon() { |
| return mBqrCommon; |
| } |
| |
| /** |
| * Get the event data object based on current Quality Report Id. If the report id is {@link |
| * #QUALITY_REPORT_ID_MONITOR}, this returns a {@link BluetoothQualityReport.BqrCommon} object. |
| * If the report id is {@link #QUALITY_REPORT_ID_APPROACH_LSTO}, this returns a {@link |
| * BluetoothQualityReport.BqrVsLsto} object. If the report id is {@link |
| * #QUALITY_REPORT_ID_A2DP_CHOPPY}, this returns a {@link |
| * BluetoothQualityReport.BqrVsA2dpChoppy} object. If the report id is {@link |
| * #QUALITY_REPORT_ID_SCO_CHOPPY}, this returns a {@link BluetoothQualityReport.BqrVsScoChoppy} |
| * object. If the report id is {@link #QUALITY_REPORT_ID_CONN_FAIL}, this returns a {@link |
| * BluetoothQualityReport.BqrConnectFail} object. If the report id is none of the above, this |
| * returns {@code null}. |
| * |
| * @return the event data object based on the quality report id |
| * @hide |
| */ |
| @SystemApi |
| public @Nullable Parcelable getBqrEvent() { |
| if (mBqrCommon == null) { |
| return null; |
| } |
| switch (mBqrCommon.getQualityReportId()) { |
| case QUALITY_REPORT_ID_MONITOR: |
| return mBqrCommon; |
| case QUALITY_REPORT_ID_APPROACH_LSTO: |
| return mBqrVsLsto; |
| case QUALITY_REPORT_ID_A2DP_CHOPPY: |
| return mBqrVsA2dpChoppy; |
| case QUALITY_REPORT_ID_SCO_CHOPPY: |
| return mBqrVsScoChoppy; |
| case QUALITY_REPORT_ID_CONN_FAIL: |
| return mBqrConnectFail; |
| default: |
| return null; |
| } |
| } |
| |
| /** @hide */ |
| @SystemApi |
| public static final @NonNull Parcelable.Creator<BluetoothQualityReport> CREATOR = |
| new Parcelable.Creator<BluetoothQualityReport>() { |
| public BluetoothQualityReport createFromParcel(Parcel in) { |
| return new BluetoothQualityReport(in); |
| } |
| |
| public BluetoothQualityReport[] newArray(int size) { |
| return new BluetoothQualityReport[size]; |
| } |
| }; |
| |
| /** |
| * Describe contents. |
| * |
| * @return 0 |
| * @hide |
| */ |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** |
| * Write BluetoothQualityReport to parcel. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @Override |
| public void writeToParcel(@NonNull Parcel out, int flags) { |
| out.writeString(mAddr); |
| out.writeInt(mLmpVer); |
| out.writeInt(mLmpSubVer); |
| out.writeInt(mManufacturerId); |
| out.writeString(mName); |
| out.writeInt(mBluetoothClass.getClassOfDevice()); |
| mBqrCommon.writeToParcel(out, flags); |
| int id = mBqrCommon.getQualityReportId(); |
| if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { |
| mBqrVsLsto.writeToParcel(out, flags); |
| } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { |
| mBqrVsA2dpChoppy.writeToParcel(out, flags); |
| } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { |
| mBqrVsScoChoppy.writeToParcel(out, flags); |
| } else if (id == QUALITY_REPORT_ID_CONN_FAIL) { |
| mBqrConnectFail.writeToParcel(out, flags); |
| } |
| } |
| |
| /** BluetoothQualityReport to String. */ |
| @Override |
| @NonNull |
| public String toString() { |
| String str; |
| str = |
| "BQR: {\n" |
| + " mAddr: " |
| + mAddr |
| + ", mLmpVer: " |
| + String.format("0x%02X", mLmpVer) |
| + ", mLmpSubVer: " |
| + String.format("0x%04X", mLmpSubVer) |
| + ", mManufacturerId: " |
| + String.format("0x%04X", mManufacturerId) |
| + ", mName: " |
| + mName |
| + ", mBluetoothClass: " |
| + mBluetoothClass.toString() |
| + ",\n" |
| + mBqrCommon |
| + "\n"; |
| |
| int id = mBqrCommon.getQualityReportId(); |
| if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { |
| str += mBqrVsLsto + "\n}"; |
| } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { |
| str += mBqrVsA2dpChoppy + "\n}"; |
| } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { |
| str += mBqrVsScoChoppy + "\n}"; |
| } else if (id == QUALITY_REPORT_ID_CONN_FAIL) { |
| str += mBqrConnectFail + "\n}"; |
| } else if (id == QUALITY_REPORT_ID_MONITOR) { |
| str += "}"; |
| } |
| |
| return str; |
| } |
| |
| /** |
| * Builder for new instances of {@link BluetoothQualityReport}. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final class Builder { |
| private String remoteAddr = "00:00:00:00:00:00"; |
| private int lmpVer; |
| private int lmpSubVer; |
| private int manufacturerId; |
| private String remoteName = ""; |
| private BluetoothClass bluetoothClass = new BluetoothClass(0); |
| private byte[] rawData; |
| |
| /** |
| * Creates a new instance of {@link Builder}. |
| * |
| * @return The new instance |
| * @throws NullPointerException if rawData is null |
| * @hide |
| */ |
| @SystemApi |
| public Builder(@NonNull byte[] rawData) { |
| this.rawData = Objects.requireNonNull(rawData); |
| } |
| |
| /** |
| * Sets the Remote Device Address (big-endian) attribute for the new instance of {@link |
| * BluetoothQualityReport}. |
| * |
| * @param remoteAddr the Remote Device Address (big-endian) attribute |
| * @hide |
| */ |
| @NonNull |
| @SystemApi |
| public Builder setRemoteAddress(@Nullable String remoteAddr) { |
| if (!BluetoothAdapter.checkBluetoothAddress(remoteAddr)) { |
| Log.d(TAG, "remote address is not a valid bluetooth address: " + remoteAddr); |
| } else { |
| this.remoteAddr = remoteAddr; |
| } |
| return this; |
| } |
| |
| /** |
| * Sets the Link Manager Protocol Version attribute for the new instance of {@link |
| * BluetoothQualityReport}. |
| * |
| * @param lmpVer the Link Manager Protocol Version attribute |
| * @hide |
| */ |
| @NonNull |
| @SystemApi |
| public Builder setLmpVersion(int lmpVer) { |
| this.lmpVer = lmpVer; |
| return this; |
| } |
| |
| /** |
| * Sets the Link Manager Protocol SubVersion attribute for the new instance of {@link |
| * BluetoothQualityReport}. |
| * |
| * @param lmpSubVer the Link Manager Protocol SubVersion attribute |
| * @hide |
| */ |
| @NonNull |
| @SystemApi |
| public Builder setLmpSubVersion(int lmpSubVer) { |
| this.lmpSubVer = lmpSubVer; |
| return this; |
| } |
| |
| /** |
| * Sets the Manufacturer Id attribute for the new instance of {@link |
| * BluetoothQualityReport}. |
| * |
| * @param manufacturerId the Manufacturer Id attribute |
| * @hide |
| */ |
| @NonNull |
| @SystemApi |
| public Builder setManufacturerId(int manufacturerId) { |
| this.manufacturerId = manufacturerId; |
| return this; |
| } |
| |
| /** |
| * Sets the Remote Device Name attribute for the new instance of {@link |
| * BluetoothQualityReport}. |
| * |
| * @param remoteName the Remote Device Name attribute |
| * @hide |
| */ |
| @NonNull |
| @SystemApi |
| public Builder setRemoteName(@Nullable String remoteName) { |
| if (remoteName == null) { |
| Log.d(TAG, "remote name is null"); |
| } else { |
| this.remoteName = remoteName; |
| } |
| return this; |
| } |
| |
| /** |
| * Sets the Bluetooth Class of Remote Device attribute for the new instance of {@link |
| * BluetoothQualityReport}. |
| * |
| * @param bluetoothClass the Remote Class of Device attribute |
| * @hide |
| */ |
| @NonNull |
| @SystemApi |
| public Builder setBluetoothClass(@Nullable BluetoothClass bluetoothClass) { |
| if (bluetoothClass == null) { |
| Log.d(TAG, "remote bluetooth class is null"); |
| } else { |
| this.bluetoothClass = bluetoothClass; |
| } |
| return this; |
| } |
| |
| /** |
| * Creates a new instance of {@link BluetoothQualityReport}. |
| * |
| * @return The new instance |
| * @throws IllegalArgumentException Unsupported Quality Report Id or invalid raw data |
| * @hide |
| */ |
| @NonNull |
| @SystemApi |
| public BluetoothQualityReport build() { |
| return new BluetoothQualityReport( |
| remoteAddr, |
| lmpVer, |
| lmpSubVer, |
| manufacturerId, |
| remoteName, |
| bluetoothClass, |
| rawData); |
| } |
| } |
| |
| /** |
| * This class provides the System APIs to access the common part of BQR event. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final class BqrCommon implements Parcelable { |
| private static final String TAG = BluetoothQualityReport.TAG + ".BqrCommon"; |
| static final int BQR_COMMON_LEN = 55; |
| |
| private int mQualityReportId; |
| private int mPacketType; |
| private int mConnectionHandle; |
| private int mConnectionRole; |
| private int mTxPowerLevel; |
| private int mRssi; |
| private int mSnr; |
| private int mUnusedAfhChannelCount; |
| private int mAfhSelectUnidealChannelCount; |
| private int mLsto; |
| private long mPiconetClock; |
| private long mRetransmissionCount; |
| private long mNoRxCount; |
| private long mNakCount; |
| private long mLastTxAckTimestamp; |
| private long mFlowOffCount; |
| private long mLastFlowOnTimestamp; |
| private long mOverflowCount; |
| private long mUnderflowCount; |
| private String mAddr; |
| private int mCalFailedItemCount; |
| |
| private BqrCommon(byte[] rawData, int offset) { |
| if (rawData == null || rawData.length < offset + BQR_COMMON_LEN) { |
| throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); |
| } |
| |
| ByteBuffer bqrBuf = |
| ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); |
| bqrBuf.order(ByteOrder.LITTLE_ENDIAN); |
| |
| mQualityReportId = bqrBuf.get() & 0xFF; |
| mPacketType = bqrBuf.get() & 0xFF; |
| mConnectionHandle = bqrBuf.getShort() & 0xFFFF; |
| mConnectionRole = bqrBuf.get() & 0xFF; |
| mTxPowerLevel = bqrBuf.get() & 0xFF; |
| mRssi = bqrBuf.get(); |
| mSnr = bqrBuf.get(); |
| mUnusedAfhChannelCount = bqrBuf.get() & 0xFF; |
| mAfhSelectUnidealChannelCount = bqrBuf.get() & 0xFF; |
| mLsto = bqrBuf.getShort() & 0xFFFF; |
| mPiconetClock = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mRetransmissionCount = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mNoRxCount = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mNakCount = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mLastTxAckTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mFlowOffCount = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mLastFlowOnTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mOverflowCount = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mUnderflowCount = bqrBuf.getInt() & 0xFFFFFFFFL; |
| int currentOffset = bqrBuf.position(); |
| mAddr = |
| String.format( |
| "%02X:%02X:%02X:%02X:%02X:%02X", |
| bqrBuf.get(currentOffset + 5), |
| bqrBuf.get(currentOffset + 4), |
| bqrBuf.get(currentOffset + 3), |
| bqrBuf.get(currentOffset + 2), |
| bqrBuf.get(currentOffset + 1), |
| bqrBuf.get(currentOffset + 0)); |
| bqrBuf.position(currentOffset + 6); |
| mCalFailedItemCount = bqrBuf.get() & 0xFF; |
| } |
| |
| private BqrCommon(Parcel in) { |
| mQualityReportId = in.readInt(); |
| mPacketType = in.readInt(); |
| mConnectionHandle = in.readInt(); |
| mConnectionRole = in.readInt(); |
| mTxPowerLevel = in.readInt(); |
| mRssi = in.readInt(); |
| mSnr = in.readInt(); |
| mUnusedAfhChannelCount = in.readInt(); |
| mAfhSelectUnidealChannelCount = in.readInt(); |
| mLsto = in.readInt(); |
| mPiconetClock = in.readLong(); |
| mRetransmissionCount = in.readLong(); |
| mNoRxCount = in.readLong(); |
| mNakCount = in.readLong(); |
| mLastTxAckTimestamp = in.readLong(); |
| mFlowOffCount = in.readLong(); |
| mLastFlowOnTimestamp = in.readLong(); |
| mOverflowCount = in.readLong(); |
| mUnderflowCount = in.readLong(); |
| mAddr = in.readString(); |
| mCalFailedItemCount = in.readInt(); |
| } |
| |
| int getQualityReportId() { |
| return mQualityReportId; |
| } |
| |
| static String qualityReportIdToString(@QualityReportId int id) { |
| switch (id) { |
| case QUALITY_REPORT_ID_MONITOR: |
| return "Quality monitor"; |
| case QUALITY_REPORT_ID_APPROACH_LSTO: |
| return "Approaching LSTO"; |
| case QUALITY_REPORT_ID_A2DP_CHOPPY: |
| return "A2DP choppy"; |
| case QUALITY_REPORT_ID_SCO_CHOPPY: |
| return "SCO choppy"; |
| case QUALITY_REPORT_ID_CONN_FAIL: |
| return "Connect fail"; |
| default: |
| return "INVALID"; |
| } |
| } |
| |
| /** |
| * Get the packet type of the connection. |
| * |
| * @return the packet type |
| * @hide |
| */ |
| @SystemApi |
| public int getPacketType() { |
| return mPacketType; |
| } |
| |
| /** |
| * Get the string of packet type. |
| * |
| * @param packetType packet type of the connection |
| * @return the string of packet type |
| * @hide |
| */ |
| @SystemApi |
| public static @Nullable String packetTypeToString(int packetType) { |
| PacketType type = PacketType.fromOrdinal(packetType); |
| return type.toString(); |
| } |
| |
| /** |
| * Get the connection handle of the connection. |
| * |
| * @return the connection handle |
| * @hide |
| */ |
| @SystemApi |
| public int getConnectionHandle() { |
| return mConnectionHandle; |
| } |
| |
| /** |
| * Connection role: central. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int CONNECTION_ROLE_CENTRAL = 0; |
| |
| /** |
| * Connection role: peripheral. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int CONNECTION_ROLE_PERIPHERAL = 1; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"CONNECTION_ROLE"}, |
| value = { |
| CONNECTION_ROLE_CENTRAL, |
| CONNECTION_ROLE_PERIPHERAL, |
| }) |
| public @interface ConnectionRole {} |
| |
| /** |
| * Get the connection Role of the connection. |
| * |
| * @return the connection Role |
| * @hide |
| */ |
| @SystemApi |
| @ConnectionRole |
| public int getConnectionRole() { |
| return mConnectionRole; |
| } |
| |
| /** |
| * Get the connection Role of the connection, "Central" or "Peripheral". |
| * |
| * @param connectionRole connection Role of the connection |
| * @return the connection Role String |
| * @hide |
| */ |
| @SystemApi |
| public static @NonNull String connectionRoleToString(int connectionRole) { |
| if (connectionRole == CONNECTION_ROLE_CENTRAL) { |
| return "Central"; |
| } else if (connectionRole == CONNECTION_ROLE_PERIPHERAL) { |
| return "Peripheral"; |
| } else { |
| return "INVALID:" + connectionRole; |
| } |
| } |
| |
| /** |
| * Get the current transmit power level for the connection. |
| * |
| * @return the TX power level |
| * @hide |
| */ |
| @SystemApi |
| public int getTxPowerLevel() { |
| return mTxPowerLevel; |
| } |
| |
| /** |
| * Get the Received Signal Strength Indication (RSSI) value for the connection. |
| * |
| * @return the RSSI |
| * @hide |
| */ |
| @SystemApi |
| public int getRssi() { |
| return mRssi; |
| } |
| |
| /** |
| * Get the Signal-to-Noise Ratio (SNR) value for the connection. |
| * |
| * @return the SNR |
| * @hide |
| */ |
| @SystemApi |
| public int getSnr() { |
| return mSnr; |
| } |
| |
| /** |
| * Get the number of unused channels in AFH_channel_map. |
| * |
| * @return the number of unused channels |
| * @hide |
| */ |
| @SystemApi |
| public int getUnusedAfhChannelCount() { |
| return mUnusedAfhChannelCount; |
| } |
| |
| /** |
| * Get the number of the channels which are interfered and quality is bad but are still |
| * selected for AFH. |
| * |
| * @return the number of the selected unideal channels |
| * @hide |
| */ |
| @SystemApi |
| public int getAfhSelectUnidealChannelCount() { |
| return mAfhSelectUnidealChannelCount; |
| } |
| |
| /** |
| * Get the current link supervision timeout setting. time_ms: N * 0.625 ms (1 slot). |
| * |
| * @return link supervision timeout value |
| * @hide |
| */ |
| @SystemApi |
| public int getLsto() { |
| return mLsto; |
| } |
| |
| /** |
| * Get the piconet clock for the specified Connection_Handle. time_ms: N * 0.3125 ms (1 |
| * Bluetooth Clock). |
| * |
| * @return the piconet clock |
| * @hide |
| */ |
| @SystemApi |
| public long getPiconetClock() { |
| return mPiconetClock; |
| } |
| |
| /** |
| * Get the count of retransmission. |
| * |
| * @return the count of retransmission |
| * @hide |
| */ |
| @SystemApi |
| public long getRetransmissionCount() { |
| return mRetransmissionCount; |
| } |
| |
| /** |
| * Get the count of no RX. |
| * |
| * @return the count of no RX |
| * @hide |
| */ |
| @SystemApi |
| public long getNoRxCount() { |
| return mNoRxCount; |
| } |
| |
| /** |
| * Get the count of NAK(Negative Acknowledge). |
| * |
| * @return the count of NAK |
| * @hide |
| */ |
| @SystemApi |
| public long getNakCount() { |
| return mNakCount; |
| } |
| |
| /** |
| * Get the timestamp of last TX ACK. time_ms: N * 0.3125 ms (1 Bluetooth Clock). |
| * |
| * @return the timestamp of last TX ACK |
| * @hide |
| */ |
| @SystemApi |
| public long getLastTxAckTimestamp() { |
| return mLastTxAckTimestamp; |
| } |
| |
| /** |
| * Get the count of flow-off. |
| * |
| * @return the count of flow-off |
| * @hide |
| */ |
| @SystemApi |
| public long getFlowOffCount() { |
| return mFlowOffCount; |
| } |
| |
| /** |
| * Get the timestamp of last flow-on. |
| * |
| * @return the timestamp of last flow-on |
| * @hide |
| */ |
| @SystemApi |
| public long getLastFlowOnTimestamp() { |
| return mLastFlowOnTimestamp; |
| } |
| |
| /** |
| * Get the buffer overflow count (how many bytes of TX data are dropped) since the last |
| * event. |
| * |
| * @return the buffer overflow count |
| * @hide |
| */ |
| @SystemApi |
| public long getOverflowCount() { |
| return mOverflowCount; |
| } |
| |
| /** |
| * Get the buffer underflow count (in byte). |
| * |
| * @return the buffer underflow count |
| * @hide |
| */ |
| @SystemApi |
| public long getUnderflowCount() { |
| return mUnderflowCount; |
| } |
| |
| /** |
| * Get the count of calibration failed items. |
| * |
| * @return the count of calibration failure |
| * @hide |
| */ |
| @SystemApi |
| public int getCalFailedItemCount() { |
| return mCalFailedItemCount; |
| } |
| |
| /** |
| * Describe contents. |
| * |
| * @return 0 |
| * @hide |
| */ |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** |
| * Write BqrCommon to parcel. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeInt(mQualityReportId); |
| dest.writeInt(mPacketType); |
| dest.writeInt(mConnectionHandle); |
| dest.writeInt(mConnectionRole); |
| dest.writeInt(mTxPowerLevel); |
| dest.writeInt(mRssi); |
| dest.writeInt(mSnr); |
| dest.writeInt(mUnusedAfhChannelCount); |
| dest.writeInt(mAfhSelectUnidealChannelCount); |
| dest.writeInt(mLsto); |
| dest.writeLong(mPiconetClock); |
| dest.writeLong(mRetransmissionCount); |
| dest.writeLong(mNoRxCount); |
| dest.writeLong(mNakCount); |
| dest.writeLong(mLastTxAckTimestamp); |
| dest.writeLong(mFlowOffCount); |
| dest.writeLong(mLastFlowOnTimestamp); |
| dest.writeLong(mOverflowCount); |
| dest.writeLong(mUnderflowCount); |
| dest.writeString(mAddr); |
| dest.writeInt(mCalFailedItemCount); |
| } |
| |
| /** @hide */ |
| @SystemApi |
| public static final @NonNull Parcelable.Creator<BqrCommon> CREATOR = |
| new Parcelable.Creator<BqrCommon>() { |
| public BqrCommon createFromParcel(Parcel in) { |
| return new BqrCommon(in); |
| } |
| |
| public BqrCommon[] newArray(int size) { |
| return new BqrCommon[size]; |
| } |
| }; |
| |
| /** BqrCommon to String. */ |
| @Override |
| @NonNull |
| public String toString() { |
| String str; |
| str = |
| " BqrCommon: {\n" |
| + " mQualityReportId: " |
| + qualityReportIdToString(getQualityReportId()) |
| + "(" |
| + String.format("0x%02X", mQualityReportId) |
| + ")" |
| + ", mPacketType: " |
| + packetTypeToString(mPacketType) |
| + "(" |
| + String.format("0x%02X", mPacketType) |
| + ")" |
| + ", mConnectionHandle: " |
| + String.format("0x%04X", mConnectionHandle) |
| + ", mConnectionRole: " |
| + getConnectionRole() |
| + "(" |
| + mConnectionRole |
| + ")" |
| + ", mTxPowerLevel: " |
| + mTxPowerLevel |
| + ", mRssi: " |
| + mRssi |
| + ", mSnr: " |
| + mSnr |
| + ", mUnusedAfhChannelCount: " |
| + mUnusedAfhChannelCount |
| + ",\n" |
| + " mAfhSelectUnidealChannelCount: " |
| + mAfhSelectUnidealChannelCount |
| + ", mLsto: " |
| + mLsto |
| + ", mPiconetClock: " |
| + String.format("0x%08X", mPiconetClock) |
| + ", mRetransmissionCount: " |
| + mRetransmissionCount |
| + ", mNoRxCount: " |
| + mNoRxCount |
| + ", mNakCount: " |
| + mNakCount |
| + ", mLastTxAckTimestamp: " |
| + String.format("0x%08X", mLastTxAckTimestamp) |
| + ", mFlowOffCount: " |
| + mFlowOffCount |
| + ",\n" |
| + " mLastFlowOnTimestamp: " |
| + String.format("0x%08X", mLastFlowOnTimestamp) |
| + ", mOverflowCount: " |
| + mOverflowCount |
| + ", mUnderflowCount: " |
| + mUnderflowCount |
| + ", mAddr: " |
| + mAddr |
| + ", mCalFailedItemCount: " |
| + mCalFailedItemCount |
| + "\n }"; |
| |
| return str; |
| } |
| } |
| |
| /** |
| * This class provides the System APIs to access the vendor specific part of Approaching LSTO |
| * event. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final class BqrVsLsto implements Parcelable { |
| private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsLsto"; |
| |
| private int mConnState; |
| private long mBasebandStats; |
| private long mSlotsUsed; |
| private int mCxmDenials; |
| private int mTxSkipped; |
| private int mRfLoss; |
| private long mNativeClock; |
| private long mLastTxAckTimestamp; |
| |
| private BqrVsLsto(byte[] rawData, int offset) { |
| if (rawData == null || rawData.length <= offset) { |
| throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); |
| } |
| |
| ByteBuffer bqrBuf = |
| ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); |
| bqrBuf.order(ByteOrder.LITTLE_ENDIAN); |
| |
| mConnState = bqrBuf.get() & 0xFF; |
| mBasebandStats = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mSlotsUsed = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mCxmDenials = bqrBuf.getShort() & 0xFFFF; |
| mTxSkipped = bqrBuf.getShort() & 0xFFFF; |
| mRfLoss = bqrBuf.getShort() & 0xFFFF; |
| mNativeClock = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mLastTxAckTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; |
| } |
| |
| private BqrVsLsto(Parcel in) { |
| mConnState = in.readInt(); |
| mBasebandStats = in.readLong(); |
| mSlotsUsed = in.readLong(); |
| mCxmDenials = in.readInt(); |
| mTxSkipped = in.readInt(); |
| mRfLoss = in.readInt(); |
| mNativeClock = in.readLong(); |
| mLastTxAckTimestamp = in.readLong(); |
| } |
| |
| /** |
| * Get the conn state of sco. |
| * |
| * @return the conn state |
| * @hide |
| */ |
| @SystemApi |
| public int getConnState() { |
| return mConnState; |
| } |
| |
| /** |
| * Get the string of conn state of sco. |
| * |
| * @param connectionState connection state of sco |
| * @return the string of conn state |
| * @hide |
| */ |
| @SystemApi |
| public static @Nullable String connStateToString(int connectionState) { |
| return ConnState.toString(connectionState); |
| } |
| |
| /** |
| * Get the baseband statistics. |
| * |
| * @return the baseband statistics |
| * @hide |
| */ |
| @SystemApi |
| public long getBasebandStats() { |
| return mBasebandStats; |
| } |
| |
| /** |
| * Get the count of slots allocated for current connection. |
| * |
| * @return the count of slots allocated for current connection |
| * @hide |
| */ |
| @SystemApi |
| public long getSlotsUsed() { |
| return mSlotsUsed; |
| } |
| |
| /** |
| * Get the count of Coex denials. |
| * |
| * @return the count of CXM denials |
| * @hide |
| */ |
| @SystemApi |
| public int getCxmDenials() { |
| return mCxmDenials; |
| } |
| |
| /** |
| * Get the count of TX skipped when no poll from remote device. |
| * |
| * @return the count of TX skipped |
| * @hide |
| */ |
| @SystemApi |
| public int getTxSkipped() { |
| return mTxSkipped; |
| } |
| |
| /** |
| * Get the count of RF loss. |
| * |
| * @return the count of RF loss |
| * @hide |
| */ |
| @SystemApi |
| public int getRfLoss() { |
| return mRfLoss; |
| } |
| |
| /** |
| * Get the timestamp when issue happened. time_ms: N * 0.3125 ms (1 Bluetooth Clock). |
| * |
| * @return the timestamp when issue happened |
| * @hide |
| */ |
| @SystemApi |
| public long getNativeClock() { |
| return mNativeClock; |
| } |
| |
| /** |
| * Get the timestamp of last TX ACK. time_ms: N * 0.3125 ms (1 Bluetooth Clock). |
| * |
| * @return the timestamp of last TX ACK |
| * @hide |
| */ |
| @SystemApi |
| public long getLastTxAckTimestamp() { |
| return mLastTxAckTimestamp; |
| } |
| |
| /** |
| * Describe contents. |
| * |
| * @return 0 |
| * @hide |
| */ |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** |
| * Write BqrVsLsto to parcel. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeInt(mConnState); |
| dest.writeLong(mBasebandStats); |
| dest.writeLong(mSlotsUsed); |
| dest.writeInt(mCxmDenials); |
| dest.writeInt(mTxSkipped); |
| dest.writeInt(mRfLoss); |
| dest.writeLong(mNativeClock); |
| dest.writeLong(mLastTxAckTimestamp); |
| } |
| |
| /** @hide */ |
| @SystemApi |
| public static final @NonNull Parcelable.Creator<BqrVsLsto> CREATOR = |
| new Parcelable.Creator<BqrVsLsto>() { |
| public BqrVsLsto createFromParcel(Parcel in) { |
| return new BqrVsLsto(in); |
| } |
| |
| public BqrVsLsto[] newArray(int size) { |
| return new BqrVsLsto[size]; |
| } |
| }; |
| |
| /** BqrVsLsto to String. */ |
| @Override |
| @NonNull |
| public String toString() { |
| String str; |
| str = |
| " BqrVsLsto: {\n" |
| + " mConnState: " |
| + connStateToString(getConnState()) |
| + "(" |
| + String.format("0x%02X", mConnState) |
| + ")" |
| + ", mBasebandStats: " |
| + String.format("0x%08X", mBasebandStats) |
| + ", mSlotsUsed: " |
| + mSlotsUsed |
| + ", mCxmDenials: " |
| + mCxmDenials |
| + ", mTxSkipped: " |
| + mTxSkipped |
| + ", mRfLoss: " |
| + mRfLoss |
| + ", mNativeClock: " |
| + String.format("0x%08X", mNativeClock) |
| + ", mLastTxAckTimestamp: " |
| + String.format("0x%08X", mLastTxAckTimestamp) |
| + "\n }"; |
| |
| return str; |
| } |
| } |
| |
| /** |
| * This class provides the System APIs to access the vendor specific part of A2dp choppy event. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final class BqrVsA2dpChoppy implements Parcelable { |
| private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsA2dpChoppy"; |
| |
| private long mArrivalTime; |
| private long mScheduleTime; |
| private int mGlitchCount; |
| private int mTxCxmDenials; |
| private int mRxCxmDenials; |
| private int mAclTxQueueLength; |
| private int mLinkQuality; |
| |
| private BqrVsA2dpChoppy(byte[] rawData, int offset) { |
| if (rawData == null || rawData.length <= offset) { |
| throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); |
| } |
| |
| ByteBuffer bqrBuf = |
| ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); |
| bqrBuf.order(ByteOrder.LITTLE_ENDIAN); |
| |
| mArrivalTime = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mScheduleTime = bqrBuf.getInt() & 0xFFFFFFFFL; |
| mGlitchCount = bqrBuf.getShort() & 0xFFFF; |
| mTxCxmDenials = bqrBuf.getShort() & 0xFFFF; |
| mRxCxmDenials = bqrBuf.getShort() & 0xFFFF; |
| mAclTxQueueLength = bqrBuf.get() & 0xFF; |
| mLinkQuality = bqrBuf.get() & 0xFF; |
| } |
| |
| private BqrVsA2dpChoppy(Parcel in) { |
| mArrivalTime = in.readLong(); |
| mScheduleTime = in.readLong(); |
| mGlitchCount = in.readInt(); |
| mTxCxmDenials = in.readInt(); |
| mRxCxmDenials = in.readInt(); |
| mAclTxQueueLength = in.readInt(); |
| mLinkQuality = in.readInt(); |
| } |
| |
| /** |
| * Get the timestamp of a2dp packet arrived. time_ms: N * 0.3125 ms (1 Bluetooth Clock). |
| * |
| * @return the timestamp of a2dp packet arrived |
| * @hide |
| */ |
| @SystemApi |
| public long getArrivalTime() { |
| return mArrivalTime; |
| } |
| |
| /** |
| * Get the timestamp of a2dp packet scheduled. time_ms: N * 0.3125 ms (1 Bluetooth Clock). |
| * |
| * @return the timestamp of a2dp packet scheduled |
| * @hide |
| */ |
| @SystemApi |
| public long getScheduleTime() { |
| return mScheduleTime; |
| } |
| |
| /** |
| * Get the a2dp glitch count since the last event. |
| * |
| * @return the a2dp glitch count |
| * @hide |
| */ |
| @SystemApi |
| public int getGlitchCount() { |
| return mGlitchCount; |
| } |
| |
| /** |
| * Get the count of Coex TX denials. |
| * |
| * @return the count of Coex TX denials |
| * @hide |
| */ |
| @SystemApi |
| public int getTxCxmDenials() { |
| return mTxCxmDenials; |
| } |
| |
| /** |
| * Get the count of Coex RX denials. |
| * |
| * @return the count of Coex RX denials |
| * @hide |
| */ |
| @SystemApi |
| public int getRxCxmDenials() { |
| return mRxCxmDenials; |
| } |
| |
| /** |
| * Get the ACL queue length which are pending TX in FW. |
| * |
| * @return the ACL queue length |
| * @hide |
| */ |
| @SystemApi |
| public int getAclTxQueueLength() { |
| return mAclTxQueueLength; |
| } |
| |
| /** |
| * Get the link quality for the current connection. |
| * |
| * @return the link quality |
| * @hide |
| */ |
| @SystemApi |
| public int getLinkQuality() { |
| return mLinkQuality; |
| } |
| |
| /** |
| * Get the string of link quality for the current connection. |
| * |
| * @param linkQuality link quality for the current connection |
| * @return the string of link quality |
| * @hide |
| */ |
| @SystemApi |
| public static @Nullable String linkQualityToString(int linkQuality) { |
| LinkQuality q = LinkQuality.fromOrdinal(linkQuality); |
| return q.toString(); |
| } |
| |
| /** |
| * Describe contents. |
| * |
| * @return 0 |
| * @hide |
| */ |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** |
| * Write BqrVsA2dpChoppy to parcel. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeLong(mArrivalTime); |
| dest.writeLong(mScheduleTime); |
| dest.writeInt(mGlitchCount); |
| dest.writeInt(mTxCxmDenials); |
| dest.writeInt(mRxCxmDenials); |
| dest.writeInt(mAclTxQueueLength); |
| dest.writeInt(mLinkQuality); |
| } |
| |
| /** @hide */ |
| @SystemApi |
| public static final @NonNull Parcelable.Creator<BqrVsA2dpChoppy> CREATOR = |
| new Parcelable.Creator<BqrVsA2dpChoppy>() { |
| public BqrVsA2dpChoppy createFromParcel(Parcel in) { |
| return new BqrVsA2dpChoppy(in); |
| } |
| |
| public BqrVsA2dpChoppy[] newArray(int size) { |
| return new BqrVsA2dpChoppy[size]; |
| } |
| }; |
| |
| /** BqrVsA2dpChoppy to String. */ |
| @Override |
| @NonNull |
| public String toString() { |
| String str; |
| str = |
| " BqrVsA2dpChoppy: {\n" |
| + " mArrivalTime: " |
| + String.format("0x%08X", mArrivalTime) |
| + ", mScheduleTime: " |
| + String.format("0x%08X", mScheduleTime) |
| + ", mGlitchCount: " |
| + mGlitchCount |
| + ", mTxCxmDenials: " |
| + mTxCxmDenials |
| + ", mRxCxmDenials: " |
| + mRxCxmDenials |
| + ", mAclTxQueueLength: " |
| + mAclTxQueueLength |
| + ", mLinkQuality: " |
| + linkQualityToString(mLinkQuality) |
| + "(" |
| + String.format("0x%02X", mLinkQuality) |
| + ")" |
| + "\n }"; |
| |
| return str; |
| } |
| } |
| |
| /** |
| * This class provides the System APIs to access the vendor specific part of SCO choppy event. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final class BqrVsScoChoppy implements Parcelable { |
| private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsScoChoppy"; |
| |
| private int mGlitchCount; |
| private int mIntervalEsco; |
| private int mWindowEsco; |
| private int mAirFormat; |
| private int mInstanceCount; |
| private int mTxCxmDenials; |
| private int mRxCxmDenials; |
| private int mTxAbortCount; |
| private int mLateDispatch; |
| private int mMicIntrMiss; |
| private int mLpaIntrMiss; |
| private int mSprIntrMiss; |
| private int mPlcFillCount; |
| private int mPlcDiscardCount; |
| private int mMissedInstanceCount; |
| private int mTxRetransmitSlotCount; |
| private int mRxRetransmitSlotCount; |
| private int mGoodRxFrameCount; |
| |
| private BqrVsScoChoppy(byte[] rawData, int offset) { |
| if (rawData == null || rawData.length <= offset) { |
| throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); |
| } |
| |
| ByteBuffer bqrBuf = |
| ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); |
| bqrBuf.order(ByteOrder.LITTLE_ENDIAN); |
| |
| mGlitchCount = bqrBuf.getShort() & 0xFFFF; |
| mIntervalEsco = bqrBuf.get() & 0xFF; |
| mWindowEsco = bqrBuf.get() & 0xFF; |
| mAirFormat = bqrBuf.get() & 0xFF; |
| mInstanceCount = bqrBuf.getShort() & 0xFFFF; |
| mTxCxmDenials = bqrBuf.getShort() & 0xFFFF; |
| mRxCxmDenials = bqrBuf.getShort() & 0xFFFF; |
| mTxAbortCount = bqrBuf.getShort() & 0xFFFF; |
| mLateDispatch = bqrBuf.getShort() & 0xFFFF; |
| mMicIntrMiss = bqrBuf.getShort() & 0xFFFF; |
| mLpaIntrMiss = bqrBuf.getShort() & 0xFFFF; |
| mSprIntrMiss = bqrBuf.getShort() & 0xFFFF; |
| mPlcFillCount = bqrBuf.getShort() & 0xFFFF; |
| mPlcDiscardCount = bqrBuf.getShort() & 0xFFFF; |
| mMissedInstanceCount = bqrBuf.getShort() & 0xFFFF; |
| mTxRetransmitSlotCount = bqrBuf.getShort() & 0xFFFF; |
| mRxRetransmitSlotCount = bqrBuf.getShort() & 0xFFFF; |
| mGoodRxFrameCount = bqrBuf.getShort() & 0xFFFF; |
| } |
| |
| private BqrVsScoChoppy(Parcel in) { |
| mGlitchCount = in.readInt(); |
| mIntervalEsco = in.readInt(); |
| mWindowEsco = in.readInt(); |
| mAirFormat = in.readInt(); |
| mInstanceCount = in.readInt(); |
| mTxCxmDenials = in.readInt(); |
| mRxCxmDenials = in.readInt(); |
| mTxAbortCount = in.readInt(); |
| mLateDispatch = in.readInt(); |
| mMicIntrMiss = in.readInt(); |
| mLpaIntrMiss = in.readInt(); |
| mSprIntrMiss = in.readInt(); |
| mPlcFillCount = in.readInt(); |
| mPlcDiscardCount = in.readInt(); |
| mMissedInstanceCount = in.readInt(); |
| mTxRetransmitSlotCount = in.readInt(); |
| mRxRetransmitSlotCount = in.readInt(); |
| mGoodRxFrameCount = in.readInt(); |
| } |
| |
| /** |
| * Get the sco glitch count since the last event. |
| * |
| * @return the sco glitch count |
| * @hide |
| */ |
| @SystemApi |
| public int getGlitchCount() { |
| return mGlitchCount; |
| } |
| |
| /** |
| * Get ESCO interval in slots. It is the value of Transmission_Interval parameter in |
| * Synchronous Connection Complete event. |
| * |
| * @return ESCO interval in slots |
| * @hide |
| */ |
| @SystemApi |
| public int getIntervalEsco() { |
| return mIntervalEsco; |
| } |
| |
| /** |
| * Get ESCO window in slots. It is the value of Retransmission Window parameter in |
| * Synchronous Connection Complete event. |
| * |
| * @return ESCO window in slots |
| * @hide |
| */ |
| @SystemApi |
| public int getWindowEsco() { |
| return mWindowEsco; |
| } |
| |
| /** |
| * Get the air mode. It is the value of Air Mode parameter in Synchronous Connection |
| * Complete event. |
| * |
| * @return the air mode |
| * @hide |
| */ |
| @SystemApi |
| public int getAirFormat() { |
| return mAirFormat; |
| } |
| |
| /** |
| * Get the string of air mode. |
| * |
| * @param airFormat the value of Air Mode parameter in Synchronous Connection Complete event |
| * @return the string of air mode |
| * @hide |
| */ |
| @SystemApi |
| public static @Nullable String airFormatToString(int airFormat) { |
| AirMode m = AirMode.fromOrdinal(airFormat); |
| return m.toString(); |
| } |
| |
| /** |
| * Get the xSCO instance count. |
| * |
| * @return the xSCO instance count |
| * @hide |
| */ |
| @SystemApi |
| public int getInstanceCount() { |
| return mInstanceCount; |
| } |
| |
| /** |
| * Get the count of Coex TX denials. |
| * |
| * @return the count of Coex TX denials |
| * @hide |
| */ |
| @SystemApi |
| public int getTxCxmDenials() { |
| return mTxCxmDenials; |
| } |
| |
| /** |
| * Get the count of Coex RX denials. |
| * |
| * @return the count of Coex RX denials |
| * @hide |
| */ |
| @SystemApi |
| public int getRxCxmDenials() { |
| return mRxCxmDenials; |
| } |
| |
| /** |
| * Get the count of sco packets aborted. |
| * |
| * @return the count of sco packets aborted |
| * @hide |
| */ |
| @SystemApi |
| public int getTxAbortCount() { |
| return mTxAbortCount; |
| } |
| |
| /** |
| * Get the count of sco packets dispatched late. |
| * |
| * @return the count of sco packets dispatched late |
| * @hide |
| */ |
| @SystemApi |
| public int getLateDispatch() { |
| return mLateDispatch; |
| } |
| |
| /** |
| * Get the count of missed Mic interrupts. |
| * |
| * @return the count of missed Mic interrupts |
| * @hide |
| */ |
| @SystemApi |
| public int getMicIntrMiss() { |
| return mMicIntrMiss; |
| } |
| |
| /** |
| * Get the count of missed LPA interrupts. |
| * |
| * @return the count of missed LPA interrupts |
| * @hide |
| */ |
| @SystemApi |
| public int getLpaIntrMiss() { |
| return mLpaIntrMiss; |
| } |
| |
| /** |
| * Get the count of missed Speaker interrupts. |
| * |
| * @return the count of missed Speaker interrupts |
| * @hide |
| */ |
| @SystemApi |
| public int getSprIntrMiss() { |
| return mSprIntrMiss; |
| } |
| |
| /** |
| * Get the count of packet loss concealment filled. |
| * |
| * @return the count of packet loss concealment filled |
| * @hide |
| */ |
| @SystemApi |
| public int getPlcFillCount() { |
| return mPlcFillCount; |
| } |
| |
| /** |
| * Get the count of packet loss concealment discarded. |
| * |
| * @return the count of packet loss concealment discarded |
| * @hide |
| */ |
| @SystemApi |
| public int getPlcDiscardCount() { |
| return mPlcDiscardCount; |
| } |
| |
| /** |
| * Get the count of sco instances missed. |
| * |
| * @return the count of sco instances missed |
| * @hide |
| */ |
| @SystemApi |
| public int getMissedInstanceCount() { |
| return mMissedInstanceCount; |
| } |
| |
| /** |
| * Get the count of slots for Tx retransmission. |
| * |
| * @return the count of slots for Tx retransmission |
| * @hide |
| */ |
| @SystemApi |
| public int getTxRetransmitSlotCount() { |
| return mTxRetransmitSlotCount; |
| } |
| |
| /** |
| * Get the count of slots for Rx retransmission. |
| * |
| * @return the count of slots for Rx retransmission |
| * @hide |
| */ |
| @SystemApi |
| public int getRxRetransmitSlotCount() { |
| return mRxRetransmitSlotCount; |
| } |
| |
| /** |
| * Get the count of Rx good packets |
| * |
| * @return the count of Rx good packets |
| * @hide |
| */ |
| @SystemApi |
| public int getGoodRxFrameCount() { |
| return mGoodRxFrameCount; |
| } |
| |
| /** |
| * Describe contents. |
| * |
| * @return 0 |
| * @hide |
| */ |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** |
| * Write BqrVsScoChoppy to parcel. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeInt(mGlitchCount); |
| dest.writeInt(mIntervalEsco); |
| dest.writeInt(mWindowEsco); |
| dest.writeInt(mAirFormat); |
| dest.writeInt(mInstanceCount); |
| dest.writeInt(mTxCxmDenials); |
| dest.writeInt(mRxCxmDenials); |
| dest.writeInt(mTxAbortCount); |
| dest.writeInt(mLateDispatch); |
| dest.writeInt(mMicIntrMiss); |
| dest.writeInt(mLpaIntrMiss); |
| dest.writeInt(mSprIntrMiss); |
| dest.writeInt(mPlcFillCount); |
| dest.writeInt(mPlcDiscardCount); |
| dest.writeInt(mMissedInstanceCount); |
| dest.writeInt(mTxRetransmitSlotCount); |
| dest.writeInt(mRxRetransmitSlotCount); |
| dest.writeInt(mGoodRxFrameCount); |
| } |
| |
| /** @hide */ |
| @SystemApi |
| public static final @NonNull Parcelable.Creator<BqrVsScoChoppy> CREATOR = |
| new Parcelable.Creator<BqrVsScoChoppy>() { |
| public BqrVsScoChoppy createFromParcel(Parcel in) { |
| return new BqrVsScoChoppy(in); |
| } |
| |
| public BqrVsScoChoppy[] newArray(int size) { |
| return new BqrVsScoChoppy[size]; |
| } |
| }; |
| |
| /** BqrVsScoChoppy to String. */ |
| @Override |
| @NonNull |
| public String toString() { |
| String str; |
| str = |
| " BqrVsScoChoppy: {\n" |
| + " mGlitchCount: " |
| + mGlitchCount |
| + ", mIntervalEsco: " |
| + mIntervalEsco |
| + ", mWindowEsco: " |
| + mWindowEsco |
| + ", mAirFormat: " |
| + airFormatToString(mAirFormat) |
| + "(" |
| + String.format("0x%02X", mAirFormat) |
| + ")" |
| + ", mInstanceCount: " |
| + mInstanceCount |
| + ", mTxCxmDenials: " |
| + mTxCxmDenials |
| + ", mRxCxmDenials: " |
| + mRxCxmDenials |
| + ", mTxAbortCount: " |
| + mTxAbortCount |
| + ",\n" |
| + " mLateDispatch: " |
| + mLateDispatch |
| + ", mMicIntrMiss: " |
| + mMicIntrMiss |
| + ", mLpaIntrMiss: " |
| + mLpaIntrMiss |
| + ", mSprIntrMiss: " |
| + mSprIntrMiss |
| + ", mPlcFillCount: " |
| + mPlcFillCount |
| + ", mPlcDiscardCount: " |
| + mPlcDiscardCount |
| + ", mMissedInstanceCount: " |
| + mMissedInstanceCount |
| + ", mTxRetransmitSlotCount: " |
| + mTxRetransmitSlotCount |
| + ",\n" |
| + " mRxRetransmitSlotCount: " |
| + mRxRetransmitSlotCount |
| + ", mGoodRxFrameCount: " |
| + mGoodRxFrameCount |
| + "\n }"; |
| |
| return str; |
| } |
| } |
| |
| /** |
| * This class provides the System APIs to access the Connect fail event. |
| * |
| * @hide |
| */ |
| @SystemApi |
| public static final class BqrConnectFail implements Parcelable { |
| private static final String TAG = BluetoothQualityReport.TAG + ".BqrConnectFail"; |
| |
| /** |
| * Connect Fail reason: No error. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int CONNECT_FAIL_ID_NO_ERROR = 0x00; |
| |
| /** |
| * Connect Fail reason: Page timeout. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int CONNECT_FAIL_ID_PAGE_TIMEOUT = 0x04; |
| |
| /** |
| * Connect Fail reason: Connection timeout. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int CONNECT_FAIL_ID_CONNECTION_TIMEOUT = 0x08; |
| |
| /** |
| * Connect Fail reason: ACL already exists. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int CONNECT_FAIL_ID_ACL_ALREADY_EXIST = 0x0b; |
| |
| /** |
| * Connect Fail reason: Controller busy. |
| * |
| * @hide |
| */ |
| @SystemApi public static final int CONNECT_FAIL_ID_CONTROLLER_BUSY = 0x3a; |
| |
| /** @hide */ |
| @Retention(RetentionPolicy.SOURCE) |
| @IntDef( |
| prefix = {"CONNECT_FAIL_ID"}, |
| value = { |
| CONNECT_FAIL_ID_NO_ERROR, |
| CONNECT_FAIL_ID_PAGE_TIMEOUT, |
| CONNECT_FAIL_ID_CONNECTION_TIMEOUT, |
| CONNECT_FAIL_ID_ACL_ALREADY_EXIST, |
| CONNECT_FAIL_ID_CONTROLLER_BUSY, |
| }) |
| public @interface ConnectFailId {} |
| |
| private int mFailReason; |
| |
| private BqrConnectFail(byte[] rawData, int offset) { |
| if (rawData == null || rawData.length <= offset) { |
| throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); |
| } |
| |
| ByteBuffer bqrBuf = |
| ByteBuffer.wrap(rawData, offset, rawData.length - offset).asReadOnlyBuffer(); |
| bqrBuf.order(ByteOrder.LITTLE_ENDIAN); |
| |
| mFailReason = bqrBuf.get() & 0xFF; |
| } |
| |
| private BqrConnectFail(Parcel in) { |
| mFailReason = in.readInt(); |
| } |
| |
| /** |
| * Get the fail reason. |
| * |
| * @return the fail reason |
| * @hide |
| */ |
| @SystemApi |
| @ConnectFailId |
| public int getFailReason() { |
| return mFailReason; |
| } |
| |
| /** |
| * Describe contents. |
| * |
| * @return 0 |
| * @hide |
| */ |
| public int describeContents() { |
| return 0; |
| } |
| |
| /** |
| * Write BqrConnectFail to parcel. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeInt(mFailReason); |
| } |
| |
| /** @hide */ |
| @SystemApi |
| public static final @NonNull Parcelable.Creator<BqrConnectFail> CREATOR = |
| new Parcelable.Creator<BqrConnectFail>() { |
| public BqrConnectFail createFromParcel(Parcel in) { |
| return new BqrConnectFail(in); |
| } |
| |
| public BqrConnectFail[] newArray(int size) { |
| return new BqrConnectFail[size]; |
| } |
| }; |
| |
| /** |
| * Get the string of the Connect Fail ID. |
| * |
| * @param id the connect fail reason |
| * @return the string of the id |
| * @hide |
| */ |
| @SystemApi |
| public static @NonNull String connectFailIdToString(@ConnectFailId int id) { |
| switch (id) { |
| case CONNECT_FAIL_ID_NO_ERROR: |
| return "No error"; |
| case CONNECT_FAIL_ID_PAGE_TIMEOUT: |
| return "Page Timeout"; |
| case CONNECT_FAIL_ID_CONNECTION_TIMEOUT: |
| return "Connection Timeout"; |
| case CONNECT_FAIL_ID_ACL_ALREADY_EXIST: |
| return "ACL already exists"; |
| case CONNECT_FAIL_ID_CONTROLLER_BUSY: |
| return "Controller busy"; |
| default: |
| return "INVALID"; |
| } |
| } |
| |
| /** BqrConnectFail to String. */ |
| @Override |
| @NonNull |
| public String toString() { |
| String str; |
| str = |
| " BqrConnectFail: {\n" |
| + " mFailReason: " |
| + connectFailIdToString(mFailReason) |
| + " (" |
| + String.format("0x%02X", mFailReason) |
| + ")" |
| + "\n }"; |
| |
| return str; |
| } |
| } |
| } |