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