Home | History | Annotate | Download | only in map
      1 /*
      2 * Copyright (C) 2013 Samsung System LSI
      3 * Licensed under the Apache License, Version 2.0 (the "License");
      4 * you may not use this file except in compliance with the License.
      5 * You may obtain a copy of the License at
      6 *
      7 *      http://www.apache.org/licenses/LICENSE-2.0
      8 *
      9 * Unless required by applicable law or agreed to in writing, software
     10 * distributed under the License is distributed on an "AS IS" BASIS,
     11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 * See the License for the specific language governing permissions and
     13 * limitations under the License.
     14 */
     15 package com.android.bluetooth.map;
     16 
     17 import android.util.Log;
     18 
     19 import com.android.bluetooth.SignedLongLong;
     20 
     21 import java.io.UnsupportedEncodingException;
     22 import java.nio.ByteBuffer;
     23 import java.nio.ByteOrder;
     24 import java.text.ParseException;
     25 import java.text.SimpleDateFormat;
     26 import java.util.Arrays;
     27 import java.util.Date;
     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      */
    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      */
    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      */
    223     private void parseParams(final byte[] appParams)
    224             throws ParseException, 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,
    244                                 "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,
    317                                 "TRANSPARENT: Wrong length received: " + tagLength + " expected: "
    318                                         + TRANSPARENT_LEN);
    319                     } else {
    320                         setTransparent(appParams[i] & 0x01); // Lower bit
    321                     }
    322                     break;
    323                 case RETRY:
    324                     if (tagLength != RETRY_LEN) {
    325                         Log.w(TAG, "RETRY: Wrong length received: " + tagLength + " expected: "
    326                                 + RETRY_LEN);
    327                     } else {
    328                         setRetry(appParams[i] & 0x01); // Lower bit
    329                     }
    330                     break;
    331                 case NEW_MESSAGE:
    332                     if (tagLength != NEW_MESSAGE_LEN) {
    333                         Log.w(TAG,
    334                                 "NEW_MESSAGE: Wrong length received: " + tagLength + " expected: "
    335                                         + NEW_MESSAGE_LEN);
    336                     } else {
    337                         setNewMessage(appParams[i] & 0x01); // Lower bit
    338                     }
    339                     break;
    340                 case NOTIFICATION_STATUS:
    341                     if (tagLength != NOTIFICATION_STATUS_LEN) {
    342                         Log.w(TAG, "NOTIFICATION_STATUS: Wrong length received: " + tagLength
    343                                 + " expected: " + NOTIFICATION_STATUS_LEN);
    344                     } else {
    345                         setNotificationStatus(appParams[i] & 0x01); // Lower bit
    346                     }
    347                     break;
    348                 case NOTIFICATION_FILTER:
    349                     if (tagLength != NOTIFICATION_FILTER_LEN) {
    350                         Log.w(TAG, "NOTIFICATION_FILTER: Wrong length received: " + tagLength
    351                                 + " expected: " + NOTIFICATION_FILTER_LEN);
    352                     } else {
    353                         setNotificationFilter(appParamBuf.getInt(i) & 0xffffffffL); // 4 bytes
    354                     }
    355                     break;
    356                 case MAS_INSTANCE_ID:
    357                     if (tagLength != MAS_INSTANCE_ID_LEN) {
    358                         Log.w(TAG, "MAS_INSTANCE_ID: Wrong length received: " + tagLength
    359                                 + " expected: " + MAS_INSTANCE_ID_LEN);
    360                     } else {
    361                         setMasInstanceId(appParams[i] & 0xff);
    362                     }
    363                     break;
    364                 case PARAMETER_MASK:
    365                     if (tagLength != PARAMETER_MASK_LEN) {
    366                         Log.w(TAG, "PARAMETER_MASK: Wrong length received: " + tagLength
    367                                 + " expected: " + PARAMETER_MASK_LEN);
    368                     } else {
    369                         setParameterMask(appParamBuf.getInt(i) & 0xffffffffL); // Make it unsigned
    370                     }
    371                     break;
    372                 case FOLDER_LISTING_SIZE:
    373                     if (tagLength != FOLDER_LISTING_SIZE_LEN) {
    374                         Log.w(TAG, "FOLDER_LISTING_SIZE: Wrong length received: " + tagLength
    375                                 + " expected: " + FOLDER_LISTING_SIZE_LEN);
    376                     } else {
    377                         setFolderListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
    378                     }
    379                     break;
    380                 case MESSAGE_LISTING_SIZE:
    381                     if (tagLength != MESSAGE_LISTING_SIZE_LEN) {
    382                         Log.w(TAG, "MESSAGE_LISTING_SIZE: Wrong length received: " + tagLength
    383                                 + " expected: " + MESSAGE_LISTING_SIZE_LEN);
    384                     } else {
    385                         setMessageListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
    386                     }
    387                     break;
    388                 case SUBJECT_LENGTH:
    389                     if (tagLength != SUBJECT_LENGTH_LEN) {
    390                         Log.w(TAG, "SUBJECT_LENGTH: Wrong length received: " + tagLength
    391                                 + " expected: " + SUBJECT_LENGTH_LEN);
    392                     } else {
    393                         setSubjectLength(appParams[i] & 0xff);
    394                     }
    395                     break;
    396                 case CHARSET:
    397                     if (tagLength != CHARSET_LEN) {
    398                         Log.w(TAG, "CHARSET: Wrong length received: " + tagLength + " expected: "
    399                                 + CHARSET_LEN);
    400                     } else {
    401                         setCharset(appParams[i] & 0x01); // Lower bit
    402                     }
    403                     break;
    404                 case FRACTION_REQUEST:
    405                     if (tagLength != FRACTION_REQUEST_LEN) {
    406                         Log.w(TAG, "FRACTION_REQUEST: Wrong length received: " + tagLength
    407                                 + " expected: " + FRACTION_REQUEST_LEN);
    408                     } else {
    409                         setFractionRequest(appParams[i] & 0x01); // Lower bit
    410                     }
    411                     break;
    412                 case FRACTION_DELIVER:
    413                     if (tagLength != FRACTION_DELIVER_LEN) {
    414                         Log.w(TAG, "FRACTION_DELIVER: Wrong length received: " + tagLength
    415                                 + " expected: " + FRACTION_DELIVER_LEN);
    416                     } else {
    417                         setFractionDeliver(appParams[i] & 0x01); // Lower bit
    418                     }
    419                     break;
    420                 case STATUS_INDICATOR:
    421                     if (tagLength != STATUS_INDICATOR_LEN) {
    422                         Log.w(TAG, "STATUS_INDICATOR: Wrong length received: " + tagLength
    423                                 + " expected: " + STATUS_INDICATOR_LEN);
    424                     } else {
    425                         setStatusIndicator(appParams[i] & 0x01); // Lower bit
    426                     }
    427                     break;
    428                 case STATUS_VALUE:
    429                     if (tagLength != STATUS_VALUE_LEN) {
    430                         Log.w(TAG,
    431                                 "STATUS_VALUER: Wrong length received: " + tagLength + " expected: "
    432                                         + STATUS_VALUE_LEN);
    433                     } else {
    434                         setStatusValue(appParams[i] & 0x01); // Lower bit
    435                     }
    436                     break;
    437                 case MSE_TIME:
    438                     setMseTime(new String(appParams, i, tagLength));
    439                     break;
    440                 case DATABASE_INDETIFIER:
    441                     if ((tagLength != DATABASE_INDETIFIER_LEN)) {
    442                         Log.w(TAG, "DATABASE_IDENTIFIER: Wrong length received: " + tagLength
    443                                 + " expected: " + DATABASE_INDETIFIER_LEN);
    444                     } else {
    445                         setDatabaseIdentifier(appParamBuf.getLong(i)/*MSB*/,
    446                                 appParamBuf.getLong(i + 8)/*LSB*/);
    447                     }
    448                     break;
    449                 case CONVO_LIST_VER_COUNTER:
    450                     if ((tagLength != CONVO_LIST_VER_COUNTER_LEN)) {
    451                         Log.w(TAG, "CONVO_LIST_VER_COUNTER: Wrong length received: " + tagLength
    452                                 + " expected: " + CONVO_LIST_VER_COUNTER_LEN);
    453                     } else {
    454                         setConvoListingVerCounter(appParamBuf.getLong(i)/*MSB*/,
    455                                 appParamBuf.getLong(i + 8)/*LSB*/);
    456                     }
    457                     break;
    458                 case PRESENCE_AVAILABLE:
    459                     if ((tagLength != PRESENCE_AVAILABLE_LEN)) {
    460                         Log.w(TAG, "PRESENCE_AVAILABLE: Wrong length received: " + tagLength
    461                                 + " expected: " + PRESENCE_AVAILABLE_LEN);
    462                     } else {
    463                         setPresenceAvailability(appParams[i]);
    464                     }
    465                     break;
    466                 case PRESENCE_TEXT:
    467                     if (tagLength != 0) {
    468                         setPresenceStatus(new String(appParams, i, tagLength));
    469                     } else {
    470                         Log.w(TAG, "PRESENCE_STATUS: Wrong length received: " + tagLength
    471                                 + " expected to be more than 0");
    472                     }
    473                     break;
    474                 case LAST_ACTIVITY:
    475                     if (tagLength != 0) {
    476                         setLastActivity(new String(appParams, i, tagLength));
    477                     } else {
    478                         Log.w(TAG, "LAST_ACTIVITY: Wrong length received: " + tagLength
    479                                 + " expected to be more than 0");
    480                     }
    481                     break;
    482                 case CHAT_STATE:
    483                     if ((tagLength != CHAT_STATE_LEN)) {
    484                         Log.w(TAG, "CHAT_STATE: Wrong length received: " + tagLength + " expected: "
    485                                 + CHAT_STATE_LEN);
    486                     } else {
    487                         setChatState(appParams[i]);
    488                     }
    489                     break;
    490                 case FILTER_CONVO_ID:
    491                     if ((tagLength != 0) && (tagLength <= FILTER_CONVO_ID_LEN)) {
    492                         setFilterConvoId(new String(appParams, i, tagLength));
    493                     } else {
    494                         Log.w(TAG, "FILTER_CONVO_ID: Wrong length received: " + tagLength
    495                                 + " expected: " + FILTER_CONVO_ID_LEN);
    496                     }
    497                     break;
    498                 case CONVO_LISTING_SIZE:
    499                     if (tagLength != CONVO_LISTING_SIZE_LEN) {
    500                         Log.w(TAG,
    501                                 "LISTING_SIZE: Wrong length received: " + tagLength + " expected: "
    502                                         + CONVO_LISTING_SIZE_LEN);
    503 
    504                     } else {
    505                         setConvoListingSize(appParamBuf.getShort(i) & 0xffff);
    506                     }
    507                     break;
    508                 case FILTER_PRESENCE:
    509                     if ((tagLength != FILTER_PRESENCE_LEN)) {
    510                         Log.w(TAG, "FILTER_PRESENCE: Wrong length received: " + tagLength
    511                                 + " expected: " + FILTER_PRESENCE_LEN);
    512                     } else {
    513                         setFilterPresence(appParams[i]);
    514                     }
    515                     break;
    516                 case FILTER_UID_PRESENT:
    517                     if ((tagLength != FILTER_UID_PRESENT_LEN)) {
    518                         Log.w(TAG, "FILTER_UID_PRESENT: Wrong length received: " + tagLength
    519                                 + " expected: " + FILTER_UID_PRESENT_LEN);
    520                     } else {
    521                         setFilterUidPresent(appParams[i] & 0x1);
    522                     }
    523                     break;
    524                 case CHAT_STATE_CONVO_ID:
    525                     if ((tagLength != CHAT_STATE_CONVO_ID_LEN)) {
    526                         Log.w(TAG, "CHAT_STATE_CONVO_ID: Wrong length received: " + tagLength
    527                                 + " expected: " + CHAT_STATE_CONVO_ID_LEN);
    528                     } else {
    529                     /* TODO: Is this correct convoId handling? */
    530                         setChatStateConvoId(appParamBuf.getLong(i)/*MSB*/,
    531                                 appParamBuf.getLong(i + 8)/*LSB*/);
    532                         Log.d(TAG, "CHAT_STATE_CONVO_ID: convo id " + "MSB="
    533                                 + BluetoothMapUtils.getLongAsString(appParamBuf.getLong(i))
    534                                 + ", LSB(+8)=" + BluetoothMapUtils.getLongAsString(
    535                                 appParamBuf.getLong(i + 8)));
    536 
    537                     }
    538                     break;
    539                 case FOLDER_VER_COUNTER:
    540                     break;
    541                 case FILTER_MESSAGE_HANDLE:
    542                     if ((tagLength != 0 && tagLength <= FILTER_MESSAGE_HANDLE_LEN)) {
    543                         setFilterMsgHandle(new String(appParams, i, tagLength));
    544                     } else {
    545                         Log.w(TAG, "FILTER_MESSAGE_HANDLE: Wrong length received: " + tagLength
    546                                 + " expected: " + FILTER_MESSAGE_HANDLE_LEN);
    547                     }
    548 
    549                     break;
    550                 case CONVO_PARAMETER_MASK:
    551                     if (tagLength != CONVO_PARAMETER_MASK_LEN) {
    552                         Log.w(TAG, "CONVO_PARAMETER_MASK: Wrong length received: " + tagLength
    553                                 + " expected: " + CONVO_PARAMETER_MASK_LEN);
    554                     } else {
    555                         setConvoParameterMask(
    556                                 appParamBuf.getInt(i) & 0xffffffffL); // Make it unsigned
    557                     }
    558                     break;
    559                 default:
    560                     // Just skip unknown Tags, no need to report error
    561                     Log.w(TAG, "Unknown TagId received ( 0x" + Integer.toString(tagId, 16)
    562                             + "), skipping...");
    563                     break;
    564             }
    565             i += tagLength; // Offset to next TagId
    566         }
    567     }
    568 
    569     /**
    570      * Get the approximate length needed to store the appParameters in a byte
    571      * array.
    572      *
    573      * @return the length in bytes
    574      * @throws UnsupportedEncodingException
    575      *             if the platform does not support UTF-8 encoding.
    576      */
    577     private int getParamMaxLength() throws UnsupportedEncodingException {
    578         int length = 0;
    579         length += 38 * 2; // tagId + tagLength
    580         length += 33 + 4 * 16; // fixed sizes TODO: Update when spec is ready
    581         length += getFilterPeriodBegin() == INVALID_VALUE_PARAMETER ? 0 : 20;
    582         length += getFilterPeriodEnd() == INVALID_VALUE_PARAMETER ? 0 : 20;
    583         if (getFilterRecipient() != null) {
    584             length += getFilterRecipient().getBytes("UTF-8").length;
    585         }
    586         if (getFilterOriginator() != null) {
    587             length += getFilterOriginator().getBytes("UTF-8").length;
    588         }
    589         length += getMseTime() == INVALID_VALUE_PARAMETER ? 0 : 20;
    590         if (getPresenceStatus() != null) {
    591             length += getPresenceStatus().getBytes("UTF-8").length;
    592         }
    593         length += (getLastActivity() == INVALID_VALUE_PARAMETER) ? 0 : 20;
    594         return length;
    595     }
    596 
    597     /**
    598      * Encode the application parameter object to a byte array.
    599      *
    600      * @return a byte Array representation of the application parameter object.
    601      * @throws UnsupportedEncodingException
    602      *             if the platform does not support UTF-8 encoding.
    603      */
    604     public byte[] encodeParams() throws UnsupportedEncodingException {
    605         ByteBuffer appParamBuf = ByteBuffer.allocate(getParamMaxLength());
    606         appParamBuf.order(ByteOrder.BIG_ENDIAN);
    607         byte[] retBuf;
    608 
    609         if (getMaxListCount() != INVALID_VALUE_PARAMETER) {
    610             appParamBuf.put((byte) MAX_LIST_COUNT);
    611             appParamBuf.put((byte) MAX_LIST_COUNT_LEN);
    612             appParamBuf.putShort((short) getMaxListCount());
    613         }
    614         if (getStartOffset() != INVALID_VALUE_PARAMETER) {
    615             appParamBuf.put((byte) START_OFFSET);
    616             appParamBuf.put((byte) START_OFFSET_LEN);
    617             appParamBuf.putShort((short) getStartOffset());
    618         }
    619         if (getFilterMessageType() != INVALID_VALUE_PARAMETER) {
    620             appParamBuf.put((byte) FILTER_MESSAGE_TYPE);
    621             appParamBuf.put((byte) FILTER_MESSAGE_TYPE_LEN);
    622             appParamBuf.put((byte) getFilterMessageType());
    623         }
    624         if (getFilterPeriodBegin() != INVALID_VALUE_PARAMETER) {
    625             appParamBuf.put((byte) FILTER_PERIOD_BEGIN);
    626             appParamBuf.put((byte) getFilterPeriodBeginString().getBytes("UTF-8").length);
    627             appParamBuf.put(getFilterPeriodBeginString().getBytes("UTF-8"));
    628         }
    629         if (getFilterPeriodEnd() != INVALID_VALUE_PARAMETER) {
    630             appParamBuf.put((byte) FILTER_PERIOD_END);
    631             appParamBuf.put((byte) getFilterPeriodEndString().getBytes("UTF-8").length);
    632             appParamBuf.put(getFilterPeriodEndString().getBytes("UTF-8"));
    633         }
    634         if (getFilterReadStatus() != INVALID_VALUE_PARAMETER) {
    635             appParamBuf.put((byte) FILTER_READ_STATUS);
    636             appParamBuf.put((byte) FILTER_READ_STATUS_LEN);
    637             appParamBuf.put((byte) getFilterReadStatus());
    638         }
    639         if (getFilterRecipient() != null) {
    640             appParamBuf.put((byte) FILTER_RECIPIENT);
    641             appParamBuf.put((byte) getFilterRecipient().getBytes("UTF-8").length);
    642             appParamBuf.put(getFilterRecipient().getBytes("UTF-8"));
    643         }
    644         if (getFilterOriginator() != null) {
    645             appParamBuf.put((byte) FILTER_ORIGINATOR);
    646             appParamBuf.put((byte) getFilterOriginator().getBytes("UTF-8").length);
    647             appParamBuf.put(getFilterOriginator().getBytes("UTF-8"));
    648         }
    649         if (getFilterPriority() != INVALID_VALUE_PARAMETER) {
    650             appParamBuf.put((byte) FILTER_PRIORITY);
    651             appParamBuf.put((byte) FILTER_PRIORITY_LEN);
    652             appParamBuf.put((byte) getFilterPriority());
    653         }
    654         if (getAttachment() != INVALID_VALUE_PARAMETER) {
    655             appParamBuf.put((byte) ATTACHMENT);
    656             appParamBuf.put((byte) ATTACHMENT_LEN);
    657             appParamBuf.put((byte) getAttachment());
    658         }
    659         if (getTransparent() != INVALID_VALUE_PARAMETER) {
    660             appParamBuf.put((byte) TRANSPARENT);
    661             appParamBuf.put((byte) TRANSPARENT_LEN);
    662             appParamBuf.put((byte) getTransparent());
    663         }
    664         if (getRetry() != INVALID_VALUE_PARAMETER) {
    665             appParamBuf.put((byte) RETRY);
    666             appParamBuf.put((byte) RETRY_LEN);
    667             appParamBuf.put((byte) getRetry());
    668         }
    669         if (getNewMessage() != INVALID_VALUE_PARAMETER) {
    670             appParamBuf.put((byte) NEW_MESSAGE);
    671             appParamBuf.put((byte) NEW_MESSAGE_LEN);
    672             appParamBuf.put((byte) getNewMessage());
    673         }
    674         if (getNotificationStatus() != INVALID_VALUE_PARAMETER) {
    675             appParamBuf.put((byte) NOTIFICATION_STATUS);
    676             appParamBuf.put((byte) NOTIFICATION_STATUS_LEN);
    677             appParamBuf.putShort((short) getNotificationStatus());
    678         }
    679         if (getNotificationFilter() != INVALID_VALUE_PARAMETER) {
    680             appParamBuf.put((byte) NOTIFICATION_FILTER);
    681             appParamBuf.put((byte) NOTIFICATION_FILTER_LEN);
    682             appParamBuf.putInt((int) getNotificationFilter());
    683         }
    684         if (getMasInstanceId() != INVALID_VALUE_PARAMETER) {
    685             appParamBuf.put((byte) MAS_INSTANCE_ID);
    686             appParamBuf.put((byte) MAS_INSTANCE_ID_LEN);
    687             appParamBuf.put((byte) getMasInstanceId());
    688         }
    689         if (getParameterMask() != INVALID_VALUE_PARAMETER) {
    690             appParamBuf.put((byte) PARAMETER_MASK);
    691             appParamBuf.put((byte) PARAMETER_MASK_LEN);
    692             appParamBuf.putInt((int) getParameterMask());
    693         }
    694         if (getFolderListingSize() != INVALID_VALUE_PARAMETER) {
    695             appParamBuf.put((byte) FOLDER_LISTING_SIZE);
    696             appParamBuf.put((byte) FOLDER_LISTING_SIZE_LEN);
    697             appParamBuf.putShort((short) getFolderListingSize());
    698         }
    699         if (getMessageListingSize() != INVALID_VALUE_PARAMETER) {
    700             appParamBuf.put((byte) MESSAGE_LISTING_SIZE);
    701             appParamBuf.put((byte) MESSAGE_LISTING_SIZE_LEN);
    702             appParamBuf.putShort((short) getMessageListingSize());
    703         }
    704         if (getSubjectLength() != INVALID_VALUE_PARAMETER) {
    705             appParamBuf.put((byte) SUBJECT_LENGTH);
    706             appParamBuf.put((byte) SUBJECT_LENGTH_LEN);
    707             appParamBuf.put((byte) getSubjectLength());
    708         }
    709         if (getCharset() != INVALID_VALUE_PARAMETER) {
    710             appParamBuf.put((byte) CHARSET);
    711             appParamBuf.put((byte) CHARSET_LEN);
    712             appParamBuf.put((byte) getCharset());
    713         }
    714         if (getFractionRequest() != INVALID_VALUE_PARAMETER) {
    715             appParamBuf.put((byte) FRACTION_REQUEST);
    716             appParamBuf.put((byte) FRACTION_REQUEST_LEN);
    717             appParamBuf.put((byte) getFractionRequest());
    718         }
    719         if (getFractionDeliver() != INVALID_VALUE_PARAMETER) {
    720             appParamBuf.put((byte) FRACTION_DELIVER);
    721             appParamBuf.put((byte) FRACTION_DELIVER_LEN);
    722             appParamBuf.put((byte) getFractionDeliver());
    723         }
    724         if (getStatusIndicator() != INVALID_VALUE_PARAMETER) {
    725             appParamBuf.put((byte) STATUS_INDICATOR);
    726             appParamBuf.put((byte) STATUS_INDICATOR_LEN);
    727             appParamBuf.put((byte) getStatusIndicator());
    728         }
    729         if (getStatusValue() != INVALID_VALUE_PARAMETER) {
    730             appParamBuf.put((byte) STATUS_VALUE);
    731             appParamBuf.put((byte) STATUS_VALUE_LEN);
    732             appParamBuf.put((byte) getStatusValue());
    733         }
    734         if (getMseTime() != INVALID_VALUE_PARAMETER) {
    735             appParamBuf.put((byte) MSE_TIME);
    736             appParamBuf.put((byte) getMseTimeString().getBytes("UTF-8").length);
    737             appParamBuf.put(getMseTimeString().getBytes("UTF-8"));
    738         }
    739         // Note: New for IM
    740         if (getDatabaseIdentifier() != null) {
    741             appParamBuf.put((byte) DATABASE_INDETIFIER);
    742             appParamBuf.put((byte) DATABASE_INDETIFIER_LEN);
    743             appParamBuf.put(getDatabaseIdentifier());
    744         }
    745         if (getConvoListingVerCounter() != null) {
    746             appParamBuf.put((byte) CONVO_LIST_VER_COUNTER);
    747             appParamBuf.put((byte) CONVO_LIST_VER_COUNTER_LEN);
    748             appParamBuf.put(getConvoListingVerCounter());
    749         }
    750         if (getPresenceAvailability() != INVALID_VALUE_PARAMETER) {
    751             appParamBuf.put((byte) PRESENCE_AVAILABLE);
    752             appParamBuf.put((byte) PRESENCE_AVAILABLE_LEN);
    753             appParamBuf.putInt((int) getPresenceAvailability());
    754         }
    755         if (getPresenceStatus() != null) {
    756             appParamBuf.put((byte) PRESENCE_TEXT);
    757             appParamBuf.put((byte) getPresenceStatus().getBytes("UTF-8").length);
    758             appParamBuf.put(getPresenceStatus().getBytes());
    759         }
    760         if (getLastActivity() != INVALID_VALUE_PARAMETER) {
    761             appParamBuf.put((byte) LAST_ACTIVITY);
    762             appParamBuf.put((byte) getLastActivityString().getBytes("UTF-8").length);
    763             appParamBuf.put(getLastActivityString().getBytes());
    764         }
    765         if (getChatState() != INVALID_VALUE_PARAMETER) {
    766             appParamBuf.put((byte) CHAT_STATE);
    767             appParamBuf.put((byte) CHAT_STATE_LEN);
    768             appParamBuf.putShort((short) getChatState());
    769         }
    770         if (getFilterConvoId() != null) {
    771             appParamBuf.put((byte) FILTER_CONVO_ID);
    772             appParamBuf.put((byte) FILTER_CONVO_ID_LEN);
    773             appParamBuf.putLong(getFilterConvoId().getMostSignificantBits());
    774             appParamBuf.putLong(getFilterConvoId().getLeastSignificantBits());
    775         }
    776         if (getConvoListingSize() != INVALID_VALUE_PARAMETER) {
    777             appParamBuf.put((byte) CONVO_LISTING_SIZE);
    778             appParamBuf.put((byte) CONVO_LISTING_SIZE_LEN);
    779             appParamBuf.putShort((short) getConvoListingSize());
    780         }
    781         if (getFilterPresence() != INVALID_VALUE_PARAMETER) {
    782             appParamBuf.put((byte) FILTER_PRESENCE);
    783             appParamBuf.put((byte) FILTER_PRESENCE_LEN);
    784             appParamBuf.putShort((short) getFilterPresence());
    785         }
    786         if (getFilterUidPresent() != INVALID_VALUE_PARAMETER) {
    787             appParamBuf.put((byte) FILTER_UID_PRESENT);
    788             appParamBuf.put((byte) FILTER_UID_PRESENT_LEN);
    789             appParamBuf.putShort((short) getFilterUidPresent());
    790         }
    791         if (getChatStateConvoId() != null) {
    792             appParamBuf.put((byte) CHAT_STATE_CONVO_ID);
    793             appParamBuf.put((byte) CHAT_STATE_CONVO_ID_LEN);
    794             appParamBuf.putLong(getChatStateConvoId().getMostSignificantBits());
    795             appParamBuf.putLong(getChatStateConvoId().getLeastSignificantBits());
    796         }
    797         if (getFolderVerCounter() != null) {
    798             appParamBuf.put((byte) FOLDER_VER_COUNTER);
    799             appParamBuf.put((byte) FOLDER_VER_COUNTER_LEN);
    800             appParamBuf.put(getFolderVerCounter());
    801         }
    802         if (getFilterMsgHandle() != INVALID_VALUE_PARAMETER) {
    803             appParamBuf.put((byte) FILTER_MESSAGE_HANDLE);
    804             appParamBuf.put((byte) FILTER_MESSAGE_HANDLE_LEN);
    805             appParamBuf.putLong(getFilterMsgHandle());
    806         }
    807         if (getConvoParameterMask() != INVALID_VALUE_PARAMETER) {
    808             appParamBuf.put((byte) CONVO_PARAMETER_MASK);
    809             appParamBuf.put((byte) CONVO_PARAMETER_MASK_LEN);
    810             appParamBuf.putInt((int) getConvoParameterMask());
    811         }
    812 
    813         // We need to reduce the length of the array to match the content
    814         retBuf = Arrays.copyOfRange(appParamBuf.array(), appParamBuf.arrayOffset(),
    815                 appParamBuf.arrayOffset() + appParamBuf.position());
    816         return retBuf;
    817     }
    818 
    819     public int getMaxListCount() {
    820         return mMaxListCount;
    821     }
    822 
    823     public void setMaxListCount(int maxListCount) throws IllegalArgumentException {
    824         if (maxListCount < 0 || maxListCount > 0xFFFF) {
    825             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
    826         }
    827         this.mMaxListCount = maxListCount;
    828     }
    829 
    830     public int getStartOffset() {
    831         return mStartOffset;
    832     }
    833 
    834     public void setStartOffset(int startOffset) throws IllegalArgumentException {
    835         if (startOffset < 0 || startOffset > 0xFFFF) {
    836             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
    837         }
    838         this.mStartOffset = startOffset;
    839     }
    840 
    841     public int getFilterMessageType() {
    842         return mFilterMessageType;
    843     }
    844 
    845     public void setFilterMessageType(int filterMessageType) throws IllegalArgumentException {
    846         if (filterMessageType < 0 || filterMessageType > 0x001F) {
    847             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x001F");
    848         }
    849         this.mFilterMessageType = filterMessageType;
    850     }
    851 
    852     public long getFilterPeriodBegin() {
    853         return mFilterPeriodBegin;
    854     }
    855 
    856     public String getFilterPeriodBeginString() {
    857         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    858         Date date = new Date(mFilterPeriodBegin);
    859         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
    860     }
    861 
    862     public void setFilterPeriodBegin(long filterPeriodBegin) {
    863         this.mFilterPeriodBegin = filterPeriodBegin;
    864     }
    865 
    866     public void setFilterPeriodBegin(String filterPeriodBegin) throws ParseException {
    867         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    868         Date date = format.parse(filterPeriodBegin);
    869         this.mFilterPeriodBegin = date.getTime();
    870     }
    871 
    872     public long getFilterLastActivityBegin() {
    873         return mFilterPeriodBegin;
    874     }
    875 
    876     public String getFilterLastActivityBeginString() {
    877         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    878         Date date = new Date(mFilterPeriodBegin);
    879         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
    880     }
    881 
    882     public void setFilterLastActivityBegin(long filterPeriodBegin) {
    883         this.mFilterPeriodBegin = filterPeriodBegin;
    884     }
    885 
    886     public void setFilterLastActivityBegin(String filterPeriodBegin) throws ParseException {
    887         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    888         Date date = format.parse(filterPeriodBegin);
    889         this.mFilterPeriodBegin = date.getTime();
    890     }
    891 
    892     public long getFilterPeriodEnd() {
    893         return mFilterPeriodEnd;
    894     }
    895 
    896     public long getFilterLastActivityEnd() {
    897         return mFilterPeriodEnd;
    898     }
    899 
    900     public String getFilterLastActivityEndString() {
    901         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    902         Date date = new Date(mFilterPeriodEnd);
    903         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
    904     }
    905 
    906     public void setFilterLastActivityEnd(long filterPeriodEnd) {
    907         this.mFilterPeriodEnd = filterPeriodEnd; //er reuse the same
    908     }
    909 
    910     public void setFilterPeriodEnd(String filterPeriodEnd) throws ParseException {
    911         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    912         Date date = format.parse(filterPeriodEnd);
    913         this.mFilterPeriodEnd = date.getTime();
    914     }
    915 
    916     public String getFilterPeriodEndString() {
    917         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    918         Date date = new Date(mFilterPeriodEnd);
    919         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
    920     }
    921 
    922     public void setFilterPeriodEnd(long filterPeriodEnd) {
    923         this.mFilterPeriodEnd = filterPeriodEnd;
    924     }
    925 
    926     public void setFilterLastActivityEnd(String filterPeriodEnd) throws ParseException {
    927         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
    928         Date date = format.parse(filterPeriodEnd);
    929         this.mFilterPeriodEnd = date.getTime();
    930     }
    931 
    932     public int getFilterReadStatus() {
    933         return mFilterReadStatus;
    934     }
    935 
    936     public void setFilterReadStatus(int filterReadStatus) throws IllegalArgumentException {
    937         if (filterReadStatus < 0 || filterReadStatus > 0x0002) {
    938             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
    939         }
    940         this.mFilterReadStatus = filterReadStatus;
    941     }
    942 
    943     public String getFilterRecipient() {
    944         return mFilterRecipient;
    945     }
    946 
    947     public void setFilterRecipient(String filterRecipient) {
    948         this.mFilterRecipient = filterRecipient;
    949     }
    950 
    951     public String getFilterOriginator() {
    952         return mFilterOriginator;
    953     }
    954 
    955     public void setFilterOriginator(String filterOriginator) {
    956         this.mFilterOriginator = filterOriginator;
    957     }
    958 
    959     public int getFilterPriority() {
    960         return mFilterPriority;
    961     }
    962 
    963     public void setFilterPriority(int filterPriority) throws IllegalArgumentException {
    964         if (filterPriority < 0 || filterPriority > 0x0002) {
    965             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
    966         }
    967         this.mFilterPriority = filterPriority;
    968     }
    969 
    970     public void setDatabaseIdentifier(long idHigh, long idLow) {
    971         this.mDatabaseIdentifierHigh = idHigh;
    972         this.mDatabaseIdentifierLow = idLow;
    973     }
    974 
    975     public byte[] getDatabaseIdentifier() {
    976         if (mDatabaseIdentifierLow != INVALID_VALUE_PARAMETER
    977                 && mDatabaseIdentifierHigh != INVALID_VALUE_PARAMETER) {
    978             ByteBuffer ret = ByteBuffer.allocate(16);
    979             ret.putLong(mDatabaseIdentifierHigh);
    980             ret.putLong(mDatabaseIdentifierLow);
    981             return ret.array();
    982         } else {
    983             return null;
    984         }
    985     }
    986 
    987     public void setConvoListingVerCounter(long countLow, long countHigh) {
    988         this.mConvoListingVerCounterHigh = countHigh;
    989         this.mConvoListingVerCounterLow = countLow;
    990     }
    991 
    992     public byte[] getConvoListingVerCounter() {
    993         if (mConvoListingVerCounterHigh != INVALID_VALUE_PARAMETER
    994                 && mConvoListingVerCounterLow != INVALID_VALUE_PARAMETER) {
    995             ByteBuffer ret = ByteBuffer.allocate(16);
    996             ret.putLong(mConvoListingVerCounterHigh);
    997             ret.putLong(mConvoListingVerCounterLow);
    998             return ret.array();
    999         } else {
   1000             return null;
   1001         }
   1002     }
   1003 
   1004     public void setFolderVerCounter(long countLow, long countHigh) {
   1005         this.mFolderVerCounterHigh = countHigh;
   1006         this.mFolderVerCounterLow = countLow;
   1007     }
   1008 
   1009     public byte[] getFolderVerCounter() {
   1010         if (mFolderVerCounterHigh != INVALID_VALUE_PARAMETER
   1011                 && mFolderVerCounterLow != INVALID_VALUE_PARAMETER) {
   1012             ByteBuffer ret = ByteBuffer.allocate(16);
   1013             ret.putLong(mFolderVerCounterHigh);
   1014             ret.putLong(mFolderVerCounterLow);
   1015             return ret.array();
   1016         } else {
   1017             return null;
   1018         }
   1019     }
   1020 
   1021     public SignedLongLong getChatStateConvoId() {
   1022         return mChatStateConvoId;
   1023     }
   1024 
   1025     public byte[] getChatStateConvoIdByteArray() {
   1026         if (mChatStateConvoId != null) {
   1027             ByteBuffer ret = ByteBuffer.allocate(16);
   1028             ret.putLong(mChatStateConvoId.getMostSignificantBits());
   1029             ret.putLong(mChatStateConvoId.getLeastSignificantBits());
   1030             return ret.array();
   1031         } else {
   1032             return null;
   1033         }
   1034     }
   1035 
   1036     public String getChatStateConvoIdString() {
   1037         String str = null;
   1038         str = new String(this.getChatStateConvoIdByteArray());
   1039         return str;
   1040     }
   1041 
   1042     public void setChatStateConvoId(long idHigh, long idLow) {
   1043         mChatStateConvoId = new SignedLongLong(idLow, idHigh);
   1044     }
   1045 
   1046     public void setFilterMsgHandle(String handle) {
   1047         try {
   1048             mFilterMsgHandle = BluetoothMapUtils.getLongFromString(handle);
   1049         } catch (UnsupportedEncodingException e) {
   1050             Log.w(TAG, "Error creating long from handle string", e);
   1051         }
   1052     }
   1053 
   1054     public long getFilterMsgHandle() {
   1055         return mFilterMsgHandle;
   1056     }
   1057 
   1058     public String getFilterMsgHandleString() {
   1059         String str = null;
   1060         if (mFilterMsgHandle != INVALID_VALUE_PARAMETER) {
   1061             str = BluetoothMapUtils.getLongAsString(mFilterMsgHandle);
   1062         }
   1063         return str;
   1064     }
   1065 
   1066     public int getFilterUidPresent() {
   1067         return mFilterUidPresent;
   1068     }
   1069 
   1070     public void setFilterUidPresent(int present) {
   1071         if (present < 0 || present > 0x00FF) {
   1072             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
   1073         }
   1074         this.mFilterUidPresent = present;
   1075     }
   1076 
   1077     public int getFilterPresence() {
   1078         return mFilterPresence;
   1079     }
   1080 
   1081 
   1082     public SignedLongLong getFilterConvoId() {
   1083         return mFilterConvoId;
   1084     }
   1085 
   1086     /**
   1087      * Get a decimal representation of the lower bits of the ConvoId - used for queries.
   1088      * The upper bits are used for convo-type.
   1089      * @return decimal representation of the convo ID.
   1090      */
   1091     public String getFilterConvoIdString() {
   1092         String str = null;
   1093         if (mFilterConvoId != null) {
   1094             str = BluetoothMapUtils.getLongAsString(mFilterConvoId.getLeastSignificantBits());
   1095         }
   1096         return str;
   1097     }
   1098 
   1099 
   1100     public void setFilterConvoId(String id) {
   1101         try {
   1102             mFilterConvoId = SignedLongLong.fromString(id);
   1103         } catch (UnsupportedEncodingException e) {
   1104             Log.w(TAG, "Error creating long from id string", e);
   1105         }
   1106     }
   1107 
   1108 
   1109     public void setChatState(int state) {
   1110         if (state < 0 || state > 0x00FF) {
   1111             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
   1112         }
   1113         this.mChatState = state;
   1114     }
   1115 
   1116     public int getChatState() {
   1117         return mChatState;
   1118     }
   1119 
   1120     public long getLastActivity() {
   1121         return this.mLastActivity;
   1122     }
   1123 
   1124     public String getLastActivityString() {
   1125         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
   1126         Date date = new Date(mLastActivity);
   1127         return format.format(date); // Format to YYYYMMDDTHHMMSS local time
   1128     }
   1129 
   1130     public void setLastActivity(long last) {
   1131         this.mLastActivity = last;
   1132     }
   1133 
   1134     public void setLastActivity(String lastActivity) throws ParseException {
   1135         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
   1136         Date date = format.parse(lastActivity);
   1137         this.mLastActivity = date.getTime();
   1138     }
   1139 
   1140     public void setPresenceStatus(String status) {
   1141         this.mPresenceStatus = status;
   1142     }
   1143 
   1144     public String getPresenceStatus() {
   1145         return this.mPresenceStatus;
   1146     }
   1147 
   1148     public void setFilterPresence(int presence) {
   1149         if (presence < 0 || presence > 0xFFFF) {
   1150             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
   1151         }
   1152         this.mFilterPresence = presence;
   1153     }
   1154 
   1155     public void setPresenceAvailability(int availability) {
   1156         if (availability < 0 || availability > 0x00FF) {
   1157             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
   1158         }
   1159         this.mPresenceAvailability = availability;
   1160     }
   1161 
   1162     public int getPresenceAvailability() {
   1163         return mPresenceAvailability;
   1164     }
   1165 
   1166     public int getSubjectLength() {
   1167         return mSubjectLength;
   1168     }
   1169 
   1170     public int getAttachment() {
   1171         return mAttachment;
   1172     }
   1173 
   1174     public void setAttachment(int attachment) throws IllegalArgumentException {
   1175         if (attachment < 0 || attachment > 0x0001) {
   1176             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1177         }
   1178         this.mAttachment = attachment;
   1179     }
   1180 
   1181     public int getTransparent() {
   1182         return mTransparent;
   1183     }
   1184 
   1185     public void setTransparent(int transparent) throws IllegalArgumentException {
   1186         if (transparent < 0 || transparent > 0x0001) {
   1187             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1188         }
   1189         this.mTransparent = transparent;
   1190     }
   1191 
   1192     public int getRetry() {
   1193         return mRetry;
   1194     }
   1195 
   1196     public void setRetry(int retry) throws IllegalArgumentException {
   1197         if (retry < 0 || retry > 0x0001) {
   1198             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1199         }
   1200         this.mRetry = retry;
   1201     }
   1202 
   1203     public int getNewMessage() {
   1204         return mNewMessage;
   1205     }
   1206 
   1207     public void setNewMessage(int newMessage) throws IllegalArgumentException {
   1208         if (newMessage < 0 || newMessage > 0x0001) {
   1209             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1210         }
   1211         this.mNewMessage = newMessage;
   1212     }
   1213 
   1214     public int getNotificationStatus() {
   1215         return mNotificationStatus;
   1216     }
   1217 
   1218     public void setNotificationStatus(int notificationStatus) throws IllegalArgumentException {
   1219         if (notificationStatus < 0 || notificationStatus > 0x0001) {
   1220             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1221         }
   1222         this.mNotificationStatus = notificationStatus;
   1223     }
   1224 
   1225     public long getNotificationFilter() {
   1226         return mNotificationFilter;
   1227     }
   1228 
   1229     public void setNotificationFilter(long notificationFilter) throws IllegalArgumentException {
   1230         if (notificationFilter < 0 || notificationFilter > 0xFFFFFFFFL) {
   1231             throw new IllegalArgumentException(
   1232                     "Out of range, valid range is 0x0000 to 0xFFFFFFFFL");
   1233         }
   1234         this.mNotificationFilter = notificationFilter;
   1235     }
   1236 
   1237     public int getMasInstanceId() {
   1238         return mMasInstanceId;
   1239     }
   1240 
   1241     public void setMasInstanceId(int masInstanceId) {
   1242         if (masInstanceId < 0 || masInstanceId > 0x00FF) {
   1243             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
   1244         }
   1245         this.mMasInstanceId = masInstanceId;
   1246     }
   1247 
   1248     public long getParameterMask() {
   1249         return mParameterMask;
   1250     }
   1251 
   1252     public void setParameterMask(long parameterMask) {
   1253         if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL) {
   1254             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF");
   1255         }
   1256         this.mParameterMask = parameterMask;
   1257     }
   1258 
   1259     public void setConvoParameterMask(long parameterMask) {
   1260         if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL) {
   1261             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF");
   1262         }
   1263         this.mConvoParameterMask = parameterMask;
   1264     }
   1265 
   1266     public long getConvoParameterMask() {
   1267         return mConvoParameterMask;
   1268     }
   1269 
   1270     public int getFolderListingSize() {
   1271         return mFolderListingSize;
   1272     }
   1273 
   1274     public void setFolderListingSize(int folderListingSize) {
   1275         if (folderListingSize < 0 || folderListingSize > 0xFFFF) {
   1276             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
   1277         }
   1278         this.mFolderListingSize = folderListingSize;
   1279     }
   1280 
   1281     public int getMessageListingSize() {
   1282         return mMessageListingSize;
   1283     }
   1284 
   1285     public void setMessageListingSize(int messageListingSize) {
   1286         if (messageListingSize < 0 || messageListingSize > 0xFFFF) {
   1287             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
   1288         }
   1289         this.mMessageListingSize = messageListingSize;
   1290     }
   1291 
   1292     public int getConvoListingSize() {
   1293         return mConvoListingSize;
   1294     }
   1295 
   1296     public void setConvoListingSize(int convoListingSize) {
   1297         if (convoListingSize < 0 || convoListingSize > 0xFFFF) {
   1298             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
   1299         }
   1300         this.mConvoListingSize = convoListingSize;
   1301     }
   1302 
   1303     public void setSubjectLength(int subjectLength) {
   1304         if (subjectLength < 0 || subjectLength > 0xFF) {
   1305             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
   1306         }
   1307         this.mSubjectLength = subjectLength;
   1308     }
   1309 
   1310     public int getCharset() {
   1311         return mCharset;
   1312     }
   1313 
   1314     public void setCharset(int charset) {
   1315         if (charset < 0 || charset > 0x1) {
   1316             throw new IllegalArgumentException(
   1317                     "Out of range: " + charset + ", valid range is 0x0000 to 0x0001");
   1318         }
   1319         this.mCharset = charset;
   1320     }
   1321 
   1322     public int getFractionRequest() {
   1323         return mFractionRequest;
   1324     }
   1325 
   1326     public void setFractionRequest(int fractionRequest) {
   1327         if (fractionRequest < 0 || fractionRequest > 0x1) {
   1328             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1329         }
   1330         this.mFractionRequest = fractionRequest;
   1331     }
   1332 
   1333     public int getFractionDeliver() {
   1334         return mFractionDeliver;
   1335     }
   1336 
   1337     public void setFractionDeliver(int fractionDeliver) {
   1338         if (fractionDeliver < 0 || fractionDeliver > 0x1) {
   1339             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1340         }
   1341         this.mFractionDeliver = fractionDeliver;
   1342     }
   1343 
   1344     public int getStatusIndicator() {
   1345         return mStatusIndicator;
   1346     }
   1347 
   1348     public void setStatusIndicator(int statusIndicator) {
   1349         if (statusIndicator < 0 || statusIndicator > 0x1) {
   1350             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1351         }
   1352         this.mStatusIndicator = statusIndicator;
   1353     }
   1354 
   1355     public int getStatusValue() {
   1356         return mStatusValue;
   1357     }
   1358 
   1359     public void setStatusValue(int statusValue) {
   1360         if (statusValue < 0 || statusValue > 0x1) {
   1361             throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
   1362         }
   1363         this.mStatusValue = statusValue;
   1364     }
   1365 
   1366     public long getMseTime() {
   1367         return mMseTime;
   1368     }
   1369 
   1370     public String getMseTimeString() {
   1371         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
   1372         Date date = new Date(getMseTime());
   1373         return format.format(date); // Format to YYYYMMDDTHHMMSShhmm UTC time  offset
   1374     }
   1375 
   1376     public void setMseTime(long mseTime) {
   1377         this.mMseTime = mseTime;
   1378     }
   1379 
   1380     public void setMseTime(String mseTime) throws ParseException {
   1381         SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
   1382         Date date = format.parse(mseTime);
   1383         this.mMseTime = date.getTime();
   1384     }
   1385 
   1386 
   1387 }
   1388