diff options
-rw-r--r-- | core/java/android/bluetooth/BluetoothAdapter.java | 25 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothQualityReport.java | 1055 |
2 files changed, 979 insertions, 101 deletions
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index ea6fddbfac73..63eff19d3600 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -15,6 +15,12 @@ * limitations under the License. */ +/* + * Changes from Qualcomm Innovation Center are provided under the following license: + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + package android.bluetooth; import static java.util.Objects.requireNonNull; @@ -395,6 +401,25 @@ public final class BluetoothAdapter { public static final String EXTRA_PREVIOUS_SCAN_MODE = "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE"; + /** + * Broadcast Action: Broadcast details of IOT device when an IOT + * related issue is observed. + * <p>Always contains the extra fields {@link #EXTRA_NAME}. + * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive. + * @hide + **/ + + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_REMOTE_ISSUE_OCCURRED = + "org.codeaurora.intent.bluetooth.action.REMOTE_ISSUE_OCCURRED"; + + /** + * Used as a Parcelable {@link BluetoothQualityReport} extra field in + * {@link #ACTION_REMOTE_ISSUE_OCCURRED} intent. It contains the {@link BluetoothQualityReport}. + * @hide + */ + public static final String EXTRA_BQR = "android.bluetooth.qti.extra.EXTRA_BQR"; + /** @hide */ @IntDef(prefix = { "SCAN_" }, value = { SCAN_MODE_NONE, diff --git a/core/java/android/bluetooth/BluetoothQualityReport.java b/core/java/android/bluetooth/BluetoothQualityReport.java index e9ed008b6954..0e225371ad04 100644 --- a/core/java/android/bluetooth/BluetoothQualityReport.java +++ b/core/java/android/bluetooth/BluetoothQualityReport.java @@ -27,6 +27,12 @@ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/* + * Changes from Qualcomm Innovation Center are provided under the following license: + * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * SPDX-License-Identifier: BSD-3-Clause-Clear + */ + package android.bluetooth; import android.annotation.NonNull; @@ -77,8 +83,12 @@ public final class BluetoothQualityReport implements Parcelable { public static final int QUALITY_REPORT_ID_APPROACH_LSTO = 0x02; public static final int QUALITY_REPORT_ID_A2DP_CHOPPY = 0x03; public static final int QUALITY_REPORT_ID_SCO_CHOPPY = 0x04; + public static final int QUALITY_REPORT_ID_VENDOR_SPECIFIC = 0x10; /* Vendor Specific Report IDs from 0x20 */ public static final int QUALITY_REPORT_ID_CONN_FAIL = 0x20; + public static final int QUALITY_REPORT_ID_CONN_FAIL_BQR5 = 0x08; + public static final int QUALITY_REPORT_ID_VS_DISC_MONITOR = 0x01; + public static final int QUALITY_REPORT_ID_VS_MISC_MONITOR = 0x02; private String mAddr; private int mLmpVer; @@ -86,14 +96,18 @@ public final class BluetoothQualityReport implements Parcelable { private int mManufacturerId; private String mName; private int mBluetoothClass; + private boolean mVendorBqr5; private BqrCommon mBqrCommon; private BqrVsCommon mBqrVsCommon; + private BqrVsQualityMonitor mBqrVsQualityMonitor; private BqrVsLsto mBqrVsLsto; private BqrVsA2dpChoppy mBqrVsA2dpChoppy; private BqrVsScoChoppy mBqrVsScoChoppy; private BqrVsConnectFail mBqrVsConnectFail; + private BqrVsDiscoveryMonitoring mBqrVsDiscMonitoring; + private BqrVsMiscMonitoring mBqrVsMiscMonitoring; enum PacketType { INVALID, TYPE_ID, TYPE_NULL, TYPE_POLL, TYPE_FHS, TYPE_HV1, TYPE_HV2, TYPE_HV3, @@ -203,8 +217,81 @@ public final class BluetoothQualityReport implements Parcelable { } } + + public BluetoothQualityReport(String remoteAddr, int lmpVer, int lmpSubVer, + int manufacturerId, String remoteName, int remoteCoD, byte[] rawData, + boolean vendorBqr5) { + mVendorBqr5 = vendorBqr5; + if (!BluetoothAdapter.checkBluetoothAddress(remoteAddr)) { + Log.d(TAG, "remote addr is invalid"); + mAddr = "00:00:00:00:00:00"; + } else { + mAddr = remoteAddr; + } + + mLmpVer = lmpVer; + mLmpSubVer = lmpSubVer; + mManufacturerId = manufacturerId; + if (remoteName == null) { + Log.d(TAG, "remote name is null"); + mName = ""; + } else { + mName = remoteName; + } + mBluetoothClass = remoteCoD; + + mBqrCommon = new BqrCommon(rawData, 0, vendorBqr5); + int id = mBqrCommon.getQualityReportId(); + int vsPartOffset = 0; + if (id == QUALITY_REPORT_ID_MONITOR || + id == QUALITY_REPORT_ID_APPROACH_LSTO || + id == QUALITY_REPORT_ID_A2DP_CHOPPY || + id == QUALITY_REPORT_ID_SCO_CHOPPY) { + mBqrVsCommon = new BqrVsCommon(rawData, BqrCommon.BQR_COMMON_LEN); + vsPartOffset = BqrCommon.BQR_COMMON_LEN + mBqrVsCommon.getLength(); + } + + if (mVendorBqr5 == true && id == QUALITY_REPORT_ID_CONN_FAIL_BQR5) { + mBqrVsCommon = new BqrVsCommon(rawData, BqrCommon.BQR_COMMON_LEN); + vsPartOffset = BqrCommon.BQR_COMMON_LEN + mBqrVsCommon.getLength(); + } + + if (mVendorBqr5 == false && id == QUALITY_REPORT_ID_CONN_FAIL) { + mBqrVsCommon = new BqrVsCommon(rawData, BqrCommon.BQR_COMMON_LEN); + vsPartOffset = BqrCommon.BQR_COMMON_LEN + mBqrVsCommon.getLength(); + } + + if (mVendorBqr5 == true && id == QUALITY_REPORT_ID_MONITOR) { + mBqrVsQualityMonitor = new BqrVsQualityMonitor(rawData, vsPartOffset); + } else if (mVendorBqr5 == false && id == QUALITY_REPORT_ID_MONITOR){ + return; + } else 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(mVendorBqr5 == true && + id == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + int vsId = mBqrCommon.getVendorQualityReportId(); + if (vsId == QUALITY_REPORT_ID_VS_DISC_MONITOR) { + mBqrVsDiscMonitoring = new BqrVsDiscoveryMonitoring(rawData, 2); + } else if (vsId == QUALITY_REPORT_ID_VS_MISC_MONITOR) { + mBqrVsMiscMonitoring = new BqrVsMiscMonitoring(rawData, 2); + } + } else if ((mVendorBqr5 == true && + id == QUALITY_REPORT_ID_CONN_FAIL_BQR5) || + (mVendorBqr5 == false && + id == QUALITY_REPORT_ID_CONN_FAIL)) { + mBqrVsConnectFail = new BqrVsConnectFail(rawData, vsPartOffset); + } else { + throw new IllegalArgumentException(TAG + ": unkown quality report id:" + id); + } + } + private BluetoothQualityReport(Parcel in) { mBqrCommon = new BqrCommon(in); + mVendorBqr5 = in.readBoolean(); mAddr = in.readString(); mLmpVer = in.readInt(); mLmpSubVer = in.readInt(); @@ -212,15 +299,44 @@ public final class BluetoothQualityReport implements Parcelable { mName = in.readString(); mBluetoothClass = in.readInt(); - mBqrVsCommon = new BqrVsCommon(in); int id = mBqrCommon.getQualityReportId(); - if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { + if (id == QUALITY_REPORT_ID_MONITOR || + id == QUALITY_REPORT_ID_APPROACH_LSTO || + id == QUALITY_REPORT_ID_A2DP_CHOPPY || + id == QUALITY_REPORT_ID_SCO_CHOPPY) { + mBqrVsCommon = new BqrVsCommon(in); + } + + if (mVendorBqr5 == true && id == QUALITY_REPORT_ID_CONN_FAIL_BQR5) { + mBqrVsCommon = new BqrVsCommon(in); + } + + if (mVendorBqr5 == false && id == QUALITY_REPORT_ID_CONN_FAIL) { + mBqrVsCommon = new BqrVsCommon(in); + } + + if (mVendorBqr5 == true && id == QUALITY_REPORT_ID_MONITOR) { + mBqrVsQualityMonitor = new BqrVsQualityMonitor(in); + } else if (mVendorBqr5 == false && id == QUALITY_REPORT_ID_MONITOR) { + return; + } else 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) { + } else if(mVendorBqr5 == true && + id == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + int vsId = mBqrCommon.getVendorQualityReportId(); + if (vsId == QUALITY_REPORT_ID_VS_DISC_MONITOR) { + mBqrVsDiscMonitoring = new BqrVsDiscoveryMonitoring(in); + } else if (vsId == QUALITY_REPORT_ID_VS_MISC_MONITOR) { + mBqrVsMiscMonitoring = new BqrVsMiscMonitoring(in); + } + } else if ((mVendorBqr5 == true && + id == QUALITY_REPORT_ID_CONN_FAIL_BQR5) || + (mVendorBqr5 == false && + id == QUALITY_REPORT_ID_CONN_FAIL)) { mBqrVsConnectFail = new BqrVsConnectFail(in); } } @@ -236,25 +352,59 @@ public final class BluetoothQualityReport implements Parcelable { } /** + * Get the vendor quality report id. + * @return the id, is one of {@link #QUALITY_REPORT_ID_VS_DISC_MONITOR}, + * {@link #QUALITY_REPORT_ID_VS_MISC_MONITOR}. + */ + public int getVendorQualityReportId() { + return mBqrCommon.getVendorQualityReportId(); + } + + /** * Get the string of the quality report id. * @return the string of the id. */ public String getQualityReportIdStr() { int id = mBqrCommon.getQualityReportId(); - 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"; + if (id == QUALITY_REPORT_ID_MONITOR) { + return "Quality monitor"; + } else if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { + return "Approaching LSTO"; + } else if (id == QUALITY_REPORT_ID_A2DP_CHOPPY) { + return "A2DP choppy"; + } else if (id == QUALITY_REPORT_ID_SCO_CHOPPY) { + return "SCO choppy"; + } else if(mVendorBqr5 == true && + id == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + return "Vendor specific"; + } else if ((mVendorBqr5 == true && + id == QUALITY_REPORT_ID_CONN_FAIL_BQR5) || + (mVendorBqr5 == false && + id == QUALITY_REPORT_ID_CONN_FAIL)) { + return "Connect failed"; + } else { + return "Invalid"; + } + } + + /** + * Get the string of the vendor quality report id. + * @return the string of the id. + */ + public String getVendorQualityReportIdStr() { + int id = mBqrCommon.getQualityReportId(); + if(mVendorBqr5 == true && + id == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + int vsId = mBqrCommon.getVendorQualityReportId(); + if (vsId == QUALITY_REPORT_ID_VS_DISC_MONITOR) { + return "Discovery Monitoring"; + } else if (vsId == QUALITY_REPORT_ID_VS_MISC_MONITOR) { + return "Misc Monitoring"; + } + } else { + return "Invalid"; } + return "Invalid"; } /** @@ -266,6 +416,14 @@ public final class BluetoothQualityReport implements Parcelable { } /** + * Is Vendor BQR5 Enabled. + * @return true if Vendor BQR5 Enabled otherwise false. + */ + public boolean isVendorBqr5() { + return mVendorBqr5; + } + + /** * Get LMP version of remote device in this report. * @return LMP version of remote device. */ @@ -375,21 +533,51 @@ public final class BluetoothQualityReport implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { mBqrCommon.writeToParcel(out, flags); + out.writeBoolean(mVendorBqr5); out.writeString(mAddr); out.writeInt(mLmpVer); out.writeInt(mLmpSubVer); out.writeInt(mManufacturerId); out.writeString(mName); out.writeInt(mBluetoothClass); - mBqrVsCommon.writeToParcel(out, flags); int id = mBqrCommon.getQualityReportId(); - if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { + if (id == QUALITY_REPORT_ID_MONITOR || + id == QUALITY_REPORT_ID_APPROACH_LSTO || + id == QUALITY_REPORT_ID_A2DP_CHOPPY || + id == QUALITY_REPORT_ID_SCO_CHOPPY) { + mBqrVsCommon.writeToParcel(out, flags); + } + + if (mVendorBqr5 == true && id == QUALITY_REPORT_ID_CONN_FAIL_BQR5) { + mBqrVsCommon.writeToParcel(out, flags); + } + + if (mVendorBqr5 == false && id == QUALITY_REPORT_ID_CONN_FAIL) { + mBqrVsCommon.writeToParcel(out, flags); + } + + if (mVendorBqr5 == true && id == QUALITY_REPORT_ID_MONITOR) { + mBqrVsQualityMonitor.writeToParcel(out, flags); + } else if (mVendorBqr5 == false && id == QUALITY_REPORT_ID_MONITOR) { + return; + } else 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) { + } else if(mVendorBqr5 == true && + id == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + int vsId = mBqrCommon.getVendorQualityReportId(); + if (vsId == QUALITY_REPORT_ID_VS_DISC_MONITOR) { + mBqrVsDiscMonitoring.writeToParcel(out, flags); + } else if (vsId == QUALITY_REPORT_ID_VS_MISC_MONITOR) { + mBqrVsMiscMonitoring.writeToParcel(out, flags); + } + } else if ((mVendorBqr5 == true && + id == QUALITY_REPORT_ID_CONN_FAIL_BQR5) || + (mVendorBqr5 == false && + id == QUALITY_REPORT_ID_CONN_FAIL)) { mBqrVsConnectFail.writeToParcel(out, flags); } } @@ -398,6 +586,7 @@ public final class BluetoothQualityReport implements Parcelable { public String toString() { String str; str = "BQR: {\n" + + " mVendorBqr5: " + mVendorBqr5 + " mAddr: " + mAddr + ", mLmpVer: " + String.format("0x%02X", mLmpVer) + ", mLmpSubVer: " + String.format("0x%04X", mLmpSubVer) @@ -405,22 +594,35 @@ public final class BluetoothQualityReport implements Parcelable { + ", mName: " + mName + ", mBluetoothClass: " + String.format("0x%X", mBluetoothClass) + ",\n" - + mBqrCommon + "\n" - + mBqrVsCommon + "\n"; + + mBqrCommon + "\n"; int id = mBqrCommon.getQualityReportId(); - if (id == QUALITY_REPORT_ID_APPROACH_LSTO) { + if(!(mVendorBqr5 == true && + id == QUALITY_REPORT_ID_VENDOR_SPECIFIC)){ + str += mBqrVsCommon + "\n"; + } + if (mVendorBqr5 == true && id == QUALITY_REPORT_ID_MONITOR) { + str += mBqrVsQualityMonitor + "\n}"; + } else 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) { + } else if(mVendorBqr5 == true && + id == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + int vsId = mBqrCommon.getVendorQualityReportId(); + if (vsId == QUALITY_REPORT_ID_VS_DISC_MONITOR) { + str += mBqrVsDiscMonitoring + "\n}"; + } else if (vsId == QUALITY_REPORT_ID_VS_MISC_MONITOR) { + str += mBqrVsMiscMonitoring + "\n}"; + } + } else if ((mVendorBqr5 == true && + id == QUALITY_REPORT_ID_CONN_FAIL_BQR5) || + (mVendorBqr5 == false && + id == QUALITY_REPORT_ID_CONN_FAIL)) { str += mBqrVsConnectFail + "\n}"; - } else if (id == QUALITY_REPORT_ID_MONITOR) { - str += "}"; } - return str; } @@ -432,6 +634,7 @@ public final class BluetoothQualityReport implements Parcelable { static final int BQR_COMMON_LEN = 48; private int mQualityReportId; + private int mVendorQualityReportId; private int mPacketType; private int mConnectionHandle; private int mConnectionRole; @@ -450,6 +653,7 @@ public final class BluetoothQualityReport implements Parcelable { private long mLastFlowOnTimestamp; private long mOverflowCount; private long mUnderflowCount; + private boolean mVendorBqr5; private BqrCommon(byte[] rawData, int offset) { if (rawData == null || rawData.length < offset + BQR_COMMON_LEN) { @@ -481,32 +685,76 @@ public final class BluetoothQualityReport implements Parcelable { mUnderflowCount = bqrBuf.getInt() & 0xFFFFFFFFL; } + private BqrCommon(byte[] rawData, int offset, boolean vendorBqr5) { + if (rawData == null || rawData.length < offset + 2) { + 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); + mVendorBqr5 = vendorBqr5; + mQualityReportId = bqrBuf.get() & 0xFF; + if(mQualityReportId == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + mVendorQualityReportId = bqrBuf.get() & 0xFF; + } else { + 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; + } + } + private BqrCommon(Parcel in) { + mVendorBqr5 = in.readBoolean(); 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(); + if(mVendorBqr5 == true && + mQualityReportId == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + mVendorQualityReportId = in.readInt(); + } else { + 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(); + } } int getQualityReportId() { return mQualityReportId; } + int getVendorQualityReportId() { + return mVendorQualityReportId; + } + /** * Get the packet type of the connection. * @return the packet type. @@ -677,31 +925,47 @@ public final class BluetoothQualityReport implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(mVendorBqr5); 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); + if(mVendorBqr5 == true && + mQualityReportId == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + dest.writeInt(mVendorQualityReportId); + } else { + 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); + } } @Override public String toString() { String str; - str = " BqrCommon: {\n" + if(mVendorBqr5 == true && + mQualityReportId == QUALITY_REPORT_ID_VENDOR_SPECIFIC) { + str = " BqrCommon: {\n" + + " mQualityReportId: " + BluetoothQualityReport.this.getQualityReportIdStr() + + "(" + String.format("0x%02X", mQualityReportId) + ")" + + " mVendorQualityReportId: " + BluetoothQualityReport.this.getVendorQualityReportIdStr() + + "(" + String.format("0x%02X", mVendorQualityReportId) + ")" + + "\n }"; + return str; + } else { + str = " BqrCommon: {\n" + " mQualityReportId: " + BluetoothQualityReport.this.getQualityReportIdStr() + "(" + String.format("0x%02X", mQualityReportId) + ")" + ", mPacketType: " + getPacketTypeStr() @@ -726,10 +990,9 @@ public final class BluetoothQualityReport implements Parcelable { + ", mOverflowCount: " + mOverflowCount + ", mUnderflowCount: " + mUnderflowCount + "\n }"; - - return str; + return str; + } } - } /** @@ -798,12 +1061,93 @@ public final class BluetoothQualityReport implements Parcelable { } } + public class BqrVsQualityMonitor implements Parcelable { + private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsQualityMonitor"; + private int mPowerLevelInDbm; + private long mCrcErrorCount; + private long mDecryptErrorCount; + private long mLastSniffStartTimestamp; + private long mLastActiveStartTimestamp; + + private BqrVsQualityMonitor(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); + mPowerLevelInDbm = bqrBuf.get() & 0xFF; + mCrcErrorCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mDecryptErrorCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mLastSniffStartTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + mLastActiveStartTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + + } + + private BqrVsQualityMonitor(Parcel in) { + mPowerLevelInDbm = in.readInt(); + mCrcErrorCount = in.readLong(); + mDecryptErrorCount = in.readLong(); + mLastSniffStartTimestamp = in.readLong(); + mLastActiveStartTimestamp = in.readLong(); + } + + public int getPowerLevelInDbm() { + return mPowerLevelInDbm; + } + + public long getCrcErrorCount() { + return mCrcErrorCount; + } + + public long getDecryptErrorCount() { + return mDecryptErrorCount; + } + + public long getLastSniffStartTimestamp() { + return mLastSniffStartTimestamp; + } + + public long getLastActiveStartTimestamp() { + return mLastActiveStartTimestamp; + } + + public int describeContents(){ + return 0; + } + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mPowerLevelInDbm); + dest.writeLong(mCrcErrorCount); + dest.writeLong(mDecryptErrorCount); + dest.writeLong(mLastSniffStartTimestamp); + dest.writeLong(mLastActiveStartTimestamp); + } + + @Override + public String toString() { + String str; + str = " BqrVsQualityMonitor: {\n" + + ", mPowerLevelInDbm: " + mPowerLevelInDbm + + ", mCrcErrorCount: " + mCrcErrorCount + + ", mDecryptErrorCount: " + mDecryptErrorCount + + ", mLastSniffStartTimestamp: " + mLastSniffStartTimestamp + + ", mLastActiveStartTimestamp: " + mLastActiveStartTimestamp + + "\n }"; + + return str; + } + + } + /** * This class provides the public APIs to access the vendor specific part of * Approaching LSTO event. */ public class BqrVsLsto implements Parcelable { private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsLsto"; + static final int BQR_VS_LSTO_LEN = 26; private int mConnState; private long mBasebandStats; @@ -813,11 +1157,22 @@ public final class BluetoothQualityReport implements Parcelable { private int mRfLoss; private long mNativeClock; private long mLastTxAckTimestamp; + private int mPowerLevelInDbm; + private long mCrcErrorCount; + private long mDecryptErrorCount; + private long mLastSniffStartTimestamp; + private long mLastActiveStartTimestamp; + private boolean isExtended; private BqrVsLsto(byte[] rawData, int offset) { if (rawData == null || rawData.length <= offset) { throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); } + if ((rawData.length - offset) > BQR_VS_LSTO_LEN) { + isExtended = true; + } else { + isExtended = false; + } ByteBuffer bqrBuf = ByteBuffer.wrap(rawData, offset, rawData.length - offset) .asReadOnlyBuffer(); @@ -831,9 +1186,18 @@ public final class BluetoothQualityReport implements Parcelable { mRfLoss = bqrBuf.getShort() & 0xFFFF; mNativeClock = bqrBuf.getInt() & 0xFFFFFFFFL; mLastTxAckTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + mPowerLevelInDbm = bqrBuf.get() & 0xFF; + + if(isExtended) { + mCrcErrorCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mDecryptErrorCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mLastSniffStartTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + mLastActiveStartTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + } } private BqrVsLsto(Parcel in) { + isExtended = in.readBoolean(); mConnState = in.readInt(); mBasebandStats = in.readLong(); mSlotsUsed = in.readLong(); @@ -842,6 +1206,13 @@ public final class BluetoothQualityReport implements Parcelable { mRfLoss = in.readInt(); mNativeClock = in.readLong(); mLastTxAckTimestamp = in.readLong(); + mPowerLevelInDbm = in.readInt(); + if(isExtended){ + mCrcErrorCount = in.readLong(); + mDecryptErrorCount = in.readLong(); + mLastSniffStartTimestamp = in.readLong(); + mLastActiveStartTimestamp = in.readLong(); + } } /** @@ -853,6 +1224,14 @@ public final class BluetoothQualityReport implements Parcelable { } /** + * Is extended to have few more params. + * @return true or false. + */ + public boolean isExtended() { + return isExtended; + } + + /** * Get the string of conn state of sco. * @return the string of conn state. */ @@ -909,6 +1288,26 @@ public final class BluetoothQualityReport implements Parcelable { return mNativeClock; } + public int getPowerLevelInDbm() { + return mPowerLevelInDbm; + } + + public long getCrcErrorCount() { + return mCrcErrorCount; + } + + public long getDecryptErrorCount() { + return mDecryptErrorCount; + } + + public long getLastSniffStartTimestamp() { + return mLastSniffStartTimestamp; + } + + public long getLastActiveStartTimestamp() { + return mLastActiveStartTimestamp; + } + /** * Get the timestamp of last TX ACK. * time_ms: N * 0.3125 ms (1 Bluetooth Clock). @@ -924,6 +1323,7 @@ public final class BluetoothQualityReport implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(isExtended); dest.writeInt(mConnState); dest.writeLong(mBasebandStats); dest.writeLong(mSlotsUsed); @@ -932,12 +1332,21 @@ public final class BluetoothQualityReport implements Parcelable { dest.writeInt(mRfLoss); dest.writeLong(mNativeClock); dest.writeLong(mLastTxAckTimestamp); + dest.writeInt(mPowerLevelInDbm); + if(isExtended){ + dest.writeLong(mCrcErrorCount); + dest.writeLong(mDecryptErrorCount); + dest.writeLong(mLastSniffStartTimestamp); + dest.writeLong(mLastActiveStartTimestamp); + } + } @Override public String toString() { String str; - str = " BqrVsLsto: {\n" + str = " BqrVsLsto: {\n" + + ", isExtended: " + isExtended + " mConnState: " + getConnStateStr() + "(" + String.format("0x%02X", mConnState) + ")" + ", mBasebandStats: " + String.format("0x%08X", mBasebandStats) @@ -947,10 +1356,19 @@ public final class BluetoothQualityReport implements Parcelable { + ", mRfLoss: " + mRfLoss + ", mNativeClock: " + String.format("0x%08X", mNativeClock) + ", mLastTxAckTimestamp: " + String.format("0x%08X", mLastTxAckTimestamp) + + ", mPowerLevelInDbm: " + mPowerLevelInDbm + "\n }"; + if (isExtended) { + str += ", mCrcErrorCount: " + mCrcErrorCount + + ", mDecryptErrorCount: " + mDecryptErrorCount + + ", mLastSniffStartTimestamp: " + mLastSniffStartTimestamp + + ", mLastActiveStartTimestamp: " + mLastActiveStartTimestamp + + "\n }"; + } return str; } + } /** @@ -959,6 +1377,7 @@ public final class BluetoothQualityReport implements Parcelable { */ public class BqrVsA2dpChoppy implements Parcelable { private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsA2dpChoppy"; + private static final int BQR_VS_A2DPCHOPPY_LEN = 16; private long mArrivalTime; private long mScheduleTime; @@ -967,33 +1386,100 @@ public final class BluetoothQualityReport implements Parcelable { private int mRxCxmDenials; private int mAclTxQueueLength; private int mLinkQuality; + private int mPowerLevelInDbm; + private int mA2dpRole; + private long mCrcErrorCount; + private long mDecryptErrorCount; + private long mLastSniffStartTimestamp; + private long mLastActiveStartTimestamp; + private long mFlushedA2dpPacketCount; + private long mSinkJitterBufferOverrunCount; + private long mSinkJitterUnderrunCount; + private long mSinkRetransmissionAckCount; + private boolean isExtended; + private int role; private BqrVsA2dpChoppy(byte[] rawData, int offset) { if (rawData == null || rawData.length <= offset) { throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); } - + if ((rawData.length - offset) > BQR_VS_A2DPCHOPPY_LEN) { + isExtended = true; + } else { + isExtended = false; + } + if(isExtended) { + int roleOffset = 16; + ByteBuffer bqrBufRole = ByteBuffer.wrap(rawData, offset, rawData.length - (offset + roleOffset)) + .asReadOnlyBuffer(); + role = bqrBufRole.get() & 0xFF; + } else { + role = 1; // TODO to macro + } 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; + if (isExtended == true) { + 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; + mPowerLevelInDbm = bqrBuf.get() & 0xFF; + mA2dpRole = bqrBuf.get() & 0xFF; + mCrcErrorCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mDecryptErrorCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mLastSniffStartTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + mLastActiveStartTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + mFlushedA2dpPacketCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mSinkJitterBufferOverrunCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mSinkJitterUnderrunCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mSinkRetransmissionAckCount = bqrBuf.getInt() & 0xFFFFFFFFL; + } else { + 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; + mPowerLevelInDbm = 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(); + isExtended = in.readBoolean(); + if(isExtended==true) { + mArrivalTime = in.readLong(); + mScheduleTime = in.readLong(); + mGlitchCount = in.readInt(); + mTxCxmDenials = in.readInt(); + mRxCxmDenials = in.readInt(); + mAclTxQueueLength = in.readInt(); + mLinkQuality = in.readInt(); + mPowerLevelInDbm = in.readInt(); + mA2dpRole = in.readInt(); + mCrcErrorCount = in.readLong(); + mDecryptErrorCount = in.readLong(); + mLastSniffStartTimestamp = in.readLong(); + mLastActiveStartTimestamp = in.readLong(); + mFlushedA2dpPacketCount = in.readLong(); + mSinkJitterBufferOverrunCount = in.readLong(); + mSinkJitterUnderrunCount = in.readLong(); + mSinkRetransmissionAckCount = in.readLong(); + } else { + mArrivalTime = in.readLong(); + mScheduleTime = in.readLong(); + mGlitchCount = in.readInt(); + mTxCxmDenials = in.readInt(); + mRxCxmDenials = in.readInt(); + mAclTxQueueLength = in.readInt(); + mLinkQuality = in.readInt(); + mPowerLevelInDbm = in.readInt(); + } } /** @@ -1022,6 +1508,10 @@ public final class BluetoothQualityReport implements Parcelable { return mGlitchCount; } + public int getSinkGlitchCount() { + return mGlitchCount; + } + /** * Get the count of Coex TX denials. * @return the count of Coex TX denials. @@ -1038,6 +1528,14 @@ public final class BluetoothQualityReport implements Parcelable { return mRxCxmDenials; } + public int getSinkTxCxmDenials() { + return mTxCxmDenials; + } + + public int getSinkRxCxmDenials() { + return mRxCxmDenials; + } + /** * Get the ACL queue length which are pending TX in FW. * @return the ACL queue length. @@ -1067,21 +1565,107 @@ public final class BluetoothQualityReport implements Parcelable { return 0; } - @Override - public void writeToParcel(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); + public int getPowerLevelInDbm() { + return mPowerLevelInDbm; } - @Override - public String toString() { + public int getA2dpRole() { + return mA2dpRole; + } + + public long getCrcErrorCount() { + return mCrcErrorCount; + } + + public long getSinkCrcErrorCount() { + return mCrcErrorCount; + } + + public long getDecryptErrorCount() { + return mDecryptErrorCount; + } + + public long getSinkDecryptErrorCount() { + return mDecryptErrorCount; + } + + public long getLastSniffStartTimestamp() { + return mLastSniffStartTimestamp; + } + public long getSinkLastSniffStartTimestamp() { + return mLastSniffStartTimestamp; + } + + public long getLastActiveStartTimestamp() { + return mLastActiveStartTimestamp; + } + + public long getSinkLastActiveStartTimestamp() { + return mLastActiveStartTimestamp; + } + + public long getFlushedA2dpPacketCount() { + return mFlushedA2dpPacketCount; + } + + public long getSinkA2dpJitterBufferOverrunCount() { + return mSinkJitterBufferOverrunCount; + } + + public long getSinkA2dpJitterUnderrunCount() { + return mSinkJitterUnderrunCount; + } + + public long getSinkA2dpReTransmissionAckCounnt() { + return mSinkRetransmissionAckCount; + } + + /** + * Is extended to have few more params. + * @return true or false. + */ + public boolean isExtended() { + return isExtended; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(isExtended); + if(isExtended==true){ + dest.writeLong(mArrivalTime); + dest.writeLong(mScheduleTime); + dest.writeInt(mGlitchCount); + dest.writeInt(mTxCxmDenials); + dest.writeInt(mRxCxmDenials); + dest.writeInt(mAclTxQueueLength); + dest.writeInt(mLinkQuality); + dest.writeInt(mPowerLevelInDbm); + dest.writeInt(mA2dpRole); + dest.writeLong(mCrcErrorCount); + dest.writeLong(mDecryptErrorCount); + dest.writeLong(mLastSniffStartTimestamp); + dest.writeLong(mLastActiveStartTimestamp); + dest.writeLong(mFlushedA2dpPacketCount); + dest.writeLong(mSinkJitterBufferOverrunCount); + dest.writeLong(mSinkJitterUnderrunCount); + dest.writeLong(mSinkRetransmissionAckCount); + } else { + dest.writeLong(mArrivalTime); + dest.writeLong(mScheduleTime); + dest.writeInt(mGlitchCount); + dest.writeInt(mTxCxmDenials); + dest.writeInt(mRxCxmDenials); + dest.writeInt(mAclTxQueueLength); + dest.writeInt(mLinkQuality); + dest.writeInt(mPowerLevelInDbm); + } + } + + @Override + public String toString() { String str; str = " BqrVsA2dpChoppy: {\n" + + ", isExtended: " + isExtended + " mArrivalTime: " + String.format("0x%08X", mArrivalTime) + ", mScheduleTime: " + String.format("0x%08X", mScheduleTime) + ", mGlitchCount: " + mGlitchCount @@ -1090,19 +1674,32 @@ public final class BluetoothQualityReport implements Parcelable { + ", mAclTxQueueLength: " + mAclTxQueueLength + ", mLinkQuality: " + getLinkQualityStr() + "(" + String.format("0x%02X", mLinkQuality) + ")" + + ",mPowerLevelInDbm: " + mPowerLevelInDbm + "\n }"; - + if(isExtended) { + str += "mA2dpRole: " + mA2dpRole + + ", mCrcErrorCount: " + mCrcErrorCount + + ", mDecryptErrorCount: " + mDecryptErrorCount + + ", mLastSniffStartTimestamp: " + mLastSniffStartTimestamp + + ", mLastActiveStartTimestamp:" + mLastActiveStartTimestamp + + ", mFlushedA2dpPacketCount: " + mFlushedA2dpPacketCount + + ", mSinkJitterBufferOverrunCount: " + mSinkJitterBufferOverrunCount + + ", mSinkJitterUnderrunCount: " + mSinkJitterUnderrunCount + + ", mSinkRetransmissionAckCount: " + mSinkRetransmissionAckCount + + "\n }"; + } return str; } - } + /** * This class provides the public APIs to access the vendor specific part of * SCO choppy event. */ public class BqrVsScoChoppy implements Parcelable { private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsScoChoppy"; + private static final int BQR_VS_SCOCHOPPY_LEN = 34; private int mGlitchCount; private int mIntervalEsco; @@ -1122,12 +1719,22 @@ public final class BluetoothQualityReport implements Parcelable { private int mTxRetransmitSlotCount; private int mRxRetransmitSlotCount; private int mGoodRxFrameCount; - + private int mPowerLevelInDbm; + private long mCrcErrorCount; + private long mDecryptErrorCount; + private long mLastSniffStartTimestamp; + private long mLastActiveStartTimestamp; + private boolean isExtended; private BqrVsScoChoppy(byte[] rawData, int offset) { if (rawData == null || rawData.length <= offset) { throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); } - + if((rawData.length - offset) > BQR_VS_SCOCHOPPY_LEN){ + isExtended = true; + } + else{ + isExtended = false; + } ByteBuffer bqrBuf = ByteBuffer.wrap(rawData, offset, rawData.length - offset) .asReadOnlyBuffer(); bqrBuf.order(ByteOrder.LITTLE_ENDIAN); @@ -1151,12 +1758,20 @@ public final class BluetoothQualityReport implements Parcelable { mTxRetransmitSlotCount = bqrBuf.getShort() & 0xFFFF; mRxRetransmitSlotCount = bqrBuf.getShort() & 0xFFFF; mGoodRxFrameCount = bqrBuf.getShort() & 0xFFFF; + mPowerLevelInDbm = bqrBuf.get() & 0xFF; } catch (BufferUnderflowException e) { Log.v(TAG, "some fields are not contained"); } + if(isExtended) { + mCrcErrorCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mDecryptErrorCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mLastSniffStartTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + mLastActiveStartTimestamp = bqrBuf.getInt() & 0xFFFFFFFFL; + } } private BqrVsScoChoppy(Parcel in) { + isExtended = in.readBoolean(); mGlitchCount = in.readInt(); mIntervalEsco = in.readInt(); mWindowEsco = in.readInt(); @@ -1175,6 +1790,13 @@ public final class BluetoothQualityReport implements Parcelable { mTxRetransmitSlotCount = in.readInt(); mRxRetransmitSlotCount = in.readInt(); mGoodRxFrameCount = in.readInt(); + mPowerLevelInDbm = in.readInt(); + if (isExtended) { + mCrcErrorCount = in.readLong(); + mDecryptErrorCount = in.readLong(); + mLastSniffStartTimestamp = in.readLong(); + mLastActiveStartTimestamp = in.readLong(); + } } /** @@ -1333,12 +1955,42 @@ public final class BluetoothQualityReport implements Parcelable { return mGoodRxFrameCount; } + public int getPowerLevelInDbm() { + return mPowerLevelInDbm; + } + + public long getCrcErrorCount() { + return mCrcErrorCount; + } + + public long getDecryptErrorCount() { + return mDecryptErrorCount; + } + + public long getLastSniffStartTimestamp() { + return mLastSniffStartTimestamp; + } + + public long getLastActiveStartTimestamp() { + return mLastActiveStartTimestamp; + } + + public int describeContents() { return 0; } + /** + * Is extended to have few more params. + * @return true or false. + */ + public boolean isExtended() { + return isExtended; + } + @Override public void writeToParcel(Parcel dest, int flags) { + dest.writeBoolean(isExtended); dest.writeInt(mGlitchCount); dest.writeInt(mIntervalEsco); dest.writeInt(mWindowEsco); @@ -1357,12 +2009,20 @@ public final class BluetoothQualityReport implements Parcelable { dest.writeInt(mTxRetransmitSlotCount); dest.writeInt(mRxRetransmitSlotCount); dest.writeInt(mGoodRxFrameCount); + dest.writeInt(mPowerLevelInDbm); + if(isExtended){ + dest.writeLong(mCrcErrorCount); + dest.writeLong(mDecryptErrorCount); + dest.writeLong(mLastSniffStartTimestamp); + dest.writeLong(mLastActiveStartTimestamp); + } } @Override public String toString() { String str; str = " BqrVsScoChoppy: {\n" + + ", isExtended: " + isExtended + " mGlitchCount: " + mGlitchCount + ", mIntervalEsco: " + mIntervalEsco + ", mWindowEsco: " + mWindowEsco @@ -1384,8 +2044,202 @@ public final class BluetoothQualityReport implements Parcelable { + ",\n" + " mRxRetransmitSlotCount: " + mRxRetransmitSlotCount + ", mGoodRxFrameCount: " + mGoodRxFrameCount + + "mPowerLevelInDbm: " + mPowerLevelInDbm + + "\n }"; + if(isExtended) { + str += ", mCrcErrorCount: " + mCrcErrorCount + + ", mDecryptErrorCount: " + mDecryptErrorCount + + ", mLastSniffStartTimestamp: " + mLastSniffStartTimestamp + + ", mLastActiveStartTimestamp: " + mLastActiveStartTimestamp + + "\n }"; + } + return str; + } + } + + public class BqrVsDiscoveryMonitoring implements Parcelable { + private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsDiscoveryMonitoring"; + private long mInquiryCount; + private long mInquiryScanWindowCount; + private long mInquiryScanWindowDuration; + private long mPageScanWindowCount; + private long mPageScanWindowDuration; + private long mBleAdvertisementCount; + private long mBleScanWindowCount; + private long mBleScanWindowDuration; + private long mBleScanRequestCount; + private long mBleScanResponseCount; + + private BqrVsDiscoveryMonitoring(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); + mInquiryCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mInquiryScanWindowCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mInquiryScanWindowDuration = bqrBuf.getInt() & 0xFFFFFFFFL; + mPageScanWindowCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mPageScanWindowDuration = bqrBuf.getInt() & 0xFFFFFFFFL; + mBleAdvertisementCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mBleScanWindowCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mBleScanWindowDuration = bqrBuf.getInt() & 0xFFFFFFFFL; + mBleScanRequestCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mBleScanResponseCount = bqrBuf.getInt() & 0xFFFFFFFFL; + + } + + private BqrVsDiscoveryMonitoring(Parcel in) { + mInquiryCount = in.readLong(); + mInquiryScanWindowCount = in.readLong(); + mInquiryScanWindowDuration = in.readLong(); + mPageScanWindowCount = in.readLong(); + mPageScanWindowDuration = in.readLong(); + mBleAdvertisementCount = in.readLong(); + mBleScanRequestCount = in.readLong(); + mBleScanWindowDuration = in.readLong(); + mBleScanRequestCount = in.readLong(); + mBleScanResponseCount = in.readLong(); + } + + public long getInquiryCount() { + return mInquiryCount; + } + + public long getInquiryScanWindowCount() { + return mInquiryScanWindowCount; + } + + public long getInquiryScanWindowDuration() { + return mInquiryScanWindowDuration; + } + + public long getPageScanWindowCount() { + return mPageScanWindowCount; + } + + public long getBleAdvertisementCount() { + return mBleAdvertisementCount; + } + + public long getBleScanWindowCount() { + return mBleScanWindowCount; + } + + public long getBleScanWindowDuration() { + return mBleScanWindowDuration; + } + + public long getBleScanRequestCount() { + return mBleScanRequestCount; + } + + public long getBleScanResponseCount() { + return mBleScanResponseCount; + } + public int describeContents(){ + return 0; + } + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mInquiryCount); + dest.writeLong(mInquiryScanWindowCount); + dest.writeLong(mInquiryScanWindowDuration); + dest.writeLong(mPageScanWindowCount); + dest.writeLong(mPageScanWindowDuration); + dest.writeLong(mBleAdvertisementCount); + dest.writeLong(mBleScanWindowCount); + dest.writeLong(mBleScanWindowDuration); + dest.writeLong(mBleScanRequestCount); + dest.writeLong(mBleScanResponseCount); + } + + @Override + public String toString() { + String str = ""; + str = " BqrVsDiscoveryMonitoring: {\n" + + ", mInquiryCount: " + mInquiryCount + + ", mInquiryScanWindowCount: " + mInquiryScanWindowCount + + ", mInquiryScanWindowDuration: " + mInquiryScanWindowDuration + + ", mPageScanWindowCount: " + mPageScanWindowCount + + ", mPageScanWindowDuration: " + mPageScanWindowDuration + + ", mBleAdvertisementCount: " + mBleAdvertisementCount + + ", mBleScanWindowCount: " + mBleScanWindowCount + + ", mBleScanWindowDuration: " + mBleScanWindowDuration + + ", mBleScanRequestCount: " + mBleScanRequestCount + + ", mBleScanResponseCount: " + mBleScanResponseCount + "\n }"; + return str; + } + + } + + public class BqrVsMiscMonitoring implements Parcelable { + private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsMiscMonitoring"; + private long mRadioWakeupCount; + private long mHciWakeupCount; + private long mErrorWakeupCount; + private long mCoexRejectCount; + + private BqrVsMiscMonitoring(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); + mRadioWakeupCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mHciWakeupCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mErrorWakeupCount = bqrBuf.getInt() & 0xFFFFFFFFL; + mCoexRejectCount = bqrBuf.getInt() & 0xFFFFFFFFL; + } + + private BqrVsMiscMonitoring(Parcel in) { + mRadioWakeupCount = in.readLong(); + mHciWakeupCount = in.readLong(); + mErrorWakeupCount = in.readLong(); + mCoexRejectCount = in.readLong(); + } + + public long getRadioWakeupCount() { + return mRadioWakeupCount; + } + + public long getHciWakeupCount() { + return mHciWakeupCount; + } + public long getErrorWakeupCount() { + return mErrorWakeupCount; + } + + public long getCoexRejectCount() { + return mCoexRejectCount; + } + + public int describeContents(){ + return 0; + } + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mRadioWakeupCount); + dest.writeLong(mHciWakeupCount); + dest.writeLong(mErrorWakeupCount); + dest.writeLong(mCoexRejectCount); + } + + @Override + public String toString() { + String str = ""; + str = " BqrVsMiscMonitoring: {\n" + + ", mRadioWakeupCount: " + mRadioWakeupCount + + ", mHciWakeupCount: " + mHciWakeupCount + + ", mErrorWakeupCount: " + mErrorWakeupCount + + ", mCoexRejectCount: " + mCoexRejectCount + + "\n }"; return str; } @@ -1399,7 +2253,6 @@ public final class BluetoothQualityReport implements Parcelable { private static final String TAG = BluetoothQualityReport.TAG + ".BqrVsConnectFail"; private int mFailReason; - private BqrVsConnectFail(byte[] rawData, int offset) { if (rawData == null || rawData.length <= offset) { throw new IllegalArgumentException(TAG + ": BQR raw data length is abnormal."); @@ -1415,7 +2268,6 @@ public final class BluetoothQualityReport implements Parcelable { private BqrVsConnectFail(Parcel in) { mFailReason = in.readInt(); } - /** * Get the fail reason. * @return the fail reason. @@ -1430,9 +2282,8 @@ public final class BluetoothQualityReport implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(mFailReason); + dest.writeInt(mFailReason); } - @Override public String toString() { String str; @@ -1445,3 +2296,5 @@ public final class BluetoothQualityReport implements Parcelable { } } + + |