1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telecom; 18 19 import android.annotation.ElapsedRealtimeLong; 20 import android.annotation.IntRange; 21 import android.annotation.NonNull; 22 import android.annotation.SystemApi; 23 import android.os.Bundle; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 27 import java.util.Objects; 28 29 /** 30 * This class represents the quality report that bluetooth framework sends 31 * whenever there's a bad voice quality is detected from their side. 32 * It is sent as part of a call event via {@link Call#sendCallEvent(String, Bundle)} 33 * associated with extra EXTRA_BLUETOOTH_CALL_QUALITY_REPORT. 34 * Note that this report will be sent only during an active voice/voip call. 35 * @hide 36 */ 37 @SystemApi 38 public final class BluetoothCallQualityReport implements Parcelable { 39 40 /** 41 * Event that is sent via {@link Call#sendCallEvent(String, Bundle)} for a call quality report 42 */ 43 public static final String EVENT_BLUETOOTH_CALL_QUALITY_REPORT = 44 "android.telecom.event.BLUETOOTH_CALL_QUALITY_REPORT"; 45 46 /** 47 * Extra key sent with {@link Call#sendCallEvent(String, Bundle)} 48 */ 49 public static final String EXTRA_BLUETOOTH_CALL_QUALITY_REPORT = 50 "android.telecom.extra.BLUETOOTH_CALL_QUALITY_REPORT"; 51 52 private final long mSentTimestampMillis; 53 private final boolean mChoppyVoice; 54 private final int mRssiDbm; 55 private final int mSnrDb; 56 private final int mRetransmittedPacketsCount; 57 private final int mPacketsNotReceivedCount; 58 private final int mNegativeAcknowledgementCount; 59 60 /** 61 * @return Time in milliseconds since the epoch. Designates when report was sent. 62 * Used to determine whether this report arrived too late to be useful. 63 */ getSentTimestampMillis()64 public @ElapsedRealtimeLong long getSentTimestampMillis() { 65 return mSentTimestampMillis; 66 } 67 68 /** 69 * When the bluetooth controller detects factors that cause choppy voice, 70 * the controller reports an (e)SCO Voice Choppy event to the host 71 * @return {@code true} when we receive (e)SCO Voice Choppy event from the controller 72 */ isChoppyVoice()73 public boolean isChoppyVoice() { 74 return mChoppyVoice; 75 } 76 77 /** 78 * @return Received Signal Strength Indication (RSSI) value in dBm. 79 * This value shall be an absolute received signal strength value. 80 */ getRssiDbm()81 public @IntRange(from = -127, to = 20) int getRssiDbm() { 82 return mRssiDbm; 83 } 84 85 /** 86 * @return Signal-to-Noise Ratio (SNR) value in dB. 87 * The controller shall provide the average SNR of all the channels currently used by the link. 88 */ getSnrDb()89 public int getSnrDb() { 90 return mSnrDb; 91 } 92 93 /** 94 * @return The number of retransmissions since the last event. 95 * This count shall be reset after it is reported. 96 */ getRetransmittedPacketsCount()97 public @IntRange(from = 0) int getRetransmittedPacketsCount() { 98 return mRetransmittedPacketsCount; 99 } 100 101 /** 102 * @return No RX count since the last event. 103 * The count increases when no packet is received at the scheduled time slot or the received 104 * packet is corrupted. 105 * This count shall be reset after it is reported. 106 */ getPacketsNotReceivedCount()107 public @IntRange(from = 0) int getPacketsNotReceivedCount() { 108 return mPacketsNotReceivedCount; 109 } 110 111 /** 112 * @return NAK (Negative Acknowledge) count since the last event. 113 * This count shall be reset after it is reported. 114 */ getNegativeAcknowledgementCount()115 public @IntRange(from = 0) int getNegativeAcknowledgementCount() { 116 return mNegativeAcknowledgementCount; 117 } 118 119 // 120 // Parcelable implementation 121 // 122 123 @Override describeContents()124 public int describeContents() { 125 return 0; 126 } 127 128 @Override writeToParcel(@onNull Parcel out, int flags)129 public void writeToParcel(@NonNull Parcel out, int flags) { 130 out.writeLong(mSentTimestampMillis); 131 out.writeBoolean(mChoppyVoice); 132 out.writeInt(mRssiDbm); 133 out.writeInt(mSnrDb); 134 out.writeInt(mRetransmittedPacketsCount); 135 out.writeInt(mPacketsNotReceivedCount); 136 out.writeInt(mNegativeAcknowledgementCount); 137 } 138 139 public static final @android.annotation.NonNull Creator<BluetoothCallQualityReport> CREATOR = 140 new Creator<BluetoothCallQualityReport>() { 141 @Override 142 public BluetoothCallQualityReport createFromParcel(Parcel in) { 143 return new BluetoothCallQualityReport(in); 144 } 145 146 @Override 147 public BluetoothCallQualityReport[] newArray(int size) { 148 return new BluetoothCallQualityReport[size]; 149 } 150 }; 151 152 @Override equals(Object o)153 public boolean equals(Object o) { 154 if (this == o) return true; 155 if (o == null || getClass() != o.getClass()) return false; 156 BluetoothCallQualityReport that = (BluetoothCallQualityReport) o; 157 return mSentTimestampMillis == that.mSentTimestampMillis 158 && mChoppyVoice == that.mChoppyVoice && mRssiDbm == that.mRssiDbm 159 && mSnrDb == that.mSnrDb 160 && mRetransmittedPacketsCount == that.mRetransmittedPacketsCount 161 && mPacketsNotReceivedCount == that.mPacketsNotReceivedCount 162 && mNegativeAcknowledgementCount == that.mNegativeAcknowledgementCount; 163 } 164 165 @Override hashCode()166 public int hashCode() { 167 return Objects.hash(mSentTimestampMillis, mChoppyVoice, mRssiDbm, mSnrDb, 168 mRetransmittedPacketsCount, mPacketsNotReceivedCount, 169 mNegativeAcknowledgementCount); 170 } 171 172 /** 173 * Builder class for {@link ConnectionRequest} 174 */ 175 public static final class Builder { 176 private long mSentTimestampMillis; 177 private boolean mChoppyVoice; 178 private int mRssiDbm; 179 private int mSnrDb; 180 private int mRetransmittedPacketsCount; 181 private int mPacketsNotReceivedCount; 182 private int mNegativeAcknowledgementCount; 183 Builder()184 public Builder() { } 185 186 /** 187 * Set the time when report was sent in milliseconds since the epoch. 188 * @param sentTimestampMillis 189 */ setSentTimestampMillis(long sentTimestampMillis)190 public @NonNull Builder setSentTimestampMillis(long sentTimestampMillis) { 191 mSentTimestampMillis = sentTimestampMillis; 192 return this; 193 } 194 195 /** 196 * Set if bluetooth hardware detects voice is choppy 197 * @param choppyVoice 198 */ setChoppyVoice(boolean choppyVoice)199 public @NonNull Builder setChoppyVoice(boolean choppyVoice) { 200 mChoppyVoice = choppyVoice; 201 return this; 202 } 203 204 /** 205 * Set Received Signal Strength Indication (RSSI) value in dBm. 206 * @param rssiDbm 207 */ setRssiDbm(int rssiDbm)208 public @NonNull Builder setRssiDbm(int rssiDbm) { 209 mRssiDbm = rssiDbm; 210 return this; 211 } 212 213 /** 214 * Set Signal-to-Noise Ratio (SNR) value in dB. 215 * @param snrDb 216 */ setSnrDb(int snrDb)217 public @NonNull Builder setSnrDb(int snrDb) { 218 mSnrDb = snrDb; 219 return this; 220 } 221 222 /** 223 * Set The number of retransmissions since the last event. 224 * @param retransmittedPacketsCount 225 */ setRetransmittedPacketsCount( int retransmittedPacketsCount)226 public @NonNull Builder setRetransmittedPacketsCount( 227 int retransmittedPacketsCount) { 228 mRetransmittedPacketsCount = retransmittedPacketsCount; 229 return this; 230 } 231 232 /** 233 * Set No RX count since the last event. 234 * @param packetsNotReceivedCount 235 */ setPacketsNotReceivedCount( int packetsNotReceivedCount)236 public @NonNull Builder setPacketsNotReceivedCount( 237 int packetsNotReceivedCount) { 238 mPacketsNotReceivedCount = packetsNotReceivedCount; 239 return this; 240 } 241 242 /** 243 * Set NAK (Negative Acknowledge) count since the last event. 244 * @param negativeAcknowledgementCount 245 */ setNegativeAcknowledgementCount( int negativeAcknowledgementCount)246 public @NonNull Builder setNegativeAcknowledgementCount( 247 int negativeAcknowledgementCount) { 248 mNegativeAcknowledgementCount = negativeAcknowledgementCount; 249 return this; 250 } 251 252 /** 253 * Build the {@link BluetoothCallQualityReport} 254 * @return Result of the builder 255 */ build()256 public @NonNull BluetoothCallQualityReport build() { 257 return new BluetoothCallQualityReport(this); 258 } 259 } 260 BluetoothCallQualityReport(Parcel in)261 private BluetoothCallQualityReport(Parcel in) { 262 mSentTimestampMillis = in.readLong(); 263 mChoppyVoice = in.readBoolean(); 264 mRssiDbm = in.readInt(); 265 mSnrDb = in.readInt(); 266 mRetransmittedPacketsCount = in.readInt(); 267 mPacketsNotReceivedCount = in.readInt(); 268 mNegativeAcknowledgementCount = in.readInt(); 269 } 270 BluetoothCallQualityReport(Builder builder)271 private BluetoothCallQualityReport(Builder builder) { 272 mSentTimestampMillis = builder.mSentTimestampMillis; 273 mChoppyVoice = builder.mChoppyVoice; 274 mRssiDbm = builder.mRssiDbm; 275 mSnrDb = builder.mSnrDb; 276 mRetransmittedPacketsCount = builder.mRetransmittedPacketsCount; 277 mPacketsNotReceivedCount = builder.mPacketsNotReceivedCount; 278 mNegativeAcknowledgementCount = builder.mNegativeAcknowledgementCount; 279 } 280 } 281