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