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 java.io.UnsupportedEncodingException;
18 import java.nio.ByteBuffer;
19 import java.nio.ByteOrder;
20 import java.text.ParseException;
21 import java.text.SimpleDateFormat;
22 import java.util.Arrays;
23 import java.util.Date;
24 import java.util.UUID;
25 
26 import android.util.Log;
27 
28 import com.android.bluetooth.SignedLongLong;
29 
30 /**
31  * This class encapsulates the appParams needed for MAP.
32  */
33 public class BluetoothMapAppParams {
34 
35     private static final String TAG = "BluetoothMapAppParams";
36 
37     private static final int MAX_LIST_COUNT           = 0x01;
38     private static final int START_OFFSET             = 0x02;
39     private static final int FILTER_MESSAGE_TYPE      = 0x03;
40     private static final int FILTER_PERIOD_BEGIN      = 0x04;
41     private static final int FILTER_PERIOD_END        = 0x05;
42     private static final int FILTER_READ_STATUS       = 0x06;
43     private static final int FILTER_RECIPIENT         = 0x07;
44     private static final int FILTER_ORIGINATOR        = 0x08;
45     private static final int FILTER_PRIORITY          = 0x09;
46     private static final int ATTACHMENT               = 0x0A;
47     private static final int TRANSPARENT              = 0x0B;
48     private static final int RETRY                    = 0x0C;
49     private static final int NEW_MESSAGE              = 0x0D;
50     private static final int NOTIFICATION_STATUS      = 0x0E;
51     private static final int MAS_INSTANCE_ID          = 0x0F;
52     private static final int PARAMETER_MASK           = 0x10;
53     private static final int FOLDER_LISTING_SIZE      = 0x11;
54     private static final int MESSAGE_LISTING_SIZE     = 0x12;
55     private static final int SUBJECT_LENGTH           = 0x13;
56     private static final int CHARSET                  = 0x14;
57     private static final int FRACTION_REQUEST         = 0x15;
58     private static final int FRACTION_DELIVER         = 0x16;
59     private static final int STATUS_INDICATOR         = 0x17;
60     private static final int STATUS_VALUE             = 0x18;
61     private static final int MSE_TIME                 = 0x19;
62     private static final int DATABASE_INDETIFIER      = 0x1A;
63     private static final int CONVO_LIST_VER_COUNTER   = 0x1B;
64     private static final int PRESENCE_AVAILABLE       = 0x1C;
65     private static final int PRESENCE_TEXT            = 0x1D;
66     private static final int LAST_ACTIVITY            = 0x1E;
67     private static final int CHAT_STATE               = 0x1F;
68     private static final int FILTER_CONVO_ID          = 0x20;
69     private static final int CONVO_LISTING_SIZE       = 0x21;
70     private static final int FILTER_PRESENCE          = 0x22;
71     private static final int FILTER_UID_PRESENT       = 0x23;
72     private static final int CHAT_STATE_CONVO_ID      = 0x24;
73     private static final int FOLDER_VER_COUNTER       = 0x25;
74     private static final int FILTER_MESSAGE_HANDLE    = 0x26;
75     private static final int NOTIFICATION_FILTER      = 0x27;
76     private static final int CONVO_PARAMETER_MASK     = 0x28;
77 
78     // Length defined for Application Parameters
79     private static final int MAX_LIST_COUNT_LEN       = 0x02; //, 0x0000, 0xFFFF),
80     private static final int START_OFFSET_LEN         = 0x02; //, 0x0000, 0xFFFF),
81     private static final int FILTER_MESSAGE_TYPE_LEN  = 0x01; //, 0x0000, 0x000f),
82     private static final int FILTER_READ_STATUS_LEN   = 0x01; //, 0x0000, 0x0002),
83     private static final int FILTER_PRIORITY_LEN      = 0x01; //, 0x0000, 0x0002),
84     private static final int ATTACHMENT_LEN           = 0x01; //, 0x0000, 0x0001),
85     private static final int TRANSPARENT_LEN          = 0x01; //, 0x0000, 0x0001),
86     private static final int RETRY_LEN                = 0x01; //, 0x0000, 0x0001),
87     private static final int NEW_MESSAGE_LEN          = 0x01; //, 0x0000, 0x0001),
88     private static final int NOTIFICATION_STATUS_LEN  = 0x01; //, 0x0000, 0xFFFF),
89     private static final int MAS_INSTANCE_ID_LEN      = 0x01; //, 0x0000, 0x00FF),
90     private static final int PARAMETER_MASK_LEN       = 0x04; //, 0x0000, 0x0000),
91     private static final int FOLDER_LISTING_SIZE_LEN  = 0x02; //, 0x0000, 0xFFFF),
92     private static final int MESSAGE_LISTING_SIZE_LEN = 0x02; //, 0x0000, 0xFFFF),
93     private static final int SUBJECT_LENGTH_LEN       = 0x01; //, 0x0000, 0x00FF),
94     private static final int CHARSET_LEN              = 0x01; //, 0x0000, 0x0001),
95     private static final int FRACTION_REQUEST_LEN     = 0x01; //, 0x0000, 0x0001),
96     private static final int FRACTION_DELIVER_LEN     = 0x01; //, 0x0000, 0x0001),
97     private static final int STATUS_INDICATOR_LEN     = 0x01; //, 0x0000, 0x0001),
98     private static final int STATUS_VALUE_LEN         = 0x01; //, 0x0000, 0x0001),
99     private static final int DATABASE_INDETIFIER_LEN  = 0x10;
100     private static final int CONVO_LIST_VER_COUNTER_LEN = 0x10;
101     private static final int PRESENCE_AVAILABLE_LEN   = 0X01;
102     private static final int CHAT_STATE_LEN           = 0x01;
103     private static final int CHAT_STATE_CONVO_ID_LEN  = 0x10;
104     private static final int FILTER_CONVO_ID_LEN      = 0x20;
105     private static final int CONVO_LISTING_SIZE_LEN   = 0x02;
106     private static final int FILTER_PRESENCE_LEN      = 0x01;
107     private static final int FILTER_UID_PRESENT_LEN   = 0x01;
108     private static final int FOLDER_VER_COUNTER_LEN   = 0x10;
109     private static final int FILTER_MESSAGE_HANDLE_LEN= 0x10;
110     private static final int NOTIFICATION_FILTER_LEN  = 0x04;
111     private static final int CONVO_PARAMETER_MASK_LEN = 0x04;
112 
113     // Default values
114     public static final int INVALID_VALUE_PARAMETER     =-1;
115     public static final int NOTIFICATION_STATUS_NO      = 0;
116     public static final int NOTIFICATION_STATUS_YES     = 1;
117     public static final int STATUS_INDICATOR_READ       = 0;
118     public static final int STATUS_INDICATOR_DELETED    = 1;
119     public static final int STATUS_VALUE_YES            = 1;
120     public static final int STATUS_VALUE_NO             = 0;
121     public static final int CHARSET_NATIVE              = 0;
122     public static final int CHARSET_UTF8                = 1;
123     public static final int FRACTION_REQUEST_FIRST      = 0;
124     public static final int FRACTION_REQUEST_NEXT       = 1;
125     public static final int FRACTION_DELIVER_MORE       = 0;
126     public static final int FRACTION_DELIVER_LAST       = 1;
127 
128     public static final int FILTER_NO_SMS_GSM    = 0x01;
129     public static final int FILTER_NO_SMS_CDMA   = 0x02;
130     public static final int FILTER_NO_EMAIL      = 0x04;
131     public static final int FILTER_NO_MMS        = 0x08;
132     public static final int FILTER_NO_IM         = 0x10;
133     public static final int FILTER_MSG_TYPE_MASK = 0x1F;
134 
135     private int mMaxListCount                   = INVALID_VALUE_PARAMETER;
136     private int mStartOffset                    = INVALID_VALUE_PARAMETER;
137     private int mFilterMessageType              = INVALID_VALUE_PARAMETER;
138     // It seems like these are not implemented...
139     private long mFilterPeriodBegin             = INVALID_VALUE_PARAMETER;
140     private long mFilterPeriodEnd               = INVALID_VALUE_PARAMETER;
141     private int mFilterReadStatus               = INVALID_VALUE_PARAMETER;
142     private String mFilterRecipient             = null;
143     private String mFilterOriginator            = null;
144     private int mFilterPriority                 = INVALID_VALUE_PARAMETER;
145     private int mAttachment                     = INVALID_VALUE_PARAMETER;
146     private int mTransparent                    = INVALID_VALUE_PARAMETER;
147     private int mRetry                          = INVALID_VALUE_PARAMETER;
148     private int mNewMessage                     = INVALID_VALUE_PARAMETER;
149     private int mNotificationStatus             = INVALID_VALUE_PARAMETER;
150     private long mNotificationFilter            = INVALID_VALUE_PARAMETER;
151     private int mMasInstanceId                  = INVALID_VALUE_PARAMETER;
152     private long mParameterMask                 = INVALID_VALUE_PARAMETER;
153     private int mFolderListingSize              = INVALID_VALUE_PARAMETER;
154     private int mMessageListingSize             = INVALID_VALUE_PARAMETER;
155     private int mConvoListingSize               = INVALID_VALUE_PARAMETER;
156     private int mSubjectLength                  = INVALID_VALUE_PARAMETER;
157     private int mCharset                        = INVALID_VALUE_PARAMETER;
158     private int mFractionRequest                = INVALID_VALUE_PARAMETER;
159     private int mFractionDeliver                = INVALID_VALUE_PARAMETER;
160     private int mStatusIndicator                = INVALID_VALUE_PARAMETER;
161     private int mStatusValue                    = INVALID_VALUE_PARAMETER;
162     private long mMseTime                       = INVALID_VALUE_PARAMETER;
163     // TODO: Change to use SignedLongLong?
164     private long mConvoListingVerCounterLow     = INVALID_VALUE_PARAMETER;
165     private long mConvoListingVerCounterHigh    = INVALID_VALUE_PARAMETER;
166     private long mDatabaseIdentifierLow         = INVALID_VALUE_PARAMETER;
167     private long mDatabaseIdentifierHigh        = INVALID_VALUE_PARAMETER;
168     private long mFolderVerCounterLow           = INVALID_VALUE_PARAMETER;
169     private long mFolderVerCounterHigh          = INVALID_VALUE_PARAMETER;
170     private int mPresenceAvailability           = INVALID_VALUE_PARAMETER;
171     private String mPresenceStatus              = null;
172     private long mLastActivity                  = INVALID_VALUE_PARAMETER;
173     private int mChatState                      = INVALID_VALUE_PARAMETER;
174     private SignedLongLong mFilterConvoId       = null;
175     private int mFilterPresence                 = INVALID_VALUE_PARAMETER;
176     private int mFilterUidPresent               = INVALID_VALUE_PARAMETER;
177     private SignedLongLong mChatStateConvoId    = null;
178     private long mFilterMsgHandle               = INVALID_VALUE_PARAMETER;
179     private long mConvoParameterMask            = INVALID_VALUE_PARAMETER;
180 
181     /**
182      * Default constructor, used to build an application parameter object to be
183      * encoded. By default the member variables will be initialized to
184      * {@link INVALID_VALUE_PARAMETER} for values, and empty strings for String
185      * typed members.
186      */
BluetoothMapAppParams()187     public BluetoothMapAppParams() {
188     }
189 
190     /**
191      * Creates an application parameter object based on a application parameter
192      * OBEX header. The content of the {@link appParam} byte array will be
193      * parsed, and its content will be stored in the member variables.
194      * {@link INVALID_VALUE_PARAMETER} can be used to determine if a value is
195      * set or not, where strings will be empty, if {@link appParam} did not
196      * contain the parameter.
197      *
198      * @param appParams
199      *            the byte array containing the application parameters OBEX
200      *            header
201      * @throws IllegalArgumentException
202      *             when a parameter does not respect the valid ranges specified
203      *             in the MAP spec.
204      * @throws ParseException
205      *             if a parameter string if formated incorrectly.
206      */
BluetoothMapAppParams(final byte[] appParams)207     public BluetoothMapAppParams(final byte[] appParams)
208                  throws IllegalArgumentException, ParseException {
209         ParseParams(appParams);
210     }
211 
212     /**
213      * Parse an application parameter OBEX header stored in a byte array.
214      *
215      * @param appParams
216      *            the byte array containing the application parameters OBEX
217      *            header
218      * @throws IllegalArgumentException
219      *             when a parameter does not respect the valid ranges specified
220      *             in the MAP spec.
221      * @throws ParseException
222      *             if a parameter string if formated incorrectly.
223      */
ParseParams(final byte[] appParams)224     private void ParseParams(final byte[] appParams) throws ParseException,
225               IllegalArgumentException {
226         int i = 0;
227         int tagId, tagLength;
228         ByteBuffer appParamBuf = ByteBuffer.wrap(appParams);
229         appParamBuf.order(ByteOrder.BIG_ENDIAN);
230         while (i < appParams.length) {
231             tagId = appParams[i++] & 0xff;     // Convert to unsigned to support values above 127
232             tagLength = appParams[i++] & 0xff; // Convert to unsigned to support values above 127
233             switch (tagId) {
234             case MAX_LIST_COUNT:
235                 if (tagLength != MAX_LIST_COUNT_LEN) {
236                     Log.w(TAG, "MAX_LIST_COUNT: Wrong length received: " + tagLength
237                                + " expected: " + MAX_LIST_COUNT_LEN);
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(TAG, "START_OFFSET: Wrong length received: " + tagLength + " expected: "
245                                + START_OFFSET_LEN);
246                 } else {
247                     setStartOffset(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
248                 }
249                 break;
250             case FILTER_MESSAGE_TYPE:
251                 if (tagLength != FILTER_MESSAGE_TYPE_LEN) {
252                     Log.w(TAG, "FILTER_MESSAGE_TYPE: Wrong length received: " + tagLength
253                             + " expected: " + FILTER_MESSAGE_TYPE_LEN);
254                 } else {
255                     setFilterMessageType(appParams[i] & 0x1f);
256                 }
257                 break;
258             case FILTER_PERIOD_BEGIN:
259                 if(tagLength != 0) {
260                     setFilterPeriodBegin(new String(appParams, i, tagLength));
261                 } else {
262                     Log.w(TAG, "FILTER_PERIOD_BEGIN: Wrong length received: " + tagLength +
263                             " expected to be more than 0");
264                 }
265                 break;
266             case FILTER_PERIOD_END:
267                 if(tagLength != 0) {
268                     setFilterPeriodEnd(new String(appParams, i, tagLength));
269                 } else {
270                     Log.w(TAG, "FILTER_PERIOD_END: Wrong length received: " + tagLength +
271                             " expected to be more than 0");
272                 }
273                 break;
274             case FILTER_READ_STATUS:
275                 if (tagLength != FILTER_READ_STATUS_LEN) {
276                      Log.w(TAG, "FILTER_READ_STATUS: Wrong length received: " + tagLength +
277                              " expected: " + FILTER_READ_STATUS_LEN);
278                 } else {
279                     setFilterReadStatus(appParams[i] & 0x03); // Lower two bits
280                 }
281                 break;
282             case FILTER_RECIPIENT:
283                 if(tagLength != 0) {
284                     setFilterRecipient(new String(appParams, i, tagLength));
285                 } else {
286                     Log.w(TAG, "FILTER_RECIPIENT: Wrong length received: " + tagLength +
287                             " expected to be more than 0");
288                 }
289                 break;
290             case FILTER_ORIGINATOR:
291                 if(tagLength != 0) {
292                     setFilterOriginator(new String(appParams, i, tagLength));
293                 } else {
294                     Log.w(TAG, "FILTER_ORIGINATOR: Wrong length received: " + tagLength +
295                             " expected to be more than 0");
296                 }
297                 break;
298             case FILTER_PRIORITY:
299                 if (tagLength != FILTER_PRIORITY_LEN) {
300                      Log.w(TAG, "FILTER_PRIORITY: Wrong length received: " + tagLength +
301                              " expected: " + FILTER_PRIORITY_LEN);
302                 } else {
303                     setFilterPriority(appParams[i] & 0x03); // Lower two bits
304                 }
305                 break;
306             case ATTACHMENT:
307                 if (tagLength != ATTACHMENT_LEN) {
308                      Log.w(TAG, "ATTACHMENT: Wrong length received: " + tagLength + " expected: "
309                              + ATTACHMENT_LEN);
310                 } else {
311                     setAttachment(appParams[i] & 0x01); // Lower bit
312                 }
313                 break;
314             case TRANSPARENT:
315                 if (tagLength != TRANSPARENT_LEN) {
316                      Log.w(TAG, "TRANSPARENT: Wrong length received: " + tagLength + " expected: "
317                              + TRANSPARENT_LEN);
318                 } else {
319                     setTransparent(appParams[i] & 0x01); // Lower bit
320                 }
321                 break;
322             case RETRY:
323                 if (tagLength != RETRY_LEN) {
324                      Log.w(TAG, "RETRY: Wrong length received: " + tagLength + " expected: "
325                              + RETRY_LEN);
326                 } else {
327                     setRetry(appParams[i] & 0x01); // Lower bit
328                 }
329                 break;
330             case NEW_MESSAGE:
331                 if (tagLength != NEW_MESSAGE_LEN) {
332                      Log.w(TAG, "NEW_MESSAGE: Wrong length received: " + tagLength + " expected: "
333                              + NEW_MESSAGE_LEN);
334                 } else {
335                     setNewMessage(appParams[i] & 0x01); // Lower bit
336                 }
337                 break;
338             case NOTIFICATION_STATUS:
339                 if (tagLength != NOTIFICATION_STATUS_LEN) {
340                      Log.w(TAG, "NOTIFICATION_STATUS: Wrong length received: " + tagLength +
341                              " expected: " + NOTIFICATION_STATUS_LEN);
342                 } else {
343                     setNotificationStatus(appParams[i] & 0x01); // Lower bit
344                 }
345                 break;
346             case NOTIFICATION_FILTER:
347                 if (tagLength != NOTIFICATION_FILTER_LEN) {
348                      Log.w(TAG, "NOTIFICATION_FILTER: Wrong length received: " + tagLength +
349                              " expected: " + NOTIFICATION_FILTER_LEN);
350                 } else {
351                     setNotificationFilter(appParamBuf.getInt(i) & 0xffffffffL); // 4 bytes
352                 }
353                 break;
354             case MAS_INSTANCE_ID:
355                 if (tagLength != MAS_INSTANCE_ID_LEN) {
356                     Log.w(TAG, "MAS_INSTANCE_ID: Wrong length received: " + tagLength +
357                             " expected: " + MAS_INSTANCE_ID_LEN);
358                 } else {
359                     setMasInstanceId(appParams[i] & 0xff);
360                 }
361                 break;
362             case PARAMETER_MASK:
363                 if (tagLength != PARAMETER_MASK_LEN) {
364                     Log.w(TAG, "PARAMETER_MASK: Wrong length received: " + tagLength +
365                             " expected: " + PARAMETER_MASK_LEN);
366                 } else {
367                     setParameterMask(appParamBuf.getInt(i) & 0xffffffffL); // Make it unsigned
368                 }
369                 break;
370             case FOLDER_LISTING_SIZE:
371                 if (tagLength != FOLDER_LISTING_SIZE_LEN) {
372                     Log.w(TAG, "FOLDER_LISTING_SIZE: Wrong length received: " + tagLength +
373                             " expected: " + FOLDER_LISTING_SIZE_LEN);
374                 } else {
375                     setFolderListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
376                 }
377                 break;
378             case MESSAGE_LISTING_SIZE:
379                 if (tagLength != MESSAGE_LISTING_SIZE_LEN) {
380                     Log.w(TAG, "MESSAGE_LISTING_SIZE: Wrong length received: " + tagLength +
381                             " expected: " + MESSAGE_LISTING_SIZE_LEN);
382                 } else {
383                     setMessageListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
384                 }
385                 break;
386             case SUBJECT_LENGTH:
387                 if (tagLength != SUBJECT_LENGTH_LEN) {
388                     Log.w(TAG, "SUBJECT_LENGTH: Wrong length received: " + tagLength +
389                             " expected: " + SUBJECT_LENGTH_LEN);
390                 } else {
391                     setSubjectLength(appParams[i] & 0xff);
392                 }
393                 break;
394             case CHARSET:
395                 if (tagLength != CHARSET_LEN) {
396                     Log.w(TAG, "CHARSET: Wrong length received: " + tagLength + " expected: "
397                             + CHARSET_LEN);
398                 } else {
399                     setCharset(appParams[i] & 0x01); // Lower bit
400                 }
401                 break;
402             case FRACTION_REQUEST:
403                 if (tagLength != FRACTION_REQUEST_LEN) {
404                     Log.w(TAG, "FRACTION_REQUEST: Wrong length received: " + tagLength +
405                             " expected: " + FRACTION_REQUEST_LEN);
406                 } else {
407                     setFractionRequest(appParams[i] & 0x01); // Lower bit
408                 }
409                 break;
410             case FRACTION_DELIVER:
411                 if (tagLength != FRACTION_DELIVER_LEN) {
412                     Log.w(TAG, "FRACTION_DELIVER: Wrong length received: " + tagLength +
413                             " expected: " + FRACTION_DELIVER_LEN);
414                 } else {
415                     setFractionDeliver(appParams[i] & 0x01); // Lower bit
416                 }
417                 break;
418             case STATUS_INDICATOR:
419                 if (tagLength != STATUS_INDICATOR_LEN) {
420                     Log.w(TAG, "STATUS_INDICATOR: Wrong length received: " + tagLength +
421                             " expected: " + STATUS_INDICATOR_LEN);
422                 } else {
423                     setStatusIndicator(appParams[i] & 0x01); // Lower bit
424                 }
425                 break;
426             case STATUS_VALUE:
427                 if (tagLength != STATUS_VALUE_LEN) {
428                     Log.w(TAG, "STATUS_VALUER: Wrong length received: " + tagLength + " expected: "
429                             + STATUS_VALUE_LEN);
430                 } else {
431                     setStatusValue(appParams[i] & 0x01); // Lower bit
432                 }
433                 break;
434             case MSE_TIME:
435                 setMseTime(new String(appParams, i, tagLength));
436                 break;
437             case DATABASE_INDETIFIER:
438                 if((tagLength != DATABASE_INDETIFIER_LEN)){
439                     Log.w(TAG, "DATABASE_IDENTIFIER: Wrong length received: " + tagLength +
440                             " expected: " + DATABASE_INDETIFIER_LEN);
441                 } else {
442                     setDatabaseIdentifier(appParamBuf.getLong(i)/*MSB*/,
443                             appParamBuf.getLong(i+8)/*LSB*/);
444                 }
445                 break;
446             case CONVO_LIST_VER_COUNTER:
447                 if((tagLength != CONVO_LIST_VER_COUNTER_LEN)){
448                     Log.w(TAG, "CONVO_LIST_VER_COUNTER: Wrong length received: " + tagLength +
449                             " expected: "  + CONVO_LIST_VER_COUNTER_LEN);
450                 } else {
451                     setConvoListingVerCounter(appParamBuf.getLong(i)/*MSB*/,
452                             appParamBuf.getLong(i+8)/*LSB*/);
453                 }
454                 break;
455             case PRESENCE_AVAILABLE:
456                 if((tagLength != PRESENCE_AVAILABLE_LEN)){
457                     Log.w(TAG, "PRESENCE_AVAILABLE: Wrong length received: " + tagLength +
458                             " expected: "  + PRESENCE_AVAILABLE_LEN);
459                 } else {
460                     setPresenceAvailability(appParams[i]);
461                 }
462                 break;
463             case PRESENCE_TEXT:
464                 if(tagLength != 0) {
465                     setPresenceStatus(new String(appParams, i, tagLength));
466                 } else
467                     Log.w(TAG, "PRESENCE_STATUS: Wrong length received: " + tagLength +
468                             " expected to be more than 0");
469                 break;
470             case LAST_ACTIVITY:
471                 if(tagLength != 0) {
472                     setLastActivity(new String(appParams, i, tagLength));
473                 } else
474                     Log.w(TAG, "LAST_ACTIVITY: Wrong length received: " + tagLength +
475                             " expected to be more than 0");
476                 break;
477             case CHAT_STATE:
478                 if((tagLength != CHAT_STATE_LEN)){
479                     Log.w(TAG, "CHAT_STATE: Wrong length received: " + tagLength +
480                             " expected: "  + CHAT_STATE_LEN);
481                 } else {
482                     setChatState(appParams[i]);
483                 }
484                 break;
485             case FILTER_CONVO_ID:
486                 if((tagLength != 0) && (tagLength <= FILTER_CONVO_ID_LEN)){
487                     setFilterConvoId(new String(appParams, i, tagLength));
488                 } else {
489                     Log.w(TAG, "FILTER_CONVO_ID: Wrong length received: " + tagLength +
490                         " expected: "  + FILTER_CONVO_ID_LEN);
491                 }
492                 break;
493             case CONVO_LISTING_SIZE:
494                 if(tagLength != CONVO_LISTING_SIZE_LEN){
495                     Log.w(TAG, "LISTING_SIZE: Wrong length received: "+ tagLength+" expected: "+
496                             CONVO_LISTING_SIZE_LEN);
497 
498                 } else {
499                     setConvoListingSize(appParamBuf.getShort(i) & 0xffff);
500                 }
501                 break;
502             case FILTER_PRESENCE:
503                 if((tagLength != FILTER_PRESENCE_LEN)){
504                     Log.w(TAG, "FILTER_PRESENCE: Wrong length received: " + tagLength +
505                             " expected: "  + FILTER_PRESENCE_LEN);
506                 } else {
507                     setFilterPresence(appParams[i]);
508                 }
509                 break;
510             case FILTER_UID_PRESENT:
511                 if((tagLength != FILTER_UID_PRESENT_LEN)){
512                     Log.w(TAG, "FILTER_UID_PRESENT: Wrong length received: " + tagLength +
513                             " expected: "  + FILTER_UID_PRESENT_LEN);
514                 } else {
515                     setFilterUidPresent(appParams[i]&0x1);
516                 }
517                 break;
518             case CHAT_STATE_CONVO_ID:
519                 if((tagLength != CHAT_STATE_CONVO_ID_LEN)){
520                     Log.w(TAG, "CHAT_STATE_CONVO_ID: Wrong length received: " + tagLength +
521                             " expected: "  + CHAT_STATE_CONVO_ID_LEN);
522                 } else {
523                     /* TODO: Is this correct convoId handling? */
524                     setChatStateConvoId(appParamBuf.getLong(i)/*MSB*/,
525                                         appParamBuf.getLong(i+8)/*LSB*/);
526                     Log.d(TAG, "CHAT_STATE_CONVO_ID: convo id " +
527                         "MSB=" + BluetoothMapUtils.getLongAsString(appParamBuf.getLong(i)) +
528                         ", LSB(+8)=" + BluetoothMapUtils.getLongAsString(appParamBuf.getLong(i+8)));
529 
530                 }
531                 break;
532             case FOLDER_VER_COUNTER:
533                 break;
534             case FILTER_MESSAGE_HANDLE:
535                 if((tagLength != 0 && tagLength <= FILTER_MESSAGE_HANDLE_LEN)){
536                     setFilterMsgHandle(new String(appParams, i, tagLength));
537                 } else {
538                     Log.w(TAG, "FILTER_MESSAGE_HANDLE: Wrong length received: " + tagLength +
539                             " expected: "  + FILTER_MESSAGE_HANDLE_LEN);
540                 }
541 
542                 break;
543             case CONVO_PARAMETER_MASK:
544                 if (tagLength != CONVO_PARAMETER_MASK_LEN) {
545                     Log.w(TAG, "CONVO_PARAMETER_MASK: Wrong length received: " + tagLength +
546                             " expected: " + CONVO_PARAMETER_MASK_LEN);
547                 } else {
548                     setConvoParameterMask(appParamBuf.getInt(i) & 0xffffffffL); // Make it unsigned
549                 }
550                 break;
551             default:
552                 // Just skip unknown Tags, no need to report error
553                 Log.w(TAG, "Unknown TagId received ( 0x" + Integer.toString(tagId, 16)
554                            + "), skipping...");
555                 break;
556             }
557             i += tagLength; // Offset to next TagId
558         }
559     }
560 
561     /**
562      * Get the approximate length needed to store the appParameters in a byte
563      * array.
564      *
565      * @return the length in bytes
566      * @throws UnsupportedEncodingException
567      *             if the platform does not support UTF-8 encoding.
568      */
getParamMaxLength()569     private int getParamMaxLength() throws UnsupportedEncodingException {
570         int length = 0;
571         length += 38 * 2; // tagId + tagLength
572         length += 33+4*16; // fixed sizes TODO: Update when spec is ready
573         length += getFilterPeriodBegin() == INVALID_VALUE_PARAMETER ? 0 : 20;
574         length += getFilterPeriodEnd() == INVALID_VALUE_PARAMETER ? 0 : 20;
575         if (getFilterRecipient() != null)
576             length += getFilterRecipient().getBytes("UTF-8").length;
577         if (getFilterOriginator() != null)
578             length += getFilterOriginator().getBytes("UTF-8").length;
579         length += getMseTime() == INVALID_VALUE_PARAMETER ? 0 : 20;
580         if(getPresenceStatus() != null)
581             length += getPresenceStatus().getBytes("UTF-8").length;
582         length += (getLastActivity() == INVALID_VALUE_PARAMETER) ? 0 : 20;
583         return length;
584     }
585 
586     /**
587      * Encode the application parameter object to a byte array.
588      *
589      * @return a byte Array representation of the application parameter object.
590      * @throws UnsupportedEncodingException
591      *             if the platform does not support UTF-8 encoding.
592      */
EncodeParams()593     public byte[] EncodeParams() throws UnsupportedEncodingException {
594         ByteBuffer appParamBuf = ByteBuffer.allocate(getParamMaxLength());
595         appParamBuf.order(ByteOrder.BIG_ENDIAN);
596         byte[] retBuf;
597 
598         if (getMaxListCount() != INVALID_VALUE_PARAMETER) {
599             appParamBuf.put((byte) MAX_LIST_COUNT);
600             appParamBuf.put((byte) MAX_LIST_COUNT_LEN);
601             appParamBuf.putShort((short) getMaxListCount());
602         }
603         if (getStartOffset() != INVALID_VALUE_PARAMETER) {
604             appParamBuf.put((byte) START_OFFSET);
605             appParamBuf.put((byte) START_OFFSET_LEN);
606             appParamBuf.putShort((short) getStartOffset());
607         }
608         if (getFilterMessageType() != INVALID_VALUE_PARAMETER) {
609             appParamBuf.put((byte) FILTER_MESSAGE_TYPE);
610             appParamBuf.put((byte) FILTER_MESSAGE_TYPE_LEN);
611             appParamBuf.put((byte) getFilterMessageType());
612         }
613         if (getFilterPeriodBegin() != INVALID_VALUE_PARAMETER) {
614             appParamBuf.put((byte) FILTER_PERIOD_BEGIN);
615             appParamBuf.put((byte) getFilterPeriodBeginString().getBytes("UTF-8").length);
616             appParamBuf.put(getFilterPeriodBeginString().getBytes("UTF-8"));
617         }
618         if (getFilterPeriodEnd() != INVALID_VALUE_PARAMETER) {
619             appParamBuf.put((byte) FILTER_PERIOD_END);
620             appParamBuf.put((byte) getFilterPeriodEndString().getBytes("UTF-8").length);
621             appParamBuf.put(getFilterPeriodEndString().getBytes("UTF-8"));
622         }
623         if (getFilterReadStatus() != INVALID_VALUE_PARAMETER) {
624             appParamBuf.put((byte) FILTER_READ_STATUS);
625             appParamBuf.put((byte) FILTER_READ_STATUS_LEN);
626             appParamBuf.put((byte) getFilterReadStatus());
627         }
628         if (getFilterRecipient() != null) {
629             appParamBuf.put((byte) FILTER_RECIPIENT);
630             appParamBuf.put((byte) getFilterRecipient().getBytes("UTF-8").length);
631             appParamBuf.put(getFilterRecipient().getBytes("UTF-8"));
632         }
633         if (getFilterOriginator() != null) {
634             appParamBuf.put((byte) FILTER_ORIGINATOR);
635             appParamBuf.put((byte) getFilterOriginator().getBytes("UTF-8").length);
636             appParamBuf.put(getFilterOriginator().getBytes("UTF-8"));
637         }
638         if (getFilterPriority() != INVALID_VALUE_PARAMETER) {
639             appParamBuf.put((byte) FILTER_PRIORITY);
640             appParamBuf.put((byte) FILTER_PRIORITY_LEN);
641             appParamBuf.put((byte) getFilterPriority());
642         }
643         if (getAttachment() != INVALID_VALUE_PARAMETER) {
644             appParamBuf.put((byte) ATTACHMENT);
645             appParamBuf.put((byte) ATTACHMENT_LEN);
646             appParamBuf.put((byte) getAttachment());
647         }
648         if (getTransparent() != INVALID_VALUE_PARAMETER) {
649             appParamBuf.put((byte) TRANSPARENT);
650             appParamBuf.put((byte) TRANSPARENT_LEN);
651             appParamBuf.put((byte) getTransparent());
652         }
653         if (getRetry() != INVALID_VALUE_PARAMETER) {
654             appParamBuf.put((byte) RETRY);
655             appParamBuf.put((byte) RETRY_LEN);
656             appParamBuf.put((byte) getRetry());
657         }
658         if (getNewMessage() != INVALID_VALUE_PARAMETER) {
659             appParamBuf.put((byte) NEW_MESSAGE);
660             appParamBuf.put((byte) NEW_MESSAGE_LEN);
661             appParamBuf.put((byte) getNewMessage());
662         }
663         if (getNotificationStatus() != INVALID_VALUE_PARAMETER) {
664             appParamBuf.put((byte) NOTIFICATION_STATUS);
665             appParamBuf.put((byte) NOTIFICATION_STATUS_LEN);
666             appParamBuf.putShort((short) getNotificationStatus());
667         }
668         if (getNotificationFilter() != INVALID_VALUE_PARAMETER) {
669             appParamBuf.put((byte) NOTIFICATION_FILTER);
670             appParamBuf.put((byte) NOTIFICATION_FILTER_LEN);
671             appParamBuf.putInt((int) getNotificationFilter());
672         }
673         if (getMasInstanceId() != INVALID_VALUE_PARAMETER) {
674             appParamBuf.put((byte) MAS_INSTANCE_ID);
675             appParamBuf.put((byte) MAS_INSTANCE_ID_LEN);
676             appParamBuf.put((byte) getMasInstanceId());
677         }
678         if (getParameterMask() != INVALID_VALUE_PARAMETER) {
679             appParamBuf.put((byte) PARAMETER_MASK);
680             appParamBuf.put((byte) PARAMETER_MASK_LEN);
681             appParamBuf.putInt((int) getParameterMask());
682         }
683         if (getFolderListingSize() != INVALID_VALUE_PARAMETER) {
684             appParamBuf.put((byte) FOLDER_LISTING_SIZE);
685             appParamBuf.put((byte) FOLDER_LISTING_SIZE_LEN);
686             appParamBuf.putShort((short) getFolderListingSize());
687         }
688         if (getMessageListingSize() != INVALID_VALUE_PARAMETER) {
689             appParamBuf.put((byte) MESSAGE_LISTING_SIZE);
690             appParamBuf.put((byte) MESSAGE_LISTING_SIZE_LEN);
691             appParamBuf.putShort((short) getMessageListingSize());
692         }
693         if (getSubjectLength() != INVALID_VALUE_PARAMETER) {
694             appParamBuf.put((byte) SUBJECT_LENGTH);
695             appParamBuf.put((byte) SUBJECT_LENGTH_LEN);
696             appParamBuf.put((byte) getSubjectLength());
697         }
698         if (getCharset() != INVALID_VALUE_PARAMETER) {
699             appParamBuf.put((byte) CHARSET);
700             appParamBuf.put((byte) CHARSET_LEN);
701             appParamBuf.put((byte) getCharset());
702         }
703         if (getFractionRequest() != INVALID_VALUE_PARAMETER) {
704             appParamBuf.put((byte) FRACTION_REQUEST);
705             appParamBuf.put((byte) FRACTION_REQUEST_LEN);
706             appParamBuf.put((byte) getFractionRequest());
707         }
708         if (getFractionDeliver() != INVALID_VALUE_PARAMETER) {
709             appParamBuf.put((byte) FRACTION_DELIVER);
710             appParamBuf.put((byte) FRACTION_DELIVER_LEN);
711             appParamBuf.put((byte) getFractionDeliver());
712         }
713         if (getStatusIndicator() != INVALID_VALUE_PARAMETER) {
714             appParamBuf.put((byte) STATUS_INDICATOR);
715             appParamBuf.put((byte) STATUS_INDICATOR_LEN);
716             appParamBuf.put((byte) getStatusIndicator());
717         }
718         if (getStatusValue() != INVALID_VALUE_PARAMETER) {
719             appParamBuf.put((byte) STATUS_VALUE);
720             appParamBuf.put((byte) STATUS_VALUE_LEN);
721             appParamBuf.put((byte) getStatusValue());
722         }
723         if (getMseTime() != INVALID_VALUE_PARAMETER) {
724             appParamBuf.put((byte) MSE_TIME);
725             appParamBuf.put((byte) getMseTimeString().getBytes("UTF-8").length);
726             appParamBuf.put(getMseTimeString().getBytes("UTF-8"));
727         }
728         // Note: New for IM
729         if (getDatabaseIdentifier() != null) {
730             appParamBuf.put((byte)DATABASE_INDETIFIER);
731             appParamBuf.put((byte)DATABASE_INDETIFIER_LEN);
732             appParamBuf.put(getDatabaseIdentifier());
733         }
734         if (getConvoListingVerCounter() != null) {
735             appParamBuf.put((byte)CONVO_LIST_VER_COUNTER);
736             appParamBuf.put((byte)CONVO_LIST_VER_COUNTER_LEN);
737             appParamBuf.put(getConvoListingVerCounter());
738         }
739         if (getPresenceAvailability() != INVALID_VALUE_PARAMETER) {
740             appParamBuf.put((byte)PRESENCE_AVAILABLE);
741             appParamBuf.put((byte)PRESENCE_AVAILABLE_LEN);
742             appParamBuf.putInt((int)getPresenceAvailability());
743         }
744         if (getPresenceStatus()!= null) {
745             appParamBuf.put((byte)PRESENCE_TEXT);
746             appParamBuf.put((byte)getPresenceStatus().getBytes("UTF-8").length);
747             appParamBuf.put(getPresenceStatus().getBytes());
748         }
749         if (getLastActivity() != INVALID_VALUE_PARAMETER) {
750             appParamBuf.put((byte)LAST_ACTIVITY);
751             appParamBuf.put((byte)getLastActivityString().getBytes("UTF-8").length);
752             appParamBuf.put(getLastActivityString().getBytes());
753         }
754         if (getChatState() != INVALID_VALUE_PARAMETER) {
755             appParamBuf.put((byte)CHAT_STATE);
756             appParamBuf.put((byte)CHAT_STATE_LEN);
757             appParamBuf.putShort((short)getChatState());
758         }
759         if (getFilterConvoId() != null) {
760             appParamBuf.put((byte)FILTER_CONVO_ID);
761             appParamBuf.put((byte)FILTER_CONVO_ID_LEN);
762             appParamBuf.putLong(getFilterConvoId().getMostSignificantBits());
763             appParamBuf.putLong(getFilterConvoId().getLeastSignificantBits());
764         }
765         if (getConvoListingSize() != INVALID_VALUE_PARAMETER) {
766             appParamBuf.put((byte)CONVO_LISTING_SIZE);
767             appParamBuf.put((byte)CONVO_LISTING_SIZE_LEN);
768             appParamBuf.putShort((short)getConvoListingSize());
769         }
770         if (getFilterPresence() != INVALID_VALUE_PARAMETER) {
771             appParamBuf.put((byte)FILTER_PRESENCE);
772             appParamBuf.put((byte)FILTER_PRESENCE_LEN);
773             appParamBuf.putShort((short)getFilterPresence());
774         }
775         if (getFilterUidPresent() != INVALID_VALUE_PARAMETER) {
776             appParamBuf.put((byte)FILTER_UID_PRESENT);
777             appParamBuf.put((byte)FILTER_UID_PRESENT_LEN);
778             appParamBuf.putShort((short)getFilterUidPresent());
779         }
780         if (getChatStateConvoId() != null) {
781             appParamBuf.put((byte)CHAT_STATE_CONVO_ID);
782             appParamBuf.put((byte)CHAT_STATE_CONVO_ID_LEN);
783             appParamBuf.putLong(getChatStateConvoId().getMostSignificantBits());
784             appParamBuf.putLong(getChatStateConvoId().getLeastSignificantBits());
785         }
786         if (getFolderVerCounter() != null) {
787             appParamBuf.put((byte)FOLDER_VER_COUNTER);
788             appParamBuf.put((byte)FOLDER_VER_COUNTER_LEN);
789             appParamBuf.put(getFolderVerCounter());
790         }
791         if (getFilterMsgHandle() != INVALID_VALUE_PARAMETER) {
792             appParamBuf.put((byte)FILTER_MESSAGE_HANDLE);
793             appParamBuf.put((byte)FILTER_MESSAGE_HANDLE_LEN);
794             appParamBuf.putLong(getFilterMsgHandle());
795         }
796         if (getConvoParameterMask() != INVALID_VALUE_PARAMETER) {
797             appParamBuf.put((byte) CONVO_PARAMETER_MASK);
798             appParamBuf.put((byte) CONVO_PARAMETER_MASK_LEN);
799             appParamBuf.putInt((int) getConvoParameterMask());
800         }
801 
802         // We need to reduce the length of the array to match the content
803         retBuf = Arrays.copyOfRange(appParamBuf.array(), appParamBuf.arrayOffset(),
804                                     appParamBuf.arrayOffset() + appParamBuf.position());
805         return retBuf;
806     }
807 
getMaxListCount()808     public int getMaxListCount() {
809         return mMaxListCount;
810     }
811 
setMaxListCount(int maxListCount)812     public void setMaxListCount(int maxListCount) throws IllegalArgumentException {
813         if (maxListCount < 0 || maxListCount > 0xFFFF)
814             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
815         this.mMaxListCount = maxListCount;
816     }
817 
getStartOffset()818     public int getStartOffset() {
819         return mStartOffset;
820     }
821 
setStartOffset(int startOffset)822     public void setStartOffset(int startOffset) throws IllegalArgumentException {
823         if (startOffset < 0 || startOffset > 0xFFFF)
824             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
825         this.mStartOffset = startOffset;
826     }
827 
getFilterMessageType()828     public int getFilterMessageType() {
829         return mFilterMessageType;
830     }
831 
setFilterMessageType(int filterMessageType)832     public void setFilterMessageType(int filterMessageType) throws IllegalArgumentException {
833         if (filterMessageType < 0 || filterMessageType > 0x001F)
834             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x001F");
835         this.mFilterMessageType = filterMessageType;
836     }
837 
getFilterPeriodBegin()838     public long getFilterPeriodBegin() {
839         return mFilterPeriodBegin;
840     }
841 
getFilterPeriodBeginString()842     public String getFilterPeriodBeginString() {
843         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
844         Date date = new Date(mFilterPeriodBegin);
845         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
846     }
847 
setFilterPeriodBegin(long filterPeriodBegin)848     public void setFilterPeriodBegin(long filterPeriodBegin) {
849         this.mFilterPeriodBegin = filterPeriodBegin;
850     }
851 
setFilterPeriodBegin(String filterPeriodBegin)852     public void setFilterPeriodBegin(String filterPeriodBegin) throws ParseException {
853         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
854         Date date = format.parse(filterPeriodBegin);
855         this.mFilterPeriodBegin = date.getTime();
856     }
857 
getFilterLastActivityBegin()858     public long getFilterLastActivityBegin() {
859         return mFilterPeriodBegin;
860     }
getFilterLastActivityBeginString()861     public String getFilterLastActivityBeginString() {
862         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
863         Date date = new Date(mFilterPeriodBegin);
864         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
865     }
setFilterLastActivityBegin(long filterPeriodBegin)866     public void setFilterLastActivityBegin(long filterPeriodBegin) {
867         this.mFilterPeriodBegin = filterPeriodBegin;
868     }
869 
setFilterLastActivityBegin(String filterPeriodBegin)870     public void setFilterLastActivityBegin(String filterPeriodBegin)throws ParseException {
871         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
872         Date date = format.parse(filterPeriodBegin);
873         this.mFilterPeriodBegin = date.getTime();
874     }
getFilterPeriodEnd()875     public long getFilterPeriodEnd() {
876         return mFilterPeriodEnd;
877     }
getFilterLastActivityEnd()878     public long getFilterLastActivityEnd() {
879         return mFilterPeriodEnd;
880     }
881 
getFilterLastActivityEndString()882     public String getFilterLastActivityEndString() {
883         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
884         Date date = new Date(mFilterPeriodEnd);
885         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
886     }
887 
setFilterLastActivityEnd(long filterPeriodEnd)888     public void setFilterLastActivityEnd(long filterPeriodEnd) {
889         this.mFilterPeriodEnd= filterPeriodEnd; //er reuse the same
890     }
891 
setFilterPeriodEnd(String filterPeriodEnd)892     public void setFilterPeriodEnd(String filterPeriodEnd) throws ParseException {
893         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
894         Date date = format.parse(filterPeriodEnd);
895         this.mFilterPeriodEnd = date.getTime();
896     }
getFilterPeriodEndString()897     public String getFilterPeriodEndString() {
898         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
899         Date date = new Date(mFilterPeriodEnd);
900         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
901     }
902 
setFilterPeriodEnd(long filterPeriodEnd)903     public void setFilterPeriodEnd(long filterPeriodEnd) {
904         this.mFilterPeriodEnd = filterPeriodEnd;
905     }
906 
setFilterLastActivityEnd(String filterPeriodEnd)907     public void setFilterLastActivityEnd(String filterPeriodEnd) throws ParseException {
908         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
909         Date date = format.parse(filterPeriodEnd);
910         this.mFilterPeriodEnd = date.getTime();
911     }
getFilterReadStatus()912     public int getFilterReadStatus() {
913         return mFilterReadStatus;
914     }
915 
setFilterReadStatus(int filterReadStatus)916     public void setFilterReadStatus(int filterReadStatus) throws IllegalArgumentException {
917         if (filterReadStatus < 0 || filterReadStatus > 0x0002)
918             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
919         this.mFilterReadStatus = filterReadStatus;
920     }
921 
getFilterRecipient()922     public String getFilterRecipient() {
923         return mFilterRecipient;
924     }
925 
setFilterRecipient(String filterRecipient)926     public void setFilterRecipient(String filterRecipient) {
927         this.mFilterRecipient = filterRecipient;
928     }
929 
getFilterOriginator()930     public String getFilterOriginator() {
931         return mFilterOriginator;
932     }
933 
setFilterOriginator(String filterOriginator)934     public void setFilterOriginator(String filterOriginator) {
935         this.mFilterOriginator = filterOriginator;
936     }
937 
getFilterPriority()938     public int getFilterPriority() {
939         return mFilterPriority;
940     }
941 
setFilterPriority(int filterPriority)942     public void setFilterPriority(int filterPriority) throws IllegalArgumentException {
943         if (filterPriority < 0 || filterPriority > 0x0002)
944             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
945         this.mFilterPriority = filterPriority;
946     }
947 
setDatabaseIdentifier(long idHigh, long idLow)948     public void setDatabaseIdentifier(long idHigh, long idLow) {
949         this.mDatabaseIdentifierHigh = idHigh;
950         this.mDatabaseIdentifierLow  = idLow;
951     }
952 
getDatabaseIdentifier()953     public byte[] getDatabaseIdentifier() {
954         if(mDatabaseIdentifierLow != INVALID_VALUE_PARAMETER
955                 && mDatabaseIdentifierHigh != INVALID_VALUE_PARAMETER) {
956             ByteBuffer ret = ByteBuffer.allocate(16);
957             ret.putLong(mDatabaseIdentifierHigh);
958             ret.putLong(mDatabaseIdentifierLow);
959                 return ret.array();
960         }else return null;
961     }
962 
setConvoListingVerCounter(long countLow, long countHigh)963     public void setConvoListingVerCounter(long countLow, long countHigh) {
964         this.mConvoListingVerCounterHigh = countHigh;
965         this.mConvoListingVerCounterLow  = countLow;
966     }
967 
getConvoListingVerCounter()968     public byte[] getConvoListingVerCounter(){
969         if(mConvoListingVerCounterHigh != INVALID_VALUE_PARAMETER &&
970             mConvoListingVerCounterLow != INVALID_VALUE_PARAMETER) {
971             ByteBuffer ret = ByteBuffer.allocate(16);
972             ret.putLong(mConvoListingVerCounterHigh);
973             ret.putLong(mConvoListingVerCounterLow);
974             return ret.array();
975             } else return null;
976     }
977 
setFolderVerCounter(long countLow, long countHigh)978     public void setFolderVerCounter(long countLow, long countHigh) {
979         this.mFolderVerCounterHigh = countHigh;
980         this.mFolderVerCounterLow = countLow;
981     }
982 
getFolderVerCounter()983     public byte[] getFolderVerCounter(){
984         if(mFolderVerCounterHigh != INVALID_VALUE_PARAMETER &&
985                 mFolderVerCounterLow != INVALID_VALUE_PARAMETER) {
986             ByteBuffer ret = ByteBuffer.allocate(16);
987             ret.putLong(mFolderVerCounterHigh);
988             ret.putLong(mFolderVerCounterLow);
989             return ret.array();
990         } else return null;
991     }
992 
getChatStateConvoId()993     public SignedLongLong getChatStateConvoId(){
994         return mChatStateConvoId;
995     }
996 
getChatStateConvoIdByteArray()997     public byte[] getChatStateConvoIdByteArray() {
998         if(mChatStateConvoId != null) {
999             ByteBuffer ret = ByteBuffer.allocate(16);
1000             ret.putLong(mChatStateConvoId.getMostSignificantBits());
1001             ret.putLong(mChatStateConvoId.getLeastSignificantBits());
1002             return ret.array();
1003         } else return null;
1004     }
1005 
getChatStateConvoIdString()1006     public String getChatStateConvoIdString() {
1007         String str = null;
1008         str = new String(this.getChatStateConvoIdByteArray());
1009         return str;
1010     }
1011 
setChatStateConvoId(long idHigh, long idLow)1012     public void setChatStateConvoId(long idHigh, long idLow) {
1013         mChatStateConvoId = new SignedLongLong(idLow, idHigh);
1014     }
1015 
setFilterMsgHandle(String handle)1016     public void setFilterMsgHandle(String handle) {
1017             try {
1018                 mFilterMsgHandle = BluetoothMapUtils.getLongFromString(handle);
1019             } catch (UnsupportedEncodingException e) {
1020                 Log.w(TAG,"Error creating long from handle string", e);
1021             }
1022     }
1023 
getFilterMsgHandle()1024     public long getFilterMsgHandle(){
1025         return mFilterMsgHandle;
1026     }
1027 
getFilterMsgHandleString()1028     public String getFilterMsgHandleString() {
1029         String str = null;
1030         if(mFilterMsgHandle != INVALID_VALUE_PARAMETER) {
1031             str = BluetoothMapUtils.getLongAsString(mFilterMsgHandle);
1032         }
1033         return str;
1034     }
1035 
getFilterUidPresent()1036     public int getFilterUidPresent() {
1037         return mFilterUidPresent;
1038     }
1039 
setFilterUidPresent(int present)1040     public void setFilterUidPresent(int present) {
1041         if (present < 0 || present > 0x00FF)
1042             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1043         this.mFilterUidPresent = present;
1044     }
1045 
getFilterPresence()1046     public int getFilterPresence() {
1047         return mFilterPresence;
1048     }
1049 
1050 
1051 
getFilterConvoId()1052     public SignedLongLong getFilterConvoId(){
1053         return mFilterConvoId;
1054     }
1055 
1056     /**
1057      * Get a decimal representation of the lower bits of the ConvoId - used for queries.
1058      * The upper bits are used for convo-type.
1059      * @return decimal representation of the convo ID.
1060      */
getFilterConvoIdString()1061     public String getFilterConvoIdString() {
1062         String str = null;
1063         if(mFilterConvoId != null) {
1064             str = BluetoothMapUtils.getLongAsString(mFilterConvoId.getLeastSignificantBits());
1065         }
1066         return str;
1067     }
1068 
1069 
setFilterConvoId(String id)1070     public void setFilterConvoId(String id) {
1071         try {
1072             mFilterConvoId = SignedLongLong.fromString(id);
1073         } catch (UnsupportedEncodingException e) {
1074             Log.w(TAG,"Error creating long from id string", e);
1075         }
1076     }
1077 
1078 
setChatState(int state)1079     public void setChatState(int state) {
1080         if (state < 0 || state > 0x00FF)
1081             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1082         this.mChatState = state;
1083     }
1084 
getChatState()1085     public int getChatState() {
1086         return mChatState;
1087     }
1088 
getLastActivity()1089     public long getLastActivity(){
1090         return this.mLastActivity;
1091     }
getLastActivityString()1092     public String getLastActivityString(){
1093         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
1094         Date date = new Date(mLastActivity);
1095         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
1096     }
setLastActivity(long last)1097     public void setLastActivity(long last){
1098         this.mLastActivity = last;
1099     }
setLastActivity(String lastActivity)1100     public void setLastActivity(String lastActivity) throws ParseException {
1101         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
1102         Date date = format.parse(lastActivity);
1103         this.mLastActivity = date.getTime();
1104     }
1105 
setPresenceStatus(String status)1106     public void setPresenceStatus(String status){
1107         this.mPresenceStatus = status;
1108     }
getPresenceStatus()1109     public String getPresenceStatus(){
1110         return this.mPresenceStatus;
1111     }
1112 
setFilterPresence(int presence)1113     public void setFilterPresence(int presence) {
1114         if (presence < 0 || presence > 0xFFFF)
1115             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
1116         this.mFilterPresence = presence;
1117     }
1118 
setPresenceAvailability(int availability)1119     public void setPresenceAvailability(int availability) {
1120         if (availability < 0 || availability > 0x00FF)
1121             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1122         this.mPresenceAvailability = availability;
1123     }
1124 
getPresenceAvailability()1125     public int getPresenceAvailability() {
1126         return mPresenceAvailability;
1127     }
1128 
getSubjectLength()1129     public int getSubjectLength() {
1130         return mSubjectLength;
1131     }
getAttachment()1132     public int getAttachment() {
1133         return mAttachment;
1134     }
1135 
setAttachment(int attachment)1136     public void setAttachment(int attachment) throws IllegalArgumentException {
1137         if (attachment < 0 || attachment > 0x0001)
1138             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1139         this.mAttachment = attachment;
1140     }
1141 
getTransparent()1142     public int getTransparent() {
1143         return mTransparent;
1144     }
1145 
setTransparent(int transparent)1146     public void setTransparent(int transparent) throws IllegalArgumentException {
1147         if (transparent < 0 || transparent > 0x0001)
1148             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1149         this.mTransparent = transparent;
1150     }
1151 
getRetry()1152     public int getRetry() {
1153         return mRetry;
1154     }
1155 
setRetry(int retry)1156     public void setRetry(int retry) throws IllegalArgumentException {
1157         if (retry < 0 || retry > 0x0001)
1158             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1159         this.mRetry = retry;
1160     }
1161 
getNewMessage()1162     public int getNewMessage() {
1163         return mNewMessage;
1164     }
1165 
setNewMessage(int newMessage)1166     public void setNewMessage(int newMessage) throws IllegalArgumentException {
1167         if (newMessage < 0 || newMessage > 0x0001)
1168             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1169         this.mNewMessage = newMessage;
1170     }
1171 
getNotificationStatus()1172     public int getNotificationStatus() {
1173         return mNotificationStatus;
1174     }
1175 
setNotificationStatus(int notificationStatus)1176     public void setNotificationStatus(int notificationStatus) throws IllegalArgumentException {
1177         if (notificationStatus < 0 || notificationStatus > 0x0001)
1178             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1179         this.mNotificationStatus = notificationStatus;
1180     }
1181 
getNotificationFilter()1182     public long getNotificationFilter() {
1183         return mNotificationFilter;
1184     }
1185 
setNotificationFilter(long notificationFilter)1186     public void setNotificationFilter(long notificationFilter) throws IllegalArgumentException {
1187         if (notificationFilter < 0 || notificationFilter > 0xFFFFFFFFL)
1188             throw new IllegalArgumentException(
1189                     "Out of range, valid range is 0x0000 to 0xFFFFFFFFL");
1190         this.mNotificationFilter = notificationFilter;
1191     }
1192 
getMasInstanceId()1193     public int getMasInstanceId() {
1194         return mMasInstanceId;
1195     }
1196 
setMasInstanceId(int masInstanceId)1197     public void setMasInstanceId(int masInstanceId) {
1198         if (masInstanceId < 0 || masInstanceId > 0x00FF)
1199             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1200         this.mMasInstanceId = masInstanceId;
1201     }
1202 
getParameterMask()1203     public long getParameterMask() {
1204         return mParameterMask;
1205     }
1206 
setParameterMask(long parameterMask)1207     public void setParameterMask(long parameterMask) {
1208         if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL)
1209             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF");
1210         this.mParameterMask = parameterMask;
1211     }
1212 
setConvoParameterMask(long parameterMask)1213     public void setConvoParameterMask(long parameterMask) {
1214         if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL)
1215             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF");
1216         this.mConvoParameterMask = parameterMask;
1217     }
1218 
getConvoParameterMask()1219     public long getConvoParameterMask(){
1220         return mConvoParameterMask;
1221     }
1222 
getFolderListingSize()1223     public int getFolderListingSize() {
1224         return mFolderListingSize;
1225     }
1226 
setFolderListingSize(int folderListingSize)1227     public void setFolderListingSize(int folderListingSize) {
1228         if (folderListingSize < 0 || folderListingSize > 0xFFFF)
1229             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
1230         this.mFolderListingSize = folderListingSize;
1231     }
1232 
getMessageListingSize()1233     public int getMessageListingSize() {
1234         return mMessageListingSize;
1235     }
1236 
setMessageListingSize(int messageListingSize)1237     public void setMessageListingSize(int messageListingSize) {
1238         if (messageListingSize < 0 || messageListingSize > 0xFFFF)
1239             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
1240         this.mMessageListingSize = messageListingSize;
1241     }
1242 
getConvoListingSize()1243     public int getConvoListingSize() {
1244         return mConvoListingSize;
1245     }
1246 
setConvoListingSize(int convoListingSize)1247     public void setConvoListingSize(int convoListingSize) {
1248         if (convoListingSize < 0 || convoListingSize > 0xFFFF)
1249             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
1250         this.mConvoListingSize = convoListingSize;
1251     }
setSubjectLength(int subjectLength)1252     public void setSubjectLength(int subjectLength) {
1253         if (subjectLength < 0 || subjectLength > 0xFF)
1254             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
1255         this.mSubjectLength = subjectLength;
1256     }
1257 
getCharset()1258     public int getCharset() {
1259         return mCharset;
1260     }
1261 
setCharset(int charset)1262     public void setCharset(int charset) {
1263         if (charset < 0 || charset > 0x1)
1264             throw new IllegalArgumentException("Out of range: " + charset + ", valid range is 0x0000 to 0x0001");
1265         this.mCharset = charset;
1266     }
1267 
getFractionRequest()1268     public int getFractionRequest() {
1269         return mFractionRequest;
1270     }
1271 
setFractionRequest(int fractionRequest)1272     public void setFractionRequest(int fractionRequest) {
1273         if (fractionRequest < 0 || fractionRequest > 0x1)
1274             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1275         this.mFractionRequest = fractionRequest;
1276     }
1277 
getFractionDeliver()1278     public int getFractionDeliver() {
1279         return mFractionDeliver;
1280     }
1281 
setFractionDeliver(int fractionDeliver)1282     public void setFractionDeliver(int fractionDeliver) {
1283         if (fractionDeliver < 0 || fractionDeliver > 0x1)
1284             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1285         this.mFractionDeliver = fractionDeliver;
1286     }
1287 
getStatusIndicator()1288     public int getStatusIndicator() {
1289         return mStatusIndicator;
1290     }
1291 
setStatusIndicator(int statusIndicator)1292     public void setStatusIndicator(int statusIndicator) {
1293         if (statusIndicator < 0 || statusIndicator > 0x1)
1294             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1295         this.mStatusIndicator = statusIndicator;
1296     }
1297 
getStatusValue()1298     public int getStatusValue() {
1299         return mStatusValue;
1300     }
1301 
setStatusValue(int statusValue)1302     public void setStatusValue(int statusValue) {
1303         if (statusValue < 0 || statusValue > 0x1)
1304             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
1305         this.mStatusValue = statusValue;
1306     }
1307 
getMseTime()1308     public long getMseTime() {
1309         return mMseTime;
1310     }
1311 
getMseTimeString()1312     public String getMseTimeString() {
1313         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
1314         Date date = new Date(getMseTime());
1315         return format.format(date); // Format to YYYYMMDDTHHMMSS±hhmm UTC time ± offset
1316     }
1317 
setMseTime(long mseTime)1318     public void setMseTime(long mseTime) {
1319         this.mMseTime = mseTime;
1320     }
1321 
setMseTime(String mseTime)1322     public void setMseTime(String mseTime) throws ParseException {
1323         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
1324         Date date = format.parse(mseTime);
1325         this.mMseTime = date.getTime();
1326     }
1327 
1328 
1329 
1330 
1331 }
1332