1 /* 2 * Copyright (C) 2013 Samsung System LSI 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 package com.android.bluetooth.map; 16 17 import android.bluetooth.BluetoothProfile; 18 import android.bluetooth.BluetoothProtoEnums; 19 import android.util.Log; 20 21 import com.android.bluetooth.BluetoothStatsLog; 22 import com.android.bluetooth.SignedLongLong; 23 import com.android.bluetooth.content_profiles.ContentProfileErrorReportUtils; 24 25 import java.nio.ByteBuffer; 26 import java.nio.ByteOrder; 27 import java.nio.charset.StandardCharsets; 28 import java.text.ParseException; 29 import java.text.SimpleDateFormat; 30 import java.util.Arrays; 31 import java.util.Date; 32 import java.util.Locale; 33 34 /** This class encapsulates the appParams needed for MAP. */ 35 // Next tag value for ContentProfileErrorReportUtils.report(): 41 36 public class BluetoothMapAppParams { 37 private static final String TAG = BluetoothMapAppParams.class.getSimpleName(); 38 39 private static final int MAX_LIST_COUNT = 0x01; 40 private static final int START_OFFSET = 0x02; 41 private static final int FILTER_MESSAGE_TYPE = 0x03; 42 private static final int FILTER_PERIOD_BEGIN = 0x04; 43 private static final int FILTER_PERIOD_END = 0x05; 44 private static final int FILTER_READ_STATUS = 0x06; 45 private static final int FILTER_RECIPIENT = 0x07; 46 private static final int FILTER_ORIGINATOR = 0x08; 47 private static final int FILTER_PRIORITY = 0x09; 48 private static final int ATTACHMENT = 0x0A; 49 private static final int TRANSPARENT = 0x0B; 50 private static final int RETRY = 0x0C; 51 private static final int NEW_MESSAGE = 0x0D; 52 private static final int NOTIFICATION_STATUS = 0x0E; 53 private static final int MAS_INSTANCE_ID = 0x0F; 54 private static final int PARAMETER_MASK = 0x10; 55 private static final int FOLDER_LISTING_SIZE = 0x11; 56 private static final int MESSAGE_LISTING_SIZE = 0x12; 57 private static final int SUBJECT_LENGTH = 0x13; 58 private static final int CHARSET = 0x14; 59 private static final int FRACTION_REQUEST = 0x15; 60 private static final int FRACTION_DELIVER = 0x16; 61 private static final int STATUS_INDICATOR = 0x17; 62 private static final int STATUS_VALUE = 0x18; 63 private static final int MSE_TIME = 0x19; 64 private static final int DATABASE_IDENTIFIER = 0x1A; 65 private static final int CONVO_LIST_VER_COUNTER = 0x1B; 66 private static final int PRESENCE_AVAILABLE = 0x1C; 67 private static final int PRESENCE_TEXT = 0x1D; 68 private static final int LAST_ACTIVITY = 0x1E; 69 private static final int CHAT_STATE = 0x21; 70 private static final int FILTER_CONVO_ID = 0x22; 71 private static final int CONVO_LISTING_SIZE = 0x36; 72 private static final int FILTER_PRESENCE = 0x37; 73 private static final int FILTER_UID_PRESENT = 0x38; 74 private static final int CHAT_STATE_CONVO_ID = 0x39; 75 private static final int FOLDER_VER_COUNTER = 0x23; 76 private static final int FILTER_MESSAGE_HANDLE = 0x24; 77 private static final int NOTIFICATION_FILTER = 0x25; 78 private static final int CONVO_PARAMETER_MASK = 0x26; 79 80 // Length defined for Application Parameters 81 private static final int MAX_LIST_COUNT_LEN = 0x02; // , 0x0000, 0xFFFF), 82 private static final int START_OFFSET_LEN = 0x02; // , 0x0000, 0xFFFF), 83 private static final int FILTER_MESSAGE_TYPE_LEN = 0x01; // , 0x0000, 0x000f), 84 private static final int FILTER_READ_STATUS_LEN = 0x01; // , 0x0000, 0x0002), 85 private static final int FILTER_PRIORITY_LEN = 0x01; // , 0x0000, 0x0002), 86 private static final int ATTACHMENT_LEN = 0x01; // , 0x0000, 0x0001), 87 private static final int TRANSPARENT_LEN = 0x01; // , 0x0000, 0x0001), 88 private static final int RETRY_LEN = 0x01; // , 0x0000, 0x0001), 89 private static final int NEW_MESSAGE_LEN = 0x01; // , 0x0000, 0x0001), 90 private static final int NOTIFICATION_STATUS_LEN = 0x01; // , 0x0000, 0xFFFF), 91 private static final int MAS_INSTANCE_ID_LEN = 0x01; // , 0x0000, 0x00FF), 92 private static final int PARAMETER_MASK_LEN = 0x04; // , 0x0000, 0x0000), 93 private static final int FOLDER_LISTING_SIZE_LEN = 0x02; // , 0x0000, 0xFFFF), 94 private static final int MESSAGE_LISTING_SIZE_LEN = 0x02; // , 0x0000, 0xFFFF), 95 private static final int SUBJECT_LENGTH_LEN = 0x01; // , 0x0000, 0x00FF), 96 private static final int CHARSET_LEN = 0x01; // , 0x0000, 0x0001), 97 private static final int FRACTION_REQUEST_LEN = 0x01; // , 0x0000, 0x0001), 98 private static final int FRACTION_DELIVER_LEN = 0x01; // , 0x0000, 0x0001), 99 private static final int STATUS_INDICATOR_LEN = 0x01; // , 0x0000, 0x0001), 100 private static final int STATUS_VALUE_LEN = 0x01; // , 0x0000, 0x0001), 101 private static final int DATABASE_IDENTIFIER_LEN = 0x10; 102 private static final int CONVO_LIST_VER_COUNTER_LEN = 0x10; 103 private static final int PRESENCE_AVAILABLE_LEN = 0X01; 104 private static final int CHAT_STATE_LEN = 0x01; 105 private static final int CHAT_STATE_CONVO_ID_LEN = 0x10; 106 private static final int FILTER_CONVO_ID_LEN = 0x20; 107 private static final int CONVO_LISTING_SIZE_LEN = 0x02; 108 private static final int FILTER_PRESENCE_LEN = 0x01; 109 private static final int FILTER_UID_PRESENT_LEN = 0x01; 110 private static final int FOLDER_VER_COUNTER_LEN = 0x20; 111 private static final int FILTER_MESSAGE_HANDLE_LEN = 0x08; 112 private static final int NOTIFICATION_FILTER_LEN = 0x04; 113 private static final int CONVO_PARAMETER_MASK_LEN = 0x04; 114 115 // Default values 116 public static final int INVALID_VALUE_PARAMETER = -1; 117 public static final int NOTIFICATION_STATUS_NO = 0; 118 public static final int NOTIFICATION_STATUS_YES = 1; 119 public static final int STATUS_INDICATOR_READ = 0; 120 public static final int STATUS_INDICATOR_DELETED = 1; 121 public static final int STATUS_VALUE_YES = 1; 122 public static final int STATUS_VALUE_NO = 0; 123 public static final int CHARSET_NATIVE = 0; 124 public static final int CHARSET_UTF8 = 1; 125 public static final int FRACTION_REQUEST_FIRST = 0; 126 public static final int FRACTION_REQUEST_NEXT = 1; 127 public static final int FRACTION_DELIVER_MORE = 0; 128 public static final int FRACTION_DELIVER_LAST = 1; 129 130 public static final int FILTER_NO_SMS_GSM = 0x01; 131 public static final int FILTER_NO_SMS_CDMA = 0x02; 132 public static final int FILTER_NO_EMAIL = 0x04; 133 public static final int FILTER_NO_MMS = 0x08; 134 public static final int FILTER_NO_IM = 0x10; 135 public static final int FILTER_MSG_TYPE_MASK = 0x1F; 136 137 private int mMaxListCount = INVALID_VALUE_PARAMETER; 138 private int mStartOffset = INVALID_VALUE_PARAMETER; 139 private int mFilterMessageType = INVALID_VALUE_PARAMETER; 140 // It seems like these are not implemented... 141 private long mFilterPeriodBegin = INVALID_VALUE_PARAMETER; 142 private long mFilterPeriodEnd = INVALID_VALUE_PARAMETER; 143 private int mFilterReadStatus = INVALID_VALUE_PARAMETER; 144 private String mFilterRecipient = null; 145 private String mFilterOriginator = null; 146 private int mFilterPriority = INVALID_VALUE_PARAMETER; 147 private int mAttachment = INVALID_VALUE_PARAMETER; 148 private int mTransparent = INVALID_VALUE_PARAMETER; 149 private int mRetry = INVALID_VALUE_PARAMETER; 150 private int mNewMessage = INVALID_VALUE_PARAMETER; 151 private int mNotificationStatus = INVALID_VALUE_PARAMETER; 152 private long mNotificationFilter = INVALID_VALUE_PARAMETER; 153 private int mMasInstanceId = INVALID_VALUE_PARAMETER; 154 private long mParameterMask = INVALID_VALUE_PARAMETER; 155 private int mFolderListingSize = INVALID_VALUE_PARAMETER; 156 private int mMessageListingSize = INVALID_VALUE_PARAMETER; 157 private int mConvoListingSize = INVALID_VALUE_PARAMETER; 158 private int mSubjectLength = INVALID_VALUE_PARAMETER; 159 private int mCharset = INVALID_VALUE_PARAMETER; 160 private int mFractionRequest = INVALID_VALUE_PARAMETER; 161 private int mFractionDeliver = INVALID_VALUE_PARAMETER; 162 private int mStatusIndicator = INVALID_VALUE_PARAMETER; 163 private int mStatusValue = INVALID_VALUE_PARAMETER; 164 private long mMseTime = INVALID_VALUE_PARAMETER; 165 // TODO: Change to use SignedLongLong? 166 private long mConvoListingVerCounterLow = INVALID_VALUE_PARAMETER; 167 private long mConvoListingVerCounterHigh = INVALID_VALUE_PARAMETER; 168 private long mDatabaseIdentifierLow = INVALID_VALUE_PARAMETER; 169 private long mDatabaseIdentifierHigh = INVALID_VALUE_PARAMETER; 170 private long mFolderVerCounterLow = INVALID_VALUE_PARAMETER; 171 private long mFolderVerCounterHigh = INVALID_VALUE_PARAMETER; 172 private int mPresenceAvailability = INVALID_VALUE_PARAMETER; 173 private String mPresenceStatus = null; 174 private long mLastActivity = INVALID_VALUE_PARAMETER; 175 private int mChatState = INVALID_VALUE_PARAMETER; 176 private SignedLongLong mFilterConvoId = null; 177 private int mFilterPresence = INVALID_VALUE_PARAMETER; 178 private int mFilterUidPresent = INVALID_VALUE_PARAMETER; 179 private SignedLongLong mChatStateConvoId = null; 180 private long mFilterMsgHandle = INVALID_VALUE_PARAMETER; 181 private long mConvoParameterMask = INVALID_VALUE_PARAMETER; 182 183 /** 184 * Default constructor, used to build an application parameter object to be encoded. By default 185 * the member variables will be initialized to {@link INVALID_VALUE_PARAMETER} for values, and 186 * empty strings for String typed members. 187 */ BluetoothMapAppParams()188 public BluetoothMapAppParams() {} 189 190 /** 191 * Creates an application parameter object based on a application parameter OBEX header. The 192 * content of the {@code appParams} byte array will be parsed, and its content will be stored in 193 * the member variables. {@link INVALID_VALUE_PARAMETER} can be used to determine if a value is 194 * set or not, where strings will be empty, if {@code appParams} did not contain the parameter. 195 * 196 * @param appParams the byte array containing the application parameters OBEX header 197 * @throws IllegalArgumentException when a parameter does not respect the valid ranges specified 198 * in the MAP spec. 199 * @throws ParseException if a parameter string if formatted incorrectly. 200 */ BluetoothMapAppParams(final byte[] appParams)201 public BluetoothMapAppParams(final byte[] appParams) 202 throws IllegalArgumentException, ParseException { 203 parseParams(appParams); 204 } 205 206 /** 207 * Parse an application parameter OBEX header stored in a byte array. 208 * 209 * @param appParams the byte array containing the application parameters OBEX header 210 * @throws IllegalArgumentException when a parameter does not respect the valid ranges specified 211 * in the MAP spec. 212 * @throws ParseException if a parameter string if formatted incorrectly. 213 */ parseParams(final byte[] appParams)214 private void parseParams(final byte[] appParams) 215 throws ParseException, IllegalArgumentException { 216 int i = 0; 217 int tagId, tagLength; 218 ByteBuffer appParamBuf = ByteBuffer.wrap(appParams); 219 appParamBuf.order(ByteOrder.BIG_ENDIAN); 220 while (i < appParams.length) { 221 tagId = appParams[i++] & 0xff; // Convert to unsigned to support values above 127 222 tagLength = appParams[i++] & 0xff; // Convert to unsigned to support values above 127 223 switch (tagId) { 224 case MAX_LIST_COUNT: 225 if (tagLength != MAX_LIST_COUNT_LEN) { 226 Log.w( 227 TAG, 228 "MAX_LIST_COUNT: Wrong length received: " 229 + tagLength 230 + " expected: " 231 + MAX_LIST_COUNT_LEN); 232 ContentProfileErrorReportUtils.report( 233 BluetoothProfile.MAP, 234 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 235 BluetoothStatsLog 236 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 237 0); 238 } else { 239 setMaxListCount(appParamBuf.getShort(i) & 0xffff); // Make it unsigned 240 } 241 break; 242 case START_OFFSET: 243 if (tagLength != START_OFFSET_LEN) { 244 Log.w( 245 TAG, 246 "START_OFFSET: Wrong length received: " 247 + tagLength 248 + " expected: " 249 + START_OFFSET_LEN); 250 ContentProfileErrorReportUtils.report( 251 BluetoothProfile.MAP, 252 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 253 BluetoothStatsLog 254 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 255 1); 256 } else { 257 setStartOffset(appParamBuf.getShort(i) & 0xffff); // Make it unsigned 258 } 259 break; 260 case FILTER_MESSAGE_TYPE: 261 if (tagLength != FILTER_MESSAGE_TYPE_LEN) { 262 Log.w( 263 TAG, 264 "FILTER_MESSAGE_TYPE: Wrong length received: " 265 + tagLength 266 + " expected: " 267 + FILTER_MESSAGE_TYPE_LEN); 268 ContentProfileErrorReportUtils.report( 269 BluetoothProfile.MAP, 270 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 271 BluetoothStatsLog 272 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 273 2); 274 } else { 275 setFilterMessageType(appParams[i] & 0x1f); 276 } 277 break; 278 case FILTER_PERIOD_BEGIN: 279 if (tagLength != 0) { 280 setFilterPeriodBegin(new String(appParams, i, tagLength)); 281 } else { 282 Log.w( 283 TAG, 284 "FILTER_PERIOD_BEGIN: Wrong length received: " 285 + tagLength 286 + " expected to be more than 0"); 287 ContentProfileErrorReportUtils.report( 288 BluetoothProfile.MAP, 289 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 290 BluetoothStatsLog 291 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 292 3); 293 } 294 break; 295 case FILTER_PERIOD_END: 296 if (tagLength != 0) { 297 setFilterPeriodEnd(new String(appParams, i, tagLength)); 298 } else { 299 Log.w( 300 TAG, 301 "FILTER_PERIOD_END: Wrong length received: " 302 + tagLength 303 + " expected to be more than 0"); 304 ContentProfileErrorReportUtils.report( 305 BluetoothProfile.MAP, 306 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 307 BluetoothStatsLog 308 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 309 4); 310 } 311 break; 312 case FILTER_READ_STATUS: 313 if (tagLength != FILTER_READ_STATUS_LEN) { 314 Log.w( 315 TAG, 316 "FILTER_READ_STATUS: Wrong length received: " 317 + tagLength 318 + " expected: " 319 + FILTER_READ_STATUS_LEN); 320 ContentProfileErrorReportUtils.report( 321 BluetoothProfile.MAP, 322 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 323 BluetoothStatsLog 324 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 325 5); 326 } else { 327 setFilterReadStatus(appParams[i] & 0x03); // Lower two bits 328 } 329 break; 330 case FILTER_RECIPIENT: 331 if (tagLength != 0) { 332 setFilterRecipient(new String(appParams, i, tagLength)); 333 } else { 334 Log.w( 335 TAG, 336 "FILTER_RECIPIENT: Wrong length received: " 337 + tagLength 338 + " expected to be more than 0"); 339 ContentProfileErrorReportUtils.report( 340 BluetoothProfile.MAP, 341 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 342 BluetoothStatsLog 343 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 344 6); 345 } 346 break; 347 case FILTER_ORIGINATOR: 348 if (tagLength != 0) { 349 setFilterOriginator(new String(appParams, i, tagLength)); 350 } else { 351 Log.w( 352 TAG, 353 "FILTER_ORIGINATOR: Wrong length received: " 354 + tagLength 355 + " expected to be more than 0"); 356 ContentProfileErrorReportUtils.report( 357 BluetoothProfile.MAP, 358 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 359 BluetoothStatsLog 360 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 361 7); 362 } 363 break; 364 case FILTER_PRIORITY: 365 if (tagLength != FILTER_PRIORITY_LEN) { 366 Log.w( 367 TAG, 368 "FILTER_PRIORITY: Wrong length received: " 369 + tagLength 370 + " expected: " 371 + FILTER_PRIORITY_LEN); 372 ContentProfileErrorReportUtils.report( 373 BluetoothProfile.MAP, 374 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 375 BluetoothStatsLog 376 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 377 8); 378 } else { 379 setFilterPriority(appParams[i] & 0x03); // Lower two bits 380 } 381 break; 382 case ATTACHMENT: 383 if (tagLength != ATTACHMENT_LEN) { 384 Log.w( 385 TAG, 386 "ATTACHMENT: Wrong length received: " 387 + tagLength 388 + " expected: " 389 + ATTACHMENT_LEN); 390 ContentProfileErrorReportUtils.report( 391 BluetoothProfile.MAP, 392 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 393 BluetoothStatsLog 394 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 395 9); 396 } else { 397 setAttachment(appParams[i] & 0x01); // Lower bit 398 } 399 break; 400 case TRANSPARENT: 401 if (tagLength != TRANSPARENT_LEN) { 402 Log.w( 403 TAG, 404 "TRANSPARENT: Wrong length received: " 405 + tagLength 406 + " expected: " 407 + TRANSPARENT_LEN); 408 ContentProfileErrorReportUtils.report( 409 BluetoothProfile.MAP, 410 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 411 BluetoothStatsLog 412 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 413 10); 414 } else { 415 setTransparent(appParams[i] & 0x01); // Lower bit 416 } 417 break; 418 case RETRY: 419 if (tagLength != RETRY_LEN) { 420 Log.w( 421 TAG, 422 "RETRY: Wrong length received: " 423 + tagLength 424 + " expected: " 425 + RETRY_LEN); 426 ContentProfileErrorReportUtils.report( 427 BluetoothProfile.MAP, 428 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 429 BluetoothStatsLog 430 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 431 11); 432 } else { 433 setRetry(appParams[i] & 0x01); // Lower bit 434 } 435 break; 436 case NEW_MESSAGE: 437 if (tagLength != NEW_MESSAGE_LEN) { 438 Log.w( 439 TAG, 440 "NEW_MESSAGE: Wrong length received: " 441 + tagLength 442 + " expected: " 443 + NEW_MESSAGE_LEN); 444 ContentProfileErrorReportUtils.report( 445 BluetoothProfile.MAP, 446 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 447 BluetoothStatsLog 448 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 449 12); 450 } else { 451 setNewMessage(appParams[i] & 0x01); // Lower bit 452 } 453 break; 454 case NOTIFICATION_STATUS: 455 if (tagLength != NOTIFICATION_STATUS_LEN) { 456 Log.w( 457 TAG, 458 "NOTIFICATION_STATUS: Wrong length received: " 459 + tagLength 460 + " expected: " 461 + NOTIFICATION_STATUS_LEN); 462 ContentProfileErrorReportUtils.report( 463 BluetoothProfile.MAP, 464 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 465 BluetoothStatsLog 466 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 467 13); 468 } else { 469 setNotificationStatus(appParams[i] & 0x01); // Lower bit 470 } 471 break; 472 case NOTIFICATION_FILTER: 473 if (tagLength != NOTIFICATION_FILTER_LEN) { 474 Log.w( 475 TAG, 476 "NOTIFICATION_FILTER: Wrong length received: " 477 + tagLength 478 + " expected: " 479 + NOTIFICATION_FILTER_LEN); 480 ContentProfileErrorReportUtils.report( 481 BluetoothProfile.MAP, 482 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 483 BluetoothStatsLog 484 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 485 14); 486 } else { 487 setNotificationFilter(appParamBuf.getInt(i) & 0xffffffffL); // 4 bytes 488 } 489 break; 490 case MAS_INSTANCE_ID: 491 if (tagLength != MAS_INSTANCE_ID_LEN) { 492 Log.w( 493 TAG, 494 "MAS_INSTANCE_ID: Wrong length received: " 495 + tagLength 496 + " expected: " 497 + MAS_INSTANCE_ID_LEN); 498 ContentProfileErrorReportUtils.report( 499 BluetoothProfile.MAP, 500 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 501 BluetoothStatsLog 502 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 503 15); 504 } else { 505 setMasInstanceId(appParams[i] & 0xff); 506 } 507 break; 508 case PARAMETER_MASK: 509 if (tagLength != PARAMETER_MASK_LEN) { 510 Log.w( 511 TAG, 512 "PARAMETER_MASK: Wrong length received: " 513 + tagLength 514 + " expected: " 515 + PARAMETER_MASK_LEN); 516 ContentProfileErrorReportUtils.report( 517 BluetoothProfile.MAP, 518 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 519 BluetoothStatsLog 520 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 521 16); 522 } else { 523 setParameterMask(appParamBuf.getInt(i) & 0xffffffffL); // Make it unsigned 524 } 525 break; 526 case FOLDER_LISTING_SIZE: 527 if (tagLength != FOLDER_LISTING_SIZE_LEN) { 528 Log.w( 529 TAG, 530 "FOLDER_LISTING_SIZE: Wrong length received: " 531 + tagLength 532 + " expected: " 533 + FOLDER_LISTING_SIZE_LEN); 534 ContentProfileErrorReportUtils.report( 535 BluetoothProfile.MAP, 536 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 537 BluetoothStatsLog 538 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 539 17); 540 } else { 541 setFolderListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned 542 } 543 break; 544 case MESSAGE_LISTING_SIZE: 545 if (tagLength != MESSAGE_LISTING_SIZE_LEN) { 546 Log.w( 547 TAG, 548 "MESSAGE_LISTING_SIZE: Wrong length received: " 549 + tagLength 550 + " expected: " 551 + MESSAGE_LISTING_SIZE_LEN); 552 ContentProfileErrorReportUtils.report( 553 BluetoothProfile.MAP, 554 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 555 BluetoothStatsLog 556 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 557 18); 558 } else { 559 setMessageListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned 560 } 561 break; 562 case SUBJECT_LENGTH: 563 if (tagLength != SUBJECT_LENGTH_LEN) { 564 Log.w( 565 TAG, 566 "SUBJECT_LENGTH: Wrong length received: " 567 + tagLength 568 + " expected: " 569 + SUBJECT_LENGTH_LEN); 570 ContentProfileErrorReportUtils.report( 571 BluetoothProfile.MAP, 572 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 573 BluetoothStatsLog 574 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 575 19); 576 } else { 577 setSubjectLength(appParams[i] & 0xff); 578 } 579 break; 580 case CHARSET: 581 if (tagLength != CHARSET_LEN) { 582 Log.w( 583 TAG, 584 "CHARSET: Wrong length received: " 585 + tagLength 586 + " expected: " 587 + CHARSET_LEN); 588 ContentProfileErrorReportUtils.report( 589 BluetoothProfile.MAP, 590 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 591 BluetoothStatsLog 592 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 593 20); 594 } else { 595 setCharset(appParams[i] & 0x01); // Lower bit 596 } 597 break; 598 case FRACTION_REQUEST: 599 if (tagLength != FRACTION_REQUEST_LEN) { 600 Log.w( 601 TAG, 602 "FRACTION_REQUEST: Wrong length received: " 603 + tagLength 604 + " expected: " 605 + FRACTION_REQUEST_LEN); 606 ContentProfileErrorReportUtils.report( 607 BluetoothProfile.MAP, 608 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 609 BluetoothStatsLog 610 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 611 21); 612 } else { 613 setFractionRequest(appParams[i] & 0x01); // Lower bit 614 } 615 break; 616 case FRACTION_DELIVER: 617 if (tagLength != FRACTION_DELIVER_LEN) { 618 Log.w( 619 TAG, 620 "FRACTION_DELIVER: Wrong length received: " 621 + tagLength 622 + " expected: " 623 + FRACTION_DELIVER_LEN); 624 ContentProfileErrorReportUtils.report( 625 BluetoothProfile.MAP, 626 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 627 BluetoothStatsLog 628 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 629 22); 630 } else { 631 setFractionDeliver(appParams[i] & 0x01); // Lower bit 632 } 633 break; 634 case STATUS_INDICATOR: 635 if (tagLength != STATUS_INDICATOR_LEN) { 636 Log.w( 637 TAG, 638 "STATUS_INDICATOR: Wrong length received: " 639 + tagLength 640 + " expected: " 641 + STATUS_INDICATOR_LEN); 642 ContentProfileErrorReportUtils.report( 643 BluetoothProfile.MAP, 644 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 645 BluetoothStatsLog 646 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 647 23); 648 } else { 649 setStatusIndicator(appParams[i] & 0x01); // Lower bit 650 } 651 break; 652 case STATUS_VALUE: 653 if (tagLength != STATUS_VALUE_LEN) { 654 Log.w( 655 TAG, 656 "STATUS_VALUER: Wrong length received: " 657 + tagLength 658 + " expected: " 659 + STATUS_VALUE_LEN); 660 ContentProfileErrorReportUtils.report( 661 BluetoothProfile.MAP, 662 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 663 BluetoothStatsLog 664 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 665 24); 666 } else { 667 setStatusValue(appParams[i] & 0x01); // Lower bit 668 } 669 break; 670 case MSE_TIME: 671 setMseTime(new String(appParams, i, tagLength)); 672 break; 673 case DATABASE_IDENTIFIER: 674 if ((tagLength != DATABASE_IDENTIFIER_LEN)) { 675 Log.w( 676 TAG, 677 "DATABASE_IDENTIFIER: Wrong length received: " 678 + tagLength 679 + " expected: " 680 + DATABASE_IDENTIFIER_LEN); 681 ContentProfileErrorReportUtils.report( 682 BluetoothProfile.MAP, 683 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 684 BluetoothStatsLog 685 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 686 25); 687 } else { 688 setDatabaseIdentifier( 689 appParamBuf.getLong(i) /*MSB*/, appParamBuf.getLong(i + 8) /*LSB*/); 690 } 691 break; 692 case CONVO_LIST_VER_COUNTER: 693 if ((tagLength != CONVO_LIST_VER_COUNTER_LEN)) { 694 Log.w( 695 TAG, 696 "CONVO_LIST_VER_COUNTER: Wrong length received: " 697 + tagLength 698 + " expected: " 699 + CONVO_LIST_VER_COUNTER_LEN); 700 ContentProfileErrorReportUtils.report( 701 BluetoothProfile.MAP, 702 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 703 BluetoothStatsLog 704 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 705 26); 706 } else { 707 setConvoListingVerCounter( 708 appParamBuf.getLong(i) /*MSB*/, appParamBuf.getLong(i + 8) /*LSB*/); 709 } 710 break; 711 case PRESENCE_AVAILABLE: 712 if ((tagLength != PRESENCE_AVAILABLE_LEN)) { 713 Log.w( 714 TAG, 715 "PRESENCE_AVAILABLE: Wrong length received: " 716 + tagLength 717 + " expected: " 718 + PRESENCE_AVAILABLE_LEN); 719 ContentProfileErrorReportUtils.report( 720 BluetoothProfile.MAP, 721 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 722 BluetoothStatsLog 723 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 724 27); 725 } else { 726 setPresenceAvailability(appParams[i]); 727 } 728 break; 729 case PRESENCE_TEXT: 730 if (tagLength != 0) { 731 setPresenceStatus(new String(appParams, i, tagLength)); 732 } else { 733 Log.w( 734 TAG, 735 "PRESENCE_STATUS: Wrong length received: " 736 + tagLength 737 + " expected to be more than 0"); 738 ContentProfileErrorReportUtils.report( 739 BluetoothProfile.MAP, 740 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 741 BluetoothStatsLog 742 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 743 28); 744 } 745 break; 746 case LAST_ACTIVITY: 747 if (tagLength != 0) { 748 setLastActivity(new String(appParams, i, tagLength)); 749 } else { 750 Log.w( 751 TAG, 752 "LAST_ACTIVITY: Wrong length received: " 753 + tagLength 754 + " expected to be more than 0"); 755 ContentProfileErrorReportUtils.report( 756 BluetoothProfile.MAP, 757 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 758 BluetoothStatsLog 759 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 760 29); 761 } 762 break; 763 case CHAT_STATE: 764 if ((tagLength != CHAT_STATE_LEN)) { 765 Log.w( 766 TAG, 767 "CHAT_STATE: Wrong length received: " 768 + tagLength 769 + " expected: " 770 + CHAT_STATE_LEN); 771 ContentProfileErrorReportUtils.report( 772 BluetoothProfile.MAP, 773 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 774 BluetoothStatsLog 775 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 776 30); 777 } else { 778 setChatState(appParams[i]); 779 } 780 break; 781 case FILTER_CONVO_ID: 782 if ((tagLength != 0) && (tagLength <= FILTER_CONVO_ID_LEN)) { 783 setFilterConvoId(new String(appParams, i, tagLength)); 784 } else { 785 Log.w( 786 TAG, 787 "FILTER_CONVO_ID: Wrong length received: " 788 + tagLength 789 + " expected: " 790 + FILTER_CONVO_ID_LEN); 791 ContentProfileErrorReportUtils.report( 792 BluetoothProfile.MAP, 793 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 794 BluetoothStatsLog 795 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 796 31); 797 } 798 break; 799 case CONVO_LISTING_SIZE: 800 if (tagLength != CONVO_LISTING_SIZE_LEN) { 801 Log.w( 802 TAG, 803 "LISTING_SIZE: Wrong length received: " 804 + tagLength 805 + " expected: " 806 + CONVO_LISTING_SIZE_LEN); 807 ContentProfileErrorReportUtils.report( 808 BluetoothProfile.MAP, 809 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 810 BluetoothStatsLog 811 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 812 32); 813 } else { 814 setConvoListingSize(appParamBuf.getShort(i) & 0xffff); 815 } 816 break; 817 case FILTER_PRESENCE: 818 if ((tagLength != FILTER_PRESENCE_LEN)) { 819 Log.w( 820 TAG, 821 "FILTER_PRESENCE: Wrong length received: " 822 + tagLength 823 + " expected: " 824 + FILTER_PRESENCE_LEN); 825 ContentProfileErrorReportUtils.report( 826 BluetoothProfile.MAP, 827 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 828 BluetoothStatsLog 829 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 830 33); 831 } else { 832 setFilterPresence(appParams[i]); 833 } 834 break; 835 case FILTER_UID_PRESENT: 836 if ((tagLength != FILTER_UID_PRESENT_LEN)) { 837 Log.w( 838 TAG, 839 "FILTER_UID_PRESENT: Wrong length received: " 840 + tagLength 841 + " expected: " 842 + FILTER_UID_PRESENT_LEN); 843 ContentProfileErrorReportUtils.report( 844 BluetoothProfile.MAP, 845 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 846 BluetoothStatsLog 847 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 848 34); 849 } else { 850 setFilterUidPresent(appParams[i] & 0x1); 851 } 852 break; 853 case CHAT_STATE_CONVO_ID: 854 if ((tagLength != CHAT_STATE_CONVO_ID_LEN)) { 855 Log.w( 856 TAG, 857 "CHAT_STATE_CONVO_ID: Wrong length received: " 858 + tagLength 859 + " expected: " 860 + CHAT_STATE_CONVO_ID_LEN); 861 ContentProfileErrorReportUtils.report( 862 BluetoothProfile.MAP, 863 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 864 BluetoothStatsLog 865 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 866 35); 867 } else { 868 /* TODO: Is this correct convoId handling? */ 869 setChatStateConvoId( 870 appParamBuf.getLong(i) /*MSB*/, appParamBuf.getLong(i + 8) /*LSB*/); 871 Log.d( 872 TAG, 873 "CHAT_STATE_CONVO_ID: convo id " 874 + "MSB=" 875 + BluetoothMapUtils.getLongAsString(appParamBuf.getLong(i)) 876 + ", LSB(+8)=" 877 + BluetoothMapUtils.getLongAsString( 878 appParamBuf.getLong(i + 8))); 879 } 880 break; 881 case FOLDER_VER_COUNTER: 882 break; 883 case FILTER_MESSAGE_HANDLE: 884 if ((tagLength != 0 && tagLength <= FILTER_MESSAGE_HANDLE_LEN)) { 885 setFilterMsgHandle(new String(appParams, i, tagLength)); 886 } else { 887 Log.w( 888 TAG, 889 "FILTER_MESSAGE_HANDLE: Wrong length received: " 890 + tagLength 891 + " expected: " 892 + FILTER_MESSAGE_HANDLE_LEN); 893 ContentProfileErrorReportUtils.report( 894 BluetoothProfile.MAP, 895 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 896 BluetoothStatsLog 897 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 898 36); 899 } 900 901 break; 902 case CONVO_PARAMETER_MASK: 903 if (tagLength != CONVO_PARAMETER_MASK_LEN) { 904 Log.w( 905 TAG, 906 "CONVO_PARAMETER_MASK: Wrong length received: " 907 + tagLength 908 + " expected: " 909 + CONVO_PARAMETER_MASK_LEN); 910 ContentProfileErrorReportUtils.report( 911 BluetoothProfile.MAP, 912 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 913 BluetoothStatsLog 914 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 915 37); 916 } else { 917 setConvoParameterMask( 918 appParamBuf.getInt(i) & 0xffffffffL); // Make it unsigned 919 } 920 break; 921 default: 922 // Just skip unknown Tags, no need to report error 923 Log.w( 924 TAG, 925 "Unknown TagId received ( 0x" 926 + Integer.toString(tagId, 16) 927 + "), skipping..."); 928 ContentProfileErrorReportUtils.report( 929 BluetoothProfile.MAP, 930 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 931 BluetoothStatsLog 932 .BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN, 933 38); 934 break; 935 } 936 i += tagLength; // Offset to next TagId 937 } 938 } 939 940 /** 941 * Get the approximate length needed to store the appParameters in a byte array. 942 * 943 * @return the length in bytes 944 */ getParamMaxLength()945 private int getParamMaxLength() { 946 int length = 0; 947 length += 38 * 2; // tagId + tagLength 948 length += 33 + 4 * 16; // fixed sizes TODO: Update when spec is ready 949 length += getFilterPeriodBegin() == INVALID_VALUE_PARAMETER ? 0 : 20; 950 length += getFilterPeriodEnd() == INVALID_VALUE_PARAMETER ? 0 : 20; 951 if (getFilterRecipient() != null) { 952 length += getFilterRecipient().getBytes(StandardCharsets.UTF_8).length; 953 } 954 if (getFilterOriginator() != null) { 955 length += getFilterOriginator().getBytes(StandardCharsets.UTF_8).length; 956 } 957 length += getMseTime() == INVALID_VALUE_PARAMETER ? 0 : 20; 958 if (getPresenceStatus() != null) { 959 length += getPresenceStatus().getBytes(StandardCharsets.UTF_8).length; 960 } 961 length += (getLastActivity() == INVALID_VALUE_PARAMETER) ? 0 : 20; 962 return length; 963 } 964 965 /** 966 * Encode the application parameter object to a byte array. 967 * 968 * @return a byte Array representation of the application parameter object. 969 */ encodeParams()970 public byte[] encodeParams() { 971 ByteBuffer appParamBuf = ByteBuffer.allocate(getParamMaxLength()); 972 appParamBuf.order(ByteOrder.BIG_ENDIAN); 973 byte[] retBuf; 974 975 if (getMaxListCount() != INVALID_VALUE_PARAMETER) { 976 appParamBuf.put((byte) MAX_LIST_COUNT); 977 appParamBuf.put((byte) MAX_LIST_COUNT_LEN); 978 appParamBuf.putShort((short) getMaxListCount()); 979 } 980 if (getStartOffset() != INVALID_VALUE_PARAMETER) { 981 appParamBuf.put((byte) START_OFFSET); 982 appParamBuf.put((byte) START_OFFSET_LEN); 983 appParamBuf.putShort((short) getStartOffset()); 984 } 985 if (getFilterMessageType() != INVALID_VALUE_PARAMETER) { 986 appParamBuf.put((byte) FILTER_MESSAGE_TYPE); 987 appParamBuf.put((byte) FILTER_MESSAGE_TYPE_LEN); 988 appParamBuf.put((byte) getFilterMessageType()); 989 } 990 if (getFilterPeriodBegin() != INVALID_VALUE_PARAMETER) { 991 appParamBuf.put((byte) FILTER_PERIOD_BEGIN); 992 appParamBuf.put( 993 (byte) getFilterPeriodBeginString().getBytes(StandardCharsets.UTF_8).length); 994 appParamBuf.put(getFilterPeriodBeginString().getBytes(StandardCharsets.UTF_8)); 995 } 996 if (getFilterPeriodEnd() != INVALID_VALUE_PARAMETER) { 997 appParamBuf.put((byte) FILTER_PERIOD_END); 998 appParamBuf.put( 999 (byte) getFilterPeriodEndString().getBytes(StandardCharsets.UTF_8).length); 1000 appParamBuf.put(getFilterPeriodEndString().getBytes(StandardCharsets.UTF_8)); 1001 } 1002 if (getFilterReadStatus() != INVALID_VALUE_PARAMETER) { 1003 appParamBuf.put((byte) FILTER_READ_STATUS); 1004 appParamBuf.put((byte) FILTER_READ_STATUS_LEN); 1005 appParamBuf.put((byte) getFilterReadStatus()); 1006 } 1007 if (getFilterRecipient() != null) { 1008 appParamBuf.put((byte) FILTER_RECIPIENT); 1009 appParamBuf.put((byte) getFilterRecipient().getBytes(StandardCharsets.UTF_8).length); 1010 appParamBuf.put(getFilterRecipient().getBytes(StandardCharsets.UTF_8)); 1011 } 1012 if (getFilterOriginator() != null) { 1013 appParamBuf.put((byte) FILTER_ORIGINATOR); 1014 appParamBuf.put((byte) getFilterOriginator().getBytes(StandardCharsets.UTF_8).length); 1015 appParamBuf.put(getFilterOriginator().getBytes(StandardCharsets.UTF_8)); 1016 } 1017 if (getFilterPriority() != INVALID_VALUE_PARAMETER) { 1018 appParamBuf.put((byte) FILTER_PRIORITY); 1019 appParamBuf.put((byte) FILTER_PRIORITY_LEN); 1020 appParamBuf.put((byte) getFilterPriority()); 1021 } 1022 if (getAttachment() != INVALID_VALUE_PARAMETER) { 1023 appParamBuf.put((byte) ATTACHMENT); 1024 appParamBuf.put((byte) ATTACHMENT_LEN); 1025 appParamBuf.put((byte) getAttachment()); 1026 } 1027 if (getTransparent() != INVALID_VALUE_PARAMETER) { 1028 appParamBuf.put((byte) TRANSPARENT); 1029 appParamBuf.put((byte) TRANSPARENT_LEN); 1030 appParamBuf.put((byte) getTransparent()); 1031 } 1032 if (getRetry() != INVALID_VALUE_PARAMETER) { 1033 appParamBuf.put((byte) RETRY); 1034 appParamBuf.put((byte) RETRY_LEN); 1035 appParamBuf.put((byte) getRetry()); 1036 } 1037 if (getNewMessage() != INVALID_VALUE_PARAMETER) { 1038 appParamBuf.put((byte) NEW_MESSAGE); 1039 appParamBuf.put((byte) NEW_MESSAGE_LEN); 1040 appParamBuf.put((byte) getNewMessage()); 1041 } 1042 if (getNotificationStatus() != INVALID_VALUE_PARAMETER) { 1043 appParamBuf.put((byte) NOTIFICATION_STATUS); 1044 appParamBuf.put((byte) NOTIFICATION_STATUS_LEN); 1045 appParamBuf.putShort((short) getNotificationStatus()); 1046 } 1047 if (getNotificationFilter() != INVALID_VALUE_PARAMETER) { 1048 appParamBuf.put((byte) NOTIFICATION_FILTER); 1049 appParamBuf.put((byte) NOTIFICATION_FILTER_LEN); 1050 appParamBuf.putInt((int) getNotificationFilter()); 1051 } 1052 if (getMasInstanceId() != INVALID_VALUE_PARAMETER) { 1053 appParamBuf.put((byte) MAS_INSTANCE_ID); 1054 appParamBuf.put((byte) MAS_INSTANCE_ID_LEN); 1055 appParamBuf.put((byte) getMasInstanceId()); 1056 } 1057 if (getParameterMask() != INVALID_VALUE_PARAMETER) { 1058 appParamBuf.put((byte) PARAMETER_MASK); 1059 appParamBuf.put((byte) PARAMETER_MASK_LEN); 1060 appParamBuf.putInt((int) getParameterMask()); 1061 } 1062 if (getFolderListingSize() != INVALID_VALUE_PARAMETER) { 1063 appParamBuf.put((byte) FOLDER_LISTING_SIZE); 1064 appParamBuf.put((byte) FOLDER_LISTING_SIZE_LEN); 1065 appParamBuf.putShort((short) getFolderListingSize()); 1066 } 1067 if (getMessageListingSize() != INVALID_VALUE_PARAMETER) { 1068 appParamBuf.put((byte) MESSAGE_LISTING_SIZE); 1069 appParamBuf.put((byte) MESSAGE_LISTING_SIZE_LEN); 1070 appParamBuf.putShort((short) getMessageListingSize()); 1071 } 1072 if (getSubjectLength() != INVALID_VALUE_PARAMETER) { 1073 appParamBuf.put((byte) SUBJECT_LENGTH); 1074 appParamBuf.put((byte) SUBJECT_LENGTH_LEN); 1075 appParamBuf.put((byte) getSubjectLength()); 1076 } 1077 if (getCharset() != INVALID_VALUE_PARAMETER) { 1078 appParamBuf.put((byte) CHARSET); 1079 appParamBuf.put((byte) CHARSET_LEN); 1080 appParamBuf.put((byte) getCharset()); 1081 } 1082 if (getFractionRequest() != INVALID_VALUE_PARAMETER) { 1083 appParamBuf.put((byte) FRACTION_REQUEST); 1084 appParamBuf.put((byte) FRACTION_REQUEST_LEN); 1085 appParamBuf.put((byte) getFractionRequest()); 1086 } 1087 if (getFractionDeliver() != INVALID_VALUE_PARAMETER) { 1088 appParamBuf.put((byte) FRACTION_DELIVER); 1089 appParamBuf.put((byte) FRACTION_DELIVER_LEN); 1090 appParamBuf.put((byte) getFractionDeliver()); 1091 } 1092 if (getStatusIndicator() != INVALID_VALUE_PARAMETER) { 1093 appParamBuf.put((byte) STATUS_INDICATOR); 1094 appParamBuf.put((byte) STATUS_INDICATOR_LEN); 1095 appParamBuf.put((byte) getStatusIndicator()); 1096 } 1097 if (getStatusValue() != INVALID_VALUE_PARAMETER) { 1098 appParamBuf.put((byte) STATUS_VALUE); 1099 appParamBuf.put((byte) STATUS_VALUE_LEN); 1100 appParamBuf.put((byte) getStatusValue()); 1101 } 1102 if (getMseTime() != INVALID_VALUE_PARAMETER) { 1103 appParamBuf.put((byte) MSE_TIME); 1104 appParamBuf.put((byte) getMseTimeString().getBytes(StandardCharsets.UTF_8).length); 1105 appParamBuf.put(getMseTimeString().getBytes(StandardCharsets.UTF_8)); 1106 } 1107 // Note: New for IM 1108 if (getDatabaseIdentifier() != null) { 1109 appParamBuf.put((byte) DATABASE_IDENTIFIER); 1110 appParamBuf.put((byte) DATABASE_IDENTIFIER_LEN); 1111 appParamBuf.put(getDatabaseIdentifier()); 1112 } 1113 if (getConvoListingVerCounter() != null) { 1114 appParamBuf.put((byte) CONVO_LIST_VER_COUNTER); 1115 appParamBuf.put((byte) CONVO_LIST_VER_COUNTER_LEN); 1116 appParamBuf.put(getConvoListingVerCounter()); 1117 } 1118 if (getPresenceAvailability() != INVALID_VALUE_PARAMETER) { 1119 appParamBuf.put((byte) PRESENCE_AVAILABLE); 1120 appParamBuf.put((byte) PRESENCE_AVAILABLE_LEN); 1121 appParamBuf.putInt((int) getPresenceAvailability()); 1122 } 1123 if (getPresenceStatus() != null) { 1124 appParamBuf.put((byte) PRESENCE_TEXT); 1125 appParamBuf.put((byte) getPresenceStatus().getBytes(StandardCharsets.UTF_8).length); 1126 appParamBuf.put(getPresenceStatus().getBytes()); 1127 } 1128 if (getLastActivity() != INVALID_VALUE_PARAMETER) { 1129 appParamBuf.put((byte) LAST_ACTIVITY); 1130 appParamBuf.put((byte) getLastActivityString().getBytes(StandardCharsets.UTF_8).length); 1131 appParamBuf.put(getLastActivityString().getBytes()); 1132 } 1133 if (getChatState() != INVALID_VALUE_PARAMETER) { 1134 appParamBuf.put((byte) CHAT_STATE); 1135 appParamBuf.put((byte) CHAT_STATE_LEN); 1136 appParamBuf.putShort((short) getChatState()); 1137 } 1138 if (getFilterConvoId() != null) { 1139 appParamBuf.put((byte) FILTER_CONVO_ID); 1140 appParamBuf.put((byte) FILTER_CONVO_ID_LEN); 1141 appParamBuf.putLong(getFilterConvoId().mostSignificantBits()); 1142 appParamBuf.putLong(getFilterConvoId().leastSignificantBits()); 1143 } 1144 if (getConvoListingSize() != INVALID_VALUE_PARAMETER) { 1145 appParamBuf.put((byte) CONVO_LISTING_SIZE); 1146 appParamBuf.put((byte) CONVO_LISTING_SIZE_LEN); 1147 appParamBuf.putShort((short) getConvoListingSize()); 1148 } 1149 if (getFilterPresence() != INVALID_VALUE_PARAMETER) { 1150 appParamBuf.put((byte) FILTER_PRESENCE); 1151 appParamBuf.put((byte) FILTER_PRESENCE_LEN); 1152 appParamBuf.putShort((short) getFilterPresence()); 1153 } 1154 if (getFilterUidPresent() != INVALID_VALUE_PARAMETER) { 1155 appParamBuf.put((byte) FILTER_UID_PRESENT); 1156 appParamBuf.put((byte) FILTER_UID_PRESENT_LEN); 1157 appParamBuf.putShort((short) getFilterUidPresent()); 1158 } 1159 if (getChatStateConvoId() != null) { 1160 appParamBuf.put((byte) CHAT_STATE_CONVO_ID); 1161 appParamBuf.put((byte) CHAT_STATE_CONVO_ID_LEN); 1162 appParamBuf.putLong(getChatStateConvoId().mostSignificantBits()); 1163 appParamBuf.putLong(getChatStateConvoId().leastSignificantBits()); 1164 } 1165 if (getFolderVerCounter() != null) { 1166 appParamBuf.put((byte) FOLDER_VER_COUNTER); 1167 appParamBuf.put((byte) FOLDER_VER_COUNTER_LEN); 1168 appParamBuf.put(getFolderVerCounter()); 1169 } 1170 if (getFilterMsgHandle() != INVALID_VALUE_PARAMETER) { 1171 appParamBuf.put((byte) FILTER_MESSAGE_HANDLE); 1172 appParamBuf.put((byte) FILTER_MESSAGE_HANDLE_LEN); 1173 appParamBuf.putLong(getFilterMsgHandle()); 1174 } 1175 if (getConvoParameterMask() != INVALID_VALUE_PARAMETER) { 1176 appParamBuf.put((byte) CONVO_PARAMETER_MASK); 1177 appParamBuf.put((byte) CONVO_PARAMETER_MASK_LEN); 1178 appParamBuf.putInt((int) getConvoParameterMask()); 1179 } 1180 1181 // We need to reduce the length of the array to match the content 1182 retBuf = 1183 Arrays.copyOfRange( 1184 appParamBuf.array(), 1185 appParamBuf.arrayOffset(), 1186 appParamBuf.arrayOffset() + appParamBuf.position()); 1187 return retBuf; 1188 } 1189 getMaxListCount()1190 public int getMaxListCount() { 1191 return mMaxListCount; 1192 } 1193 setMaxListCount(int maxListCount)1194 public void setMaxListCount(int maxListCount) throws IllegalArgumentException { 1195 if (maxListCount < 0 || maxListCount > 0xFFFF) { 1196 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF"); 1197 } 1198 this.mMaxListCount = maxListCount; 1199 } 1200 getStartOffset()1201 public int getStartOffset() { 1202 return mStartOffset; 1203 } 1204 setStartOffset(int startOffset)1205 public void setStartOffset(int startOffset) throws IllegalArgumentException { 1206 if (startOffset < 0 || startOffset > 0xFFFF) { 1207 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF"); 1208 } 1209 this.mStartOffset = startOffset; 1210 } 1211 getFilterMessageType()1212 public int getFilterMessageType() { 1213 return mFilterMessageType; 1214 } 1215 setFilterMessageType(int filterMessageType)1216 public void setFilterMessageType(int filterMessageType) throws IllegalArgumentException { 1217 if (filterMessageType < 0 || filterMessageType > 0x001F) { 1218 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x001F"); 1219 } 1220 this.mFilterMessageType = filterMessageType; 1221 } 1222 getFilterPeriodBegin()1223 public long getFilterPeriodBegin() { 1224 return mFilterPeriodBegin; 1225 } 1226 1227 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate getFilterPeriodBeginString()1228 public String getFilterPeriodBeginString() { 1229 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT); 1230 Date date = new Date(mFilterPeriodBegin); 1231 return format.format(date); // Format to YYYYMMDDTHHMMSS local time 1232 } 1233 setFilterPeriodBegin(long filterPeriodBegin)1234 public void setFilterPeriodBegin(long filterPeriodBegin) { 1235 this.mFilterPeriodBegin = filterPeriodBegin; 1236 } 1237 1238 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate setFilterPeriodBegin(String filterPeriodBegin)1239 public void setFilterPeriodBegin(String filterPeriodBegin) throws ParseException { 1240 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT); 1241 Date date = format.parse(filterPeriodBegin); 1242 this.mFilterPeriodBegin = date.getTime(); 1243 } 1244 getFilterLastActivityBegin()1245 public long getFilterLastActivityBegin() { 1246 return mFilterPeriodBegin; 1247 } 1248 1249 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate getFilterLastActivityBeginString()1250 public String getFilterLastActivityBeginString() { 1251 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT); 1252 Date date = new Date(mFilterPeriodBegin); 1253 return format.format(date); // Format to YYYYMMDDTHHMMSS local time 1254 } 1255 setFilterLastActivityBegin(long filterPeriodBegin)1256 public void setFilterLastActivityBegin(long filterPeriodBegin) { 1257 this.mFilterPeriodBegin = filterPeriodBegin; 1258 } 1259 1260 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate setFilterLastActivityBegin(String filterPeriodBegin)1261 public void setFilterLastActivityBegin(String filterPeriodBegin) throws ParseException { 1262 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT); 1263 Date date = format.parse(filterPeriodBegin); 1264 this.mFilterPeriodBegin = date.getTime(); 1265 } 1266 getFilterPeriodEnd()1267 public long getFilterPeriodEnd() { 1268 return mFilterPeriodEnd; 1269 } 1270 getFilterLastActivityEnd()1271 public long getFilterLastActivityEnd() { 1272 return mFilterPeriodEnd; 1273 } 1274 1275 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate getFilterLastActivityEndString()1276 public String getFilterLastActivityEndString() { 1277 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT); 1278 Date date = new Date(mFilterPeriodEnd); 1279 return format.format(date); // Format to YYYYMMDDTHHMMSS local time 1280 } 1281 setFilterLastActivityEnd(long filterPeriodEnd)1282 public void setFilterLastActivityEnd(long filterPeriodEnd) { 1283 this.mFilterPeriodEnd = filterPeriodEnd; // er reuse the same 1284 } 1285 1286 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate setFilterPeriodEnd(String filterPeriodEnd)1287 public void setFilterPeriodEnd(String filterPeriodEnd) throws ParseException { 1288 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT); 1289 Date date = format.parse(filterPeriodEnd); 1290 this.mFilterPeriodEnd = date.getTime(); 1291 } 1292 1293 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate getFilterPeriodEndString()1294 public String getFilterPeriodEndString() { 1295 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT); 1296 Date date = new Date(mFilterPeriodEnd); 1297 return format.format(date); // Format to YYYYMMDDTHHMMSS local time 1298 } 1299 setFilterPeriodEnd(long filterPeriodEnd)1300 public void setFilterPeriodEnd(long filterPeriodEnd) { 1301 this.mFilterPeriodEnd = filterPeriodEnd; 1302 } 1303 1304 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate setFilterLastActivityEnd(String filterPeriodEnd)1305 public void setFilterLastActivityEnd(String filterPeriodEnd) throws ParseException { 1306 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss", Locale.ROOT); 1307 Date date = format.parse(filterPeriodEnd); 1308 this.mFilterPeriodEnd = date.getTime(); 1309 } 1310 getFilterReadStatus()1311 public int getFilterReadStatus() { 1312 return mFilterReadStatus; 1313 } 1314 setFilterReadStatus(int filterReadStatus)1315 public void setFilterReadStatus(int filterReadStatus) throws IllegalArgumentException { 1316 if (filterReadStatus < 0 || filterReadStatus > 0x0002) { 1317 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002"); 1318 } 1319 this.mFilterReadStatus = filterReadStatus; 1320 } 1321 getFilterRecipient()1322 public String getFilterRecipient() { 1323 return mFilterRecipient; 1324 } 1325 setFilterRecipient(String filterRecipient)1326 public void setFilterRecipient(String filterRecipient) { 1327 this.mFilterRecipient = filterRecipient; 1328 } 1329 getFilterOriginator()1330 public String getFilterOriginator() { 1331 return mFilterOriginator; 1332 } 1333 setFilterOriginator(String filterOriginator)1334 public void setFilterOriginator(String filterOriginator) { 1335 this.mFilterOriginator = filterOriginator; 1336 } 1337 getFilterPriority()1338 public int getFilterPriority() { 1339 return mFilterPriority; 1340 } 1341 setFilterPriority(int filterPriority)1342 public void setFilterPriority(int filterPriority) throws IllegalArgumentException { 1343 if (filterPriority < 0 || filterPriority > 0x0002) { 1344 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002"); 1345 } 1346 this.mFilterPriority = filterPriority; 1347 } 1348 setDatabaseIdentifier(long idHigh, long idLow)1349 public void setDatabaseIdentifier(long idHigh, long idLow) { 1350 this.mDatabaseIdentifierHigh = idHigh; 1351 this.mDatabaseIdentifierLow = idLow; 1352 } 1353 getDatabaseIdentifier()1354 public byte[] getDatabaseIdentifier() { 1355 if (mDatabaseIdentifierLow != INVALID_VALUE_PARAMETER 1356 && mDatabaseIdentifierHigh != INVALID_VALUE_PARAMETER) { 1357 ByteBuffer ret = ByteBuffer.allocate(16); 1358 ret.putLong(mDatabaseIdentifierHigh); 1359 ret.putLong(mDatabaseIdentifierLow); 1360 return ret.array(); 1361 } else { 1362 return null; 1363 } 1364 } 1365 setConvoListingVerCounter(long countLow, long countHigh)1366 public void setConvoListingVerCounter(long countLow, long countHigh) { 1367 this.mConvoListingVerCounterHigh = countHigh; 1368 this.mConvoListingVerCounterLow = countLow; 1369 } 1370 getConvoListingVerCounter()1371 public byte[] getConvoListingVerCounter() { 1372 if (mConvoListingVerCounterHigh != INVALID_VALUE_PARAMETER 1373 && mConvoListingVerCounterLow != INVALID_VALUE_PARAMETER) { 1374 ByteBuffer ret = ByteBuffer.allocate(16); 1375 ret.putLong(mConvoListingVerCounterHigh); 1376 ret.putLong(mConvoListingVerCounterLow); 1377 return ret.array(); 1378 } else { 1379 return null; 1380 } 1381 } 1382 setFolderVerCounter(long countLow, long countHigh)1383 public void setFolderVerCounter(long countLow, long countHigh) { 1384 this.mFolderVerCounterHigh = countHigh; 1385 this.mFolderVerCounterLow = countLow; 1386 } 1387 getFolderVerCounter()1388 public byte[] getFolderVerCounter() { 1389 if (mFolderVerCounterHigh != INVALID_VALUE_PARAMETER 1390 && mFolderVerCounterLow != INVALID_VALUE_PARAMETER) { 1391 ByteBuffer ret = ByteBuffer.allocate(16); 1392 ret.putLong(mFolderVerCounterHigh); 1393 ret.putLong(mFolderVerCounterLow); 1394 return ret.array(); 1395 } else { 1396 return null; 1397 } 1398 } 1399 getChatStateConvoId()1400 public SignedLongLong getChatStateConvoId() { 1401 return mChatStateConvoId; 1402 } 1403 getChatStateConvoIdByteArray()1404 public byte[] getChatStateConvoIdByteArray() { 1405 if (mChatStateConvoId != null) { 1406 ByteBuffer ret = ByteBuffer.allocate(16); 1407 ret.putLong(mChatStateConvoId.mostSignificantBits()); 1408 ret.putLong(mChatStateConvoId.leastSignificantBits()); 1409 return ret.array(); 1410 } else { 1411 return null; 1412 } 1413 } 1414 getChatStateConvoIdString()1415 public String getChatStateConvoIdString() { 1416 return new String(this.getChatStateConvoIdByteArray()); 1417 } 1418 setChatStateConvoId(long idHigh, long idLow)1419 public void setChatStateConvoId(long idHigh, long idLow) { 1420 mChatStateConvoId = new SignedLongLong(idLow, idHigh); 1421 } 1422 setFilterMsgHandle(String handle)1423 public void setFilterMsgHandle(String handle) { 1424 try { 1425 mFilterMsgHandle = BluetoothMapUtils.getLongFromString(handle); 1426 } catch (NumberFormatException e) { 1427 ContentProfileErrorReportUtils.report( 1428 BluetoothProfile.MAP, 1429 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 1430 BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, 1431 39); 1432 Log.w(TAG, "Error creating long from handle string", e); 1433 } 1434 } 1435 getFilterMsgHandle()1436 public long getFilterMsgHandle() { 1437 return mFilterMsgHandle; 1438 } 1439 getFilterMsgHandleString()1440 public String getFilterMsgHandleString() { 1441 String str = null; 1442 if (mFilterMsgHandle != INVALID_VALUE_PARAMETER) { 1443 str = BluetoothMapUtils.getLongAsString(mFilterMsgHandle); 1444 } 1445 return str; 1446 } 1447 getFilterUidPresent()1448 public int getFilterUidPresent() { 1449 return mFilterUidPresent; 1450 } 1451 setFilterUidPresent(int present)1452 public void setFilterUidPresent(int present) { 1453 if (present < 0 || present > 0x00FF) { 1454 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF"); 1455 } 1456 this.mFilterUidPresent = present; 1457 } 1458 getFilterPresence()1459 public int getFilterPresence() { 1460 return mFilterPresence; 1461 } 1462 getFilterConvoId()1463 public SignedLongLong getFilterConvoId() { 1464 return mFilterConvoId; 1465 } 1466 1467 /** 1468 * Get a decimal representation of the lower bits of the ConvoId - used for queries. The upper 1469 * bits are used for convo-type. 1470 * 1471 * @return decimal representation of the convo ID. 1472 */ getFilterConvoIdString()1473 public String getFilterConvoIdString() { 1474 String str = null; 1475 if (mFilterConvoId != null) { 1476 str = BluetoothMapUtils.getLongAsString(mFilterConvoId.leastSignificantBits()); 1477 } 1478 return str; 1479 } 1480 setFilterConvoId(String id)1481 public void setFilterConvoId(String id) { 1482 try { 1483 mFilterConvoId = SignedLongLong.fromString(id); 1484 } catch (NumberFormatException e) { 1485 ContentProfileErrorReportUtils.report( 1486 BluetoothProfile.MAP, 1487 BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS, 1488 BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION, 1489 40); 1490 Log.w(TAG, "Error creating long from id string", e); 1491 } 1492 } 1493 setChatState(int state)1494 public void setChatState(int state) { 1495 if (state < 0 || state > 0x00FF) { 1496 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF"); 1497 } 1498 this.mChatState = state; 1499 } 1500 getChatState()1501 public int getChatState() { 1502 return mChatState; 1503 } 1504 getLastActivity()1505 public long getLastActivity() { 1506 return this.mLastActivity; 1507 } 1508 1509 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate getLastActivityString()1510 public String getLastActivityString() { 1511 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ", Locale.ROOT); 1512 Date date = new Date(mLastActivity); 1513 return format.format(date); // Format to YYYYMMDDTHHMMSS local time 1514 } 1515 setLastActivity(long last)1516 public void setLastActivity(long last) { 1517 this.mLastActivity = last; 1518 } 1519 1520 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate setLastActivity(String lastActivity)1521 public void setLastActivity(String lastActivity) throws ParseException { 1522 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ", Locale.ROOT); 1523 Date date = format.parse(lastActivity); 1524 this.mLastActivity = date.getTime(); 1525 } 1526 setPresenceStatus(String status)1527 public void setPresenceStatus(String status) { 1528 this.mPresenceStatus = status; 1529 } 1530 getPresenceStatus()1531 public String getPresenceStatus() { 1532 return this.mPresenceStatus; 1533 } 1534 setFilterPresence(int presence)1535 public void setFilterPresence(int presence) { 1536 if (presence < 0 || presence > 0xFFFF) { 1537 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF"); 1538 } 1539 this.mFilterPresence = presence; 1540 } 1541 setPresenceAvailability(int availability)1542 public void setPresenceAvailability(int availability) { 1543 if (availability < 0 || availability > 0x00FF) { 1544 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF"); 1545 } 1546 this.mPresenceAvailability = availability; 1547 } 1548 getPresenceAvailability()1549 public int getPresenceAvailability() { 1550 return mPresenceAvailability; 1551 } 1552 getSubjectLength()1553 public int getSubjectLength() { 1554 return mSubjectLength; 1555 } 1556 getAttachment()1557 public int getAttachment() { 1558 return mAttachment; 1559 } 1560 setAttachment(int attachment)1561 public void setAttachment(int attachment) throws IllegalArgumentException { 1562 if (attachment < 0 || attachment > 0x0001) { 1563 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1564 } 1565 this.mAttachment = attachment; 1566 } 1567 getTransparent()1568 public int getTransparent() { 1569 return mTransparent; 1570 } 1571 setTransparent(int transparent)1572 public void setTransparent(int transparent) throws IllegalArgumentException { 1573 if (transparent < 0 || transparent > 0x0001) { 1574 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1575 } 1576 this.mTransparent = transparent; 1577 } 1578 getRetry()1579 public int getRetry() { 1580 return mRetry; 1581 } 1582 setRetry(int retry)1583 public void setRetry(int retry) throws IllegalArgumentException { 1584 if (retry < 0 || retry > 0x0001) { 1585 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1586 } 1587 this.mRetry = retry; 1588 } 1589 getNewMessage()1590 public int getNewMessage() { 1591 return mNewMessage; 1592 } 1593 setNewMessage(int newMessage)1594 public void setNewMessage(int newMessage) throws IllegalArgumentException { 1595 if (newMessage < 0 || newMessage > 0x0001) { 1596 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1597 } 1598 this.mNewMessage = newMessage; 1599 } 1600 getNotificationStatus()1601 public int getNotificationStatus() { 1602 return mNotificationStatus; 1603 } 1604 setNotificationStatus(int notificationStatus)1605 public void setNotificationStatus(int notificationStatus) throws IllegalArgumentException { 1606 if (notificationStatus < 0 || notificationStatus > 0x0001) { 1607 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1608 } 1609 this.mNotificationStatus = notificationStatus; 1610 } 1611 getNotificationFilter()1612 public long getNotificationFilter() { 1613 return mNotificationFilter; 1614 } 1615 setNotificationFilter(long notificationFilter)1616 public void setNotificationFilter(long notificationFilter) throws IllegalArgumentException { 1617 if (notificationFilter < 0 || notificationFilter > 0xFFFFFFFFL) { 1618 throw new IllegalArgumentException( 1619 "Out of range, valid range is 0x0000 to 0xFFFFFFFFL"); 1620 } 1621 this.mNotificationFilter = notificationFilter; 1622 } 1623 getMasInstanceId()1624 public int getMasInstanceId() { 1625 return mMasInstanceId; 1626 } 1627 setMasInstanceId(int masInstanceId)1628 public void setMasInstanceId(int masInstanceId) { 1629 if (masInstanceId < 0 || masInstanceId > 0x00FF) { 1630 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF"); 1631 } 1632 this.mMasInstanceId = masInstanceId; 1633 } 1634 getParameterMask()1635 public long getParameterMask() { 1636 return mParameterMask; 1637 } 1638 setParameterMask(long parameterMask)1639 public void setParameterMask(long parameterMask) { 1640 if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL) { 1641 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF"); 1642 } 1643 this.mParameterMask = parameterMask; 1644 } 1645 setConvoParameterMask(long parameterMask)1646 public void setConvoParameterMask(long parameterMask) { 1647 if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL) { 1648 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF"); 1649 } 1650 this.mConvoParameterMask = parameterMask; 1651 } 1652 getConvoParameterMask()1653 public long getConvoParameterMask() { 1654 return mConvoParameterMask; 1655 } 1656 getFolderListingSize()1657 public int getFolderListingSize() { 1658 return mFolderListingSize; 1659 } 1660 setFolderListingSize(int folderListingSize)1661 public void setFolderListingSize(int folderListingSize) { 1662 if (folderListingSize < 0 || folderListingSize > 0xFFFF) { 1663 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF"); 1664 } 1665 this.mFolderListingSize = folderListingSize; 1666 } 1667 getMessageListingSize()1668 public int getMessageListingSize() { 1669 return mMessageListingSize; 1670 } 1671 setMessageListingSize(int messageListingSize)1672 public void setMessageListingSize(int messageListingSize) { 1673 if (messageListingSize < 0 || messageListingSize > 0xFFFF) { 1674 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF"); 1675 } 1676 this.mMessageListingSize = messageListingSize; 1677 } 1678 getConvoListingSize()1679 public int getConvoListingSize() { 1680 return mConvoListingSize; 1681 } 1682 setConvoListingSize(int convoListingSize)1683 public void setConvoListingSize(int convoListingSize) { 1684 if (convoListingSize < 0 || convoListingSize > 0xFFFF) { 1685 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF"); 1686 } 1687 this.mConvoListingSize = convoListingSize; 1688 } 1689 setSubjectLength(int subjectLength)1690 public void setSubjectLength(int subjectLength) { 1691 if (subjectLength < 0 || subjectLength > 0xFF) { 1692 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF"); 1693 } 1694 this.mSubjectLength = subjectLength; 1695 } 1696 getCharset()1697 public int getCharset() { 1698 return mCharset; 1699 } 1700 setCharset(int charset)1701 public void setCharset(int charset) { 1702 if (charset < 0 || charset > 0x1) { 1703 throw new IllegalArgumentException( 1704 "Out of range: " + charset + ", valid range is 0x0000 to 0x0001"); 1705 } 1706 this.mCharset = charset; 1707 } 1708 getFractionRequest()1709 public int getFractionRequest() { 1710 return mFractionRequest; 1711 } 1712 setFractionRequest(int fractionRequest)1713 public void setFractionRequest(int fractionRequest) { 1714 if (fractionRequest < 0 || fractionRequest > 0x1) { 1715 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1716 } 1717 this.mFractionRequest = fractionRequest; 1718 } 1719 getFractionDeliver()1720 public int getFractionDeliver() { 1721 return mFractionDeliver; 1722 } 1723 setFractionDeliver(int fractionDeliver)1724 public void setFractionDeliver(int fractionDeliver) { 1725 if (fractionDeliver < 0 || fractionDeliver > 0x1) { 1726 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1727 } 1728 this.mFractionDeliver = fractionDeliver; 1729 } 1730 getStatusIndicator()1731 public int getStatusIndicator() { 1732 return mStatusIndicator; 1733 } 1734 setStatusIndicator(int statusIndicator)1735 public void setStatusIndicator(int statusIndicator) { 1736 if (statusIndicator < 0 || statusIndicator > 0x1) { 1737 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1738 } 1739 this.mStatusIndicator = statusIndicator; 1740 } 1741 getStatusValue()1742 public int getStatusValue() { 1743 return mStatusValue; 1744 } 1745 setStatusValue(int statusValue)1746 public void setStatusValue(int statusValue) { 1747 if (statusValue < 0 || statusValue > 0x1) { 1748 throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001"); 1749 } 1750 this.mStatusValue = statusValue; 1751 } 1752 getMseTime()1753 public long getMseTime() { 1754 return mMseTime; 1755 } 1756 1757 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate getMseTimeString()1758 public String getMseTimeString() { 1759 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ", Locale.ROOT); 1760 Date date = new Date(getMseTime()); 1761 return format.format(date); // Format to YYYYMMDDTHHMMSS±hhmm UTC time ± offset 1762 } 1763 setMseTime(long mseTime)1764 public void setMseTime(long mseTime) { 1765 this.mMseTime = mseTime; 1766 } 1767 1768 @SuppressWarnings("JavaUtilDate") // TODO: b/365629730 -- prefer Instant or LocalDate setMseTime(String mseTime)1769 public void setMseTime(String mseTime) throws ParseException { 1770 SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ", Locale.ROOT); 1771 Date date = format.parse(mseTime); 1772 this.mMseTime = date.getTime(); 1773 } 1774 } 1775