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.io.UnsupportedEncodingException;
26 import java.nio.ByteBuffer;
27 import java.nio.ByteOrder;
28 import java.text.ParseException;
29 import java.text.SimpleDateFormat;
30 import java.util.Arrays;
31 import java.util.Date;
32 
33 /** This class encapsulates the appParams needed for MAP. */
34 // Next tag value for ContentProfileErrorReportUtils.report(): 41
35 public class BluetoothMapAppParams {
36 
37     private static final String TAG = "BluetoothMapAppParams";
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_INDETIFIER = 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_INDETIFIER_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 {@link appParam} 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 {@link appParam} 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 formated 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 formated 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_INDETIFIER:
674                     if ((tagLength != DATABASE_INDETIFIER_LEN)) {
675                         Log.w(
676                                 TAG,
677                                 "DATABASE_IDENTIFIER: Wrong length received: "
678                                         + tagLength
679                                         + " expected: "
680                                         + DATABASE_INDETIFIER_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      * @throws UnsupportedEncodingException if the platform does not support UTF-8 encoding.
945      */
getParamMaxLength()946     private int getParamMaxLength() throws UnsupportedEncodingException {
947         int length = 0;
948         length += 38 * 2; // tagId + tagLength
949         length += 33 + 4 * 16; // fixed sizes TODO: Update when spec is ready
950         length += getFilterPeriodBegin() == INVALID_VALUE_PARAMETER ? 0 : 20;
951         length += getFilterPeriodEnd() == INVALID_VALUE_PARAMETER ? 0 : 20;
952         if (getFilterRecipient() != null) {
953             length += getFilterRecipient().getBytes("UTF-8").length;
954         }
955         if (getFilterOriginator() != null) {
956             length += getFilterOriginator().getBytes("UTF-8").length;
957         }
958         length += getMseTime() == INVALID_VALUE_PARAMETER ? 0 : 20;
959         if (getPresenceStatus() != null) {
960             length += getPresenceStatus().getBytes("UTF-8").length;
961         }
962         length += (getLastActivity() == INVALID_VALUE_PARAMETER) ? 0 : 20;
963         return length;
964     }
965 
966     /**
967      * Encode the application parameter object to a byte array.
968      *
969      * @return a byte Array representation of the application parameter object.
970      * @throws UnsupportedEncodingException if the platform does not support UTF-8 encoding.
971      */
encodeParams()972     public byte[] encodeParams() throws UnsupportedEncodingException {
973         ByteBuffer appParamBuf = ByteBuffer.allocate(getParamMaxLength());
974         appParamBuf.order(ByteOrder.BIG_ENDIAN);
975         byte[] retBuf;
976 
977         if (getMaxListCount() != INVALID_VALUE_PARAMETER) {
978             appParamBuf.put((byte) MAX_LIST_COUNT);
979             appParamBuf.put((byte) MAX_LIST_COUNT_LEN);
980             appParamBuf.putShort((short) getMaxListCount());
981         }
982         if (getStartOffset() != INVALID_VALUE_PARAMETER) {
983             appParamBuf.put((byte) START_OFFSET);
984             appParamBuf.put((byte) START_OFFSET_LEN);
985             appParamBuf.putShort((short) getStartOffset());
986         }
987         if (getFilterMessageType() != INVALID_VALUE_PARAMETER) {
988             appParamBuf.put((byte) FILTER_MESSAGE_TYPE);
989             appParamBuf.put((byte) FILTER_MESSAGE_TYPE_LEN);
990             appParamBuf.put((byte) getFilterMessageType());
991         }
992         if (getFilterPeriodBegin() != INVALID_VALUE_PARAMETER) {
993             appParamBuf.put((byte) FILTER_PERIOD_BEGIN);
994             appParamBuf.put((byte) getFilterPeriodBeginString().getBytes("UTF-8").length);
995             appParamBuf.put(getFilterPeriodBeginString().getBytes("UTF-8"));
996         }
997         if (getFilterPeriodEnd() != INVALID_VALUE_PARAMETER) {
998             appParamBuf.put((byte) FILTER_PERIOD_END);
999             appParamBuf.put((byte) getFilterPeriodEndString().getBytes("UTF-8").length);
1000             appParamBuf.put(getFilterPeriodEndString().getBytes("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("UTF-8").length);
1010             appParamBuf.put(getFilterRecipient().getBytes("UTF-8"));
1011         }
1012         if (getFilterOriginator() != null) {
1013             appParamBuf.put((byte) FILTER_ORIGINATOR);
1014             appParamBuf.put((byte) getFilterOriginator().getBytes("UTF-8").length);
1015             appParamBuf.put(getFilterOriginator().getBytes("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("UTF-8").length);
1105             appParamBuf.put(getMseTimeString().getBytes("UTF-8"));
1106         }
1107         // Note: New for IM
1108         if (getDatabaseIdentifier() != null) {
1109             appParamBuf.put((byte) DATABASE_INDETIFIER);
1110             appParamBuf.put((byte) DATABASE_INDETIFIER_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("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("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().getMostSignificantBits());
1142             appParamBuf.putLong(getFilterConvoId().getLeastSignificantBits());
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().getMostSignificantBits());
1163             appParamBuf.putLong(getChatStateConvoId().getLeastSignificantBits());
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 
getFilterPeriodBeginString()1227     public String getFilterPeriodBeginString() {
1228         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
1229         Date date = new Date(mFilterPeriodBegin);
1230         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
1231     }
1232 
setFilterPeriodBegin(long filterPeriodBegin)1233     public void setFilterPeriodBegin(long filterPeriodBegin) {
1234         this.mFilterPeriodBegin = filterPeriodBegin;
1235     }
1236 
setFilterPeriodBegin(String filterPeriodBegin)1237     public void setFilterPeriodBegin(String filterPeriodBegin) throws ParseException {
1238         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
1239         Date date = format.parse(filterPeriodBegin);
1240         this.mFilterPeriodBegin = date.getTime();
1241     }
1242 
getFilterLastActivityBegin()1243     public long getFilterLastActivityBegin() {
1244         return mFilterPeriodBegin;
1245     }
1246 
getFilterLastActivityBeginString()1247     public String getFilterLastActivityBeginString() {
1248         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
1249         Date date = new Date(mFilterPeriodBegin);
1250         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
1251     }
1252 
setFilterLastActivityBegin(long filterPeriodBegin)1253     public void setFilterLastActivityBegin(long filterPeriodBegin) {
1254         this.mFilterPeriodBegin = filterPeriodBegin;
1255     }
1256 
setFilterLastActivityBegin(String filterPeriodBegin)1257     public void setFilterLastActivityBegin(String filterPeriodBegin) throws ParseException {
1258         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
1259         Date date = format.parse(filterPeriodBegin);
1260         this.mFilterPeriodBegin = date.getTime();
1261     }
1262 
getFilterPeriodEnd()1263     public long getFilterPeriodEnd() {
1264         return mFilterPeriodEnd;
1265     }
1266 
getFilterLastActivityEnd()1267     public long getFilterLastActivityEnd() {
1268         return mFilterPeriodEnd;
1269     }
1270 
getFilterLastActivityEndString()1271     public String getFilterLastActivityEndString() {
1272         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
1273         Date date = new Date(mFilterPeriodEnd);
1274         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
1275     }
1276 
setFilterLastActivityEnd(long filterPeriodEnd)1277     public void setFilterLastActivityEnd(long filterPeriodEnd) {
1278         this.mFilterPeriodEnd = filterPeriodEnd; // er reuse the same
1279     }
1280 
setFilterPeriodEnd(String filterPeriodEnd)1281     public void setFilterPeriodEnd(String filterPeriodEnd) throws ParseException {
1282         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
1283         Date date = format.parse(filterPeriodEnd);
1284         this.mFilterPeriodEnd = date.getTime();
1285     }
1286 
getFilterPeriodEndString()1287     public String getFilterPeriodEndString() {
1288         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
1289         Date date = new Date(mFilterPeriodEnd);
1290         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
1291     }
1292 
setFilterPeriodEnd(long filterPeriodEnd)1293     public void setFilterPeriodEnd(long filterPeriodEnd) {
1294         this.mFilterPeriodEnd = filterPeriodEnd;
1295     }
1296 
setFilterLastActivityEnd(String filterPeriodEnd)1297     public void setFilterLastActivityEnd(String filterPeriodEnd) throws ParseException {
1298         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
1299         Date date = format.parse(filterPeriodEnd);
1300         this.mFilterPeriodEnd = date.getTime();
1301     }
1302 
getFilterReadStatus()1303     public int getFilterReadStatus() {
1304         return mFilterReadStatus;
1305     }
1306 
setFilterReadStatus(int filterReadStatus)1307     public void setFilterReadStatus(int filterReadStatus) throws IllegalArgumentException {
1308         if (filterReadStatus < 0 || filterReadStatus > 0x0002) {
1309             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
1310         }
1311         this.mFilterReadStatus = filterReadStatus;
1312     }
1313 
getFilterRecipient()1314     public String getFilterRecipient() {
1315         return mFilterRecipient;
1316     }
1317 
setFilterRecipient(String filterRecipient)1318     public void setFilterRecipient(String filterRecipient) {
1319         this.mFilterRecipient = filterRecipient;
1320     }
1321 
getFilterOriginator()1322     public String getFilterOriginator() {
1323         return mFilterOriginator;
1324     }
1325 
setFilterOriginator(String filterOriginator)1326     public void setFilterOriginator(String filterOriginator) {
1327         this.mFilterOriginator = filterOriginator;
1328     }
1329 
getFilterPriority()1330     public int getFilterPriority() {
1331         return mFilterPriority;
1332     }
1333 
setFilterPriority(int filterPriority)1334     public void setFilterPriority(int filterPriority) throws IllegalArgumentException {
1335         if (filterPriority < 0 || filterPriority > 0x0002) {
1336             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
1337         }
1338         this.mFilterPriority = filterPriority;
1339     }
1340 
setDatabaseIdentifier(long idHigh, long idLow)1341     public void setDatabaseIdentifier(long idHigh, long idLow) {
1342         this.mDatabaseIdentifierHigh = idHigh;
1343         this.mDatabaseIdentifierLow = idLow;
1344     }
1345 
getDatabaseIdentifier()1346     public byte[] getDatabaseIdentifier() {
1347         if (mDatabaseIdentifierLow != INVALID_VALUE_PARAMETER
1348                 && mDatabaseIdentifierHigh != INVALID_VALUE_PARAMETER) {
1349             ByteBuffer ret = ByteBuffer.allocate(16);
1350             ret.putLong(mDatabaseIdentifierHigh);
1351             ret.putLong(mDatabaseIdentifierLow);
1352             return ret.array();
1353         } else {
1354             return null;
1355         }
1356     }
1357 
setConvoListingVerCounter(long countLow, long countHigh)1358     public void setConvoListingVerCounter(long countLow, long countHigh) {
1359         this.mConvoListingVerCounterHigh = countHigh;
1360         this.mConvoListingVerCounterLow = countLow;
1361     }
1362 
getConvoListingVerCounter()1363     public byte[] getConvoListingVerCounter() {
1364         if (mConvoListingVerCounterHigh != INVALID_VALUE_PARAMETER
1365                 && mConvoListingVerCounterLow != INVALID_VALUE_PARAMETER) {
1366             ByteBuffer ret = ByteBuffer.allocate(16);
1367             ret.putLong(mConvoListingVerCounterHigh);
1368             ret.putLong(mConvoListingVerCounterLow);
1369             return ret.array();
1370         } else {
1371             return null;
1372         }
1373     }
1374 
setFolderVerCounter(long countLow, long countHigh)1375     public void setFolderVerCounter(long countLow, long countHigh) {
1376         this.mFolderVerCounterHigh = countHigh;
1377         this.mFolderVerCounterLow = countLow;
1378     }
1379 
getFolderVerCounter()1380     public byte[] getFolderVerCounter() {
1381         if (mFolderVerCounterHigh != INVALID_VALUE_PARAMETER
1382                 && mFolderVerCounterLow != INVALID_VALUE_PARAMETER) {
1383             ByteBuffer ret = ByteBuffer.allocate(16);
1384             ret.putLong(mFolderVerCounterHigh);
1385             ret.putLong(mFolderVerCounterLow);
1386             return ret.array();
1387         } else {
1388             return null;
1389         }
1390     }
1391 
getChatStateConvoId()1392     public SignedLongLong getChatStateConvoId() {
1393         return mChatStateConvoId;
1394     }
1395 
getChatStateConvoIdByteArray()1396     public byte[] getChatStateConvoIdByteArray() {
1397         if (mChatStateConvoId != null) {
1398             ByteBuffer ret = ByteBuffer.allocate(16);
1399             ret.putLong(mChatStateConvoId.getMostSignificantBits());
1400             ret.putLong(mChatStateConvoId.getLeastSignificantBits());
1401             return ret.array();
1402         } else {
1403             return null;
1404         }
1405     }
1406 
getChatStateConvoIdString()1407     public String getChatStateConvoIdString() {
1408         return new String(this.getChatStateConvoIdByteArray());
1409     }
1410 
setChatStateConvoId(long idHigh, long idLow)1411     public void setChatStateConvoId(long idHigh, long idLow) {
1412         mChatStateConvoId = new SignedLongLong(idLow, idHigh);
1413     }
1414 
setFilterMsgHandle(String handle)1415     public void setFilterMsgHandle(String handle) {
1416         try {
1417             mFilterMsgHandle = BluetoothMapUtils.getLongFromString(handle);
1418         } catch (UnsupportedEncodingException | NumberFormatException e) {
1419             ContentProfileErrorReportUtils.report(
1420                     BluetoothProfile.MAP,
1421                     BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS,
1422                     BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION,
1423                     39);
1424             Log.w(TAG, "Error creating long from handle string", e);
1425         }
1426     }
1427 
getFilterMsgHandle()1428     public long getFilterMsgHandle() {
1429         return mFilterMsgHandle;
1430     }
1431 
getFilterMsgHandleString()1432     public String getFilterMsgHandleString() {
1433         String str = null;
1434         if (mFilterMsgHandle != INVALID_VALUE_PARAMETER) {
1435             str = BluetoothMapUtils.getLongAsString(mFilterMsgHandle);
1436         }
1437         return str;
1438     }
1439 
getFilterUidPresent()1440     public int getFilterUidPresent() {
1441         return mFilterUidPresent;
1442     }
1443 
setFilterUidPresent(int present)1444     public void setFilterUidPresent(int present) {
1445         if (present < 0 || present > 0x00FF) {
1446             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1447         }
1448         this.mFilterUidPresent = present;
1449     }
1450 
getFilterPresence()1451     public int getFilterPresence() {
1452         return mFilterPresence;
1453     }
1454 
getFilterConvoId()1455     public SignedLongLong getFilterConvoId() {
1456         return mFilterConvoId;
1457     }
1458 
1459     /**
1460      * Get a decimal representation of the lower bits of the ConvoId - used for queries. The upper
1461      * bits are used for convo-type.
1462      *
1463      * @return decimal representation of the convo ID.
1464      */
getFilterConvoIdString()1465     public String getFilterConvoIdString() {
1466         String str = null;
1467         if (mFilterConvoId != null) {
1468             str = BluetoothMapUtils.getLongAsString(mFilterConvoId.getLeastSignificantBits());
1469         }
1470         return str;
1471     }
1472 
setFilterConvoId(String id)1473     public void setFilterConvoId(String id) {
1474         try {
1475             mFilterConvoId = SignedLongLong.fromString(id);
1476         } catch (UnsupportedEncodingException | NumberFormatException e) {
1477             ContentProfileErrorReportUtils.report(
1478                     BluetoothProfile.MAP,
1479                     BluetoothProtoEnums.BLUETOOTH_MAP_APP_PARAMS,
1480                     BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION,
1481                     40);
1482             Log.w(TAG, "Error creating long from id string", e);
1483         }
1484     }
1485 
setChatState(int state)1486     public void setChatState(int state) {
1487         if (state < 0 || state > 0x00FF) {
1488             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1489         }
1490         this.mChatState = state;
1491     }
1492 
getChatState()1493     public int getChatState() {
1494         return mChatState;
1495     }
1496 
getLastActivity()1497     public long getLastActivity() {
1498         return this.mLastActivity;
1499     }
1500 
getLastActivityString()1501     public String getLastActivityString() {
1502         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
1503         Date date = new Date(mLastActivity);
1504         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
1505     }
1506 
setLastActivity(long last)1507     public void setLastActivity(long last) {
1508         this.mLastActivity = last;
1509     }
1510 
setLastActivity(String lastActivity)1511     public void setLastActivity(String lastActivity) throws ParseException {
1512         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
1513         Date date = format.parse(lastActivity);
1514         this.mLastActivity = date.getTime();
1515     }
1516 
setPresenceStatus(String status)1517     public void setPresenceStatus(String status) {
1518         this.mPresenceStatus = status;
1519     }
1520 
getPresenceStatus()1521     public String getPresenceStatus() {
1522         return this.mPresenceStatus;
1523     }
1524 
setFilterPresence(int presence)1525     public void setFilterPresence(int presence) {
1526         if (presence < 0 || presence > 0xFFFF) {
1527             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
1528         }
1529         this.mFilterPresence = presence;
1530     }
1531 
setPresenceAvailability(int availability)1532     public void setPresenceAvailability(int availability) {
1533         if (availability < 0 || availability > 0x00FF) {
1534             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1535         }
1536         this.mPresenceAvailability = availability;
1537     }
1538 
getPresenceAvailability()1539     public int getPresenceAvailability() {
1540         return mPresenceAvailability;
1541     }
1542 
getSubjectLength()1543     public int getSubjectLength() {
1544         return mSubjectLength;
1545     }
1546 
getAttachment()1547     public int getAttachment() {
1548         return mAttachment;
1549     }
1550 
setAttachment(int attachment)1551     public void setAttachment(int attachment) throws IllegalArgumentException {
1552         if (attachment < 0 || attachment > 0x0001) {
1553             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1554         }
1555         this.mAttachment = attachment;
1556     }
1557 
getTransparent()1558     public int getTransparent() {
1559         return mTransparent;
1560     }
1561 
setTransparent(int transparent)1562     public void setTransparent(int transparent) throws IllegalArgumentException {
1563         if (transparent < 0 || transparent > 0x0001) {
1564             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1565         }
1566         this.mTransparent = transparent;
1567     }
1568 
getRetry()1569     public int getRetry() {
1570         return mRetry;
1571     }
1572 
setRetry(int retry)1573     public void setRetry(int retry) throws IllegalArgumentException {
1574         if (retry < 0 || retry > 0x0001) {
1575             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1576         }
1577         this.mRetry = retry;
1578     }
1579 
getNewMessage()1580     public int getNewMessage() {
1581         return mNewMessage;
1582     }
1583 
setNewMessage(int newMessage)1584     public void setNewMessage(int newMessage) throws IllegalArgumentException {
1585         if (newMessage < 0 || newMessage > 0x0001) {
1586             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1587         }
1588         this.mNewMessage = newMessage;
1589     }
1590 
getNotificationStatus()1591     public int getNotificationStatus() {
1592         return mNotificationStatus;
1593     }
1594 
setNotificationStatus(int notificationStatus)1595     public void setNotificationStatus(int notificationStatus) throws IllegalArgumentException {
1596         if (notificationStatus < 0 || notificationStatus > 0x0001) {
1597             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1598         }
1599         this.mNotificationStatus = notificationStatus;
1600     }
1601 
getNotificationFilter()1602     public long getNotificationFilter() {
1603         return mNotificationFilter;
1604     }
1605 
setNotificationFilter(long notificationFilter)1606     public void setNotificationFilter(long notificationFilter) throws IllegalArgumentException {
1607         if (notificationFilter < 0 || notificationFilter > 0xFFFFFFFFL) {
1608             throw new IllegalArgumentException(
1609                     "Out of range, valid range is 0x0000 to 0xFFFFFFFFL");
1610         }
1611         this.mNotificationFilter = notificationFilter;
1612     }
1613 
getMasInstanceId()1614     public int getMasInstanceId() {
1615         return mMasInstanceId;
1616     }
1617 
setMasInstanceId(int masInstanceId)1618     public void setMasInstanceId(int masInstanceId) {
1619         if (masInstanceId < 0 || masInstanceId > 0x00FF) {
1620             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1621         }
1622         this.mMasInstanceId = masInstanceId;
1623     }
1624 
getParameterMask()1625     public long getParameterMask() {
1626         return mParameterMask;
1627     }
1628 
setParameterMask(long parameterMask)1629     public void setParameterMask(long parameterMask) {
1630         if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL) {
1631             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF");
1632         }
1633         this.mParameterMask = parameterMask;
1634     }
1635 
setConvoParameterMask(long parameterMask)1636     public void setConvoParameterMask(long parameterMask) {
1637         if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL) {
1638             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF");
1639         }
1640         this.mConvoParameterMask = parameterMask;
1641     }
1642 
getConvoParameterMask()1643     public long getConvoParameterMask() {
1644         return mConvoParameterMask;
1645     }
1646 
getFolderListingSize()1647     public int getFolderListingSize() {
1648         return mFolderListingSize;
1649     }
1650 
setFolderListingSize(int folderListingSize)1651     public void setFolderListingSize(int folderListingSize) {
1652         if (folderListingSize < 0 || folderListingSize > 0xFFFF) {
1653             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
1654         }
1655         this.mFolderListingSize = folderListingSize;
1656     }
1657 
getMessageListingSize()1658     public int getMessageListingSize() {
1659         return mMessageListingSize;
1660     }
1661 
setMessageListingSize(int messageListingSize)1662     public void setMessageListingSize(int messageListingSize) {
1663         if (messageListingSize < 0 || messageListingSize > 0xFFFF) {
1664             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
1665         }
1666         this.mMessageListingSize = messageListingSize;
1667     }
1668 
getConvoListingSize()1669     public int getConvoListingSize() {
1670         return mConvoListingSize;
1671     }
1672 
setConvoListingSize(int convoListingSize)1673     public void setConvoListingSize(int convoListingSize) {
1674         if (convoListingSize < 0 || convoListingSize > 0xFFFF) {
1675             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
1676         }
1677         this.mConvoListingSize = convoListingSize;
1678     }
1679 
setSubjectLength(int subjectLength)1680     public void setSubjectLength(int subjectLength) {
1681         if (subjectLength < 0 || subjectLength > 0xFF) {
1682             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1683         }
1684         this.mSubjectLength = subjectLength;
1685     }
1686 
getCharset()1687     public int getCharset() {
1688         return mCharset;
1689     }
1690 
setCharset(int charset)1691     public void setCharset(int charset) {
1692         if (charset < 0 || charset > 0x1) {
1693             throw new IllegalArgumentException(
1694                     "Out of range: " + charset + ", valid range is 0x0000 to 0x0001");
1695         }
1696         this.mCharset = charset;
1697     }
1698 
getFractionRequest()1699     public int getFractionRequest() {
1700         return mFractionRequest;
1701     }
1702 
setFractionRequest(int fractionRequest)1703     public void setFractionRequest(int fractionRequest) {
1704         if (fractionRequest < 0 || fractionRequest > 0x1) {
1705             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1706         }
1707         this.mFractionRequest = fractionRequest;
1708     }
1709 
getFractionDeliver()1710     public int getFractionDeliver() {
1711         return mFractionDeliver;
1712     }
1713 
setFractionDeliver(int fractionDeliver)1714     public void setFractionDeliver(int fractionDeliver) {
1715         if (fractionDeliver < 0 || fractionDeliver > 0x1) {
1716             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1717         }
1718         this.mFractionDeliver = fractionDeliver;
1719     }
1720 
getStatusIndicator()1721     public int getStatusIndicator() {
1722         return mStatusIndicator;
1723     }
1724 
setStatusIndicator(int statusIndicator)1725     public void setStatusIndicator(int statusIndicator) {
1726         if (statusIndicator < 0 || statusIndicator > 0x1) {
1727             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1728         }
1729         this.mStatusIndicator = statusIndicator;
1730     }
1731 
getStatusValue()1732     public int getStatusValue() {
1733         return mStatusValue;
1734     }
1735 
setStatusValue(int statusValue)1736     public void setStatusValue(int statusValue) {
1737         if (statusValue < 0 || statusValue > 0x1) {
1738             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1739         }
1740         this.mStatusValue = statusValue;
1741     }
1742 
getMseTime()1743     public long getMseTime() {
1744         return mMseTime;
1745     }
1746 
getMseTimeString()1747     public String getMseTimeString() {
1748         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
1749         Date date = new Date(getMseTime());
1750         return format.format(date); // Format to YYYYMMDDTHHMMSS±hhmm UTC time ± offset
1751     }
1752 
setMseTime(long mseTime)1753     public void setMseTime(long mseTime) {
1754         this.mMseTime = mseTime;
1755     }
1756 
setMseTime(String mseTime)1757     public void setMseTime(String mseTime) throws ParseException {
1758         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
1759         Date date = format.parse(mseTime);
1760         this.mMseTime = date.getTime();
1761     }
1762 }
1763