BluetoothMapAppParams.java revision 0053efa4b58c3e5815a500bd719c5018e7e87852
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*/
15package com.android.bluetooth.map;
16
17import java.io.UnsupportedEncodingException;
18import java.nio.ByteBuffer;
19import java.nio.ByteOrder;
20import java.text.ParseException;
21import java.text.SimpleDateFormat;
22import java.util.Arrays;
23import java.util.Date;
24
25import android.util.Log;
26
27/**
28 * This class encapsulates the appParams needed for MAP.
29 */
30public class BluetoothMapAppParams {
31
32    private static final String TAG = "BluetoothMapAppParams";
33
34    private static final int MAX_LIST_COUNT           = 0x01;
35    private static final int MAX_LIST_COUNT_LEN       = 0x02; //, 0x0000, 0xFFFF),
36    private static final int START_OFFSET             = 0x02;
37    private static final int START_OFFSET_LEN         = 0x02; //, 0x0000, 0xFFFF),
38    private static final int FILTER_MESSAGE_TYPE      = 0x03;
39    private static final int FILTER_MESSAGE_TYPE_LEN  = 0x01; //, 0x0000, 0x000f),
40    private static final int FILTER_PERIOD_BEGIN      = 0x04;
41    private static final int FILTER_PERIOD_END        = 0x05;
42    private static final int FILTER_READ_STATUS       = 0x06;
43    private static final int FILTER_READ_STATUS_LEN   = 0x01; //, 0x0000, 0x0002),
44    private static final int FILTER_RECIPIENT         = 0x07;
45    private static final int FILTER_ORIGINATOR        = 0x08;
46    private static final int FILTER_PRIORITY          = 0x09;
47    private static final int FILTER_PRIORITY_LEN      = 0x01; //, 0x0000, 0x0002),
48    private static final int ATTACHMENT               = 0x0A;
49    private static final int ATTACHMENT_LEN           = 0x01; //, 0x0000, 0x0001),
50    private static final int TRANSPARENT              = 0x0B;
51    private static final int TRANSPARENT_LEN          = 0x01; //, 0x0000, 0x0001),
52    private static final int RETRY                    = 0x0C;
53    private static final int RETRY_LEN                = 0x01; //, 0x0000, 0x0001),
54    private static final int NEW_MESSAGE              = 0x0D;
55    private static final int NEW_MESSAGE_LEN          = 0x01; //, 0x0000, 0x0001),
56    private static final int NOTIFICATION_STATUS      = 0x0E;
57    private static final int NOTIFICATION_STATUS_LEN  = 0x01; //, 0x0000, 0xFFFF),
58    private static final int MAS_INSTANCE_ID          = 0x0F;
59    private static final int MAS_INSTANCE_ID_LEN      = 0x01; //, 0x0000, 0x00FF),
60    private static final int PARAMETER_MASK           = 0x10;
61    private static final int PARAMETER_MASK_LEN       = 0x04; //, 0x0000, 0x0000),
62    private static final int FOLDER_LISTING_SIZE      = 0x11;
63    private static final int FOLDER_LISTING_SIZE_LEN  = 0x02; //, 0x0000, 0xFFFF),
64    private static final int MESSAGE_LISTING_SIZE     = 0x12;
65    private static final int MESSAGE_LISTING_SIZE_LEN = 0x02; //, 0x0000, 0xFFFF),
66    private static final int SUBJECT_LENGTH           = 0x13;
67    private static final int SUBJECT_LENGTH_LEN       = 0x01; //, 0x0000, 0x00FF),
68    private static final int CHARSET                  = 0x14;
69    private static final int CHARSET_LEN              = 0x01; //, 0x0000, 0x0001),
70    private static final int FRACTION_REQUEST         = 0x15;
71    private static final int FRACTION_REQUEST_LEN     = 0x01; //, 0x0000, 0x0001),
72    private static final int FRACTION_DELIVER         = 0x16;
73    private static final int FRACTION_DELIVER_LEN     = 0x01; //, 0x0000, 0x0001),
74    private static final int STATUS_INDICATOR         = 0x17;
75    private static final int STATUS_INDICATOR_LEN     = 0x01; //, 0x0000, 0x0001),
76    private static final int STATUS_VALUE             = 0x18;
77    private static final int STATUS_VALUE_LEN         = 0x01; //, 0x0000, 0x0001),
78    private static final int MSE_TIME                 = 0x19;
79
80    public static final int INVALID_VALUE_PARAMETER = -1;
81    public static final int NOTIFICATION_STATUS_NO = 0;
82    public static final int NOTIFICATION_STATUS_YES = 1;
83    public static final int STATUS_INDICATOR_READ = 0;
84    public static final int STATUS_INDICATOR_DELETED = 1;
85    public static final int STATUS_VALUE_YES = 1;
86    public static final int STATUS_VALUE_NO = 0;
87    public static final int CHARSET_NATIVE = 0;
88    public static final int CHARSET_UTF8 = 1;
89
90    /* Default values for omitted application parameters */
91    public static final long PARAMETER_MASK_ALL_ENABLED = 0xFFFF; // TODO: Update when bit 16-31 will be used.
92
93    private int maxListCount        = INVALID_VALUE_PARAMETER;
94    private int startOffset         = INVALID_VALUE_PARAMETER;
95    private int filterMessageType   = INVALID_VALUE_PARAMETER;
96    private long filterPeriodBegin  = INVALID_VALUE_PARAMETER;
97    private long filterPeriodEnd    = INVALID_VALUE_PARAMETER;
98    private int filterReadStatus    = INVALID_VALUE_PARAMETER;
99    private String filterRecipient   = null;
100    private String filterOriginator  = null;
101    private int filterPriority      = INVALID_VALUE_PARAMETER;
102    private int attachment          = INVALID_VALUE_PARAMETER;
103    private int transparent         = INVALID_VALUE_PARAMETER;
104    private int retry               = INVALID_VALUE_PARAMETER;
105    private int newMessage          = INVALID_VALUE_PARAMETER;
106    private int notificationStatus  = INVALID_VALUE_PARAMETER;
107    private int masInstanceId       = INVALID_VALUE_PARAMETER;
108    private long parameterMask      = INVALID_VALUE_PARAMETER;
109    private int folderListingSize   = INVALID_VALUE_PARAMETER;
110    private int messageListingSize  = INVALID_VALUE_PARAMETER;
111    private int subjectLength       = INVALID_VALUE_PARAMETER;
112    private int charset             = INVALID_VALUE_PARAMETER;
113    private int fractionRequest     = INVALID_VALUE_PARAMETER;
114    private int fractionDeliver     = INVALID_VALUE_PARAMETER;
115    private int statusIndicator     = INVALID_VALUE_PARAMETER;
116    private int statusValue         = INVALID_VALUE_PARAMETER;
117    private long mseTime            = INVALID_VALUE_PARAMETER;
118
119    /**
120     * Default constructor, used to build an application parameter object to be
121     * encoded. By default the member variables will be initialized to
122     * {@link INVALID_VALUE_PARAMETER} for values, and empty strings for String
123     * typed members.
124     */
125    public BluetoothMapAppParams() {
126    }
127
128    /**
129     * Creates an application parameter object based on a application parameter
130     * OBEX header. The content of the {@link appParam} byte array will be
131     * parsed, and its content will be stored in the member variables.
132     * {@link INVALID_VALUE_PARAMETER} can be used to determine if a value is
133     * set or not, where strings will be empty, if {@link appParam} did not
134     * contain the parameter.
135     *
136     * @param appParams
137     *            the byte array containing the application parameters OBEX
138     *            header
139     * @throws IllegalArgumentException
140     *             when a parameter does not respect the valid ranges specified
141     *             in the MAP spec.
142     * @throws ParseException
143     *             if a parameter string if formated incorrectly.
144     */
145    public BluetoothMapAppParams(final byte[] appParams)
146                 throws IllegalArgumentException, ParseException {
147        ParseParams(appParams);
148    }
149
150    /**
151     * Parse an application parameter OBEX header stored in a ByteArray.
152     *
153     * @param appParams
154     *            the byte array containing the application parameters OBEX
155     *            header
156     * @throws IllegalArgumentException
157     *             when a parameter does not respect the valid ranges specified
158     *             in the MAP spec.
159     * @throws ParseException
160     *             if a parameter string if formated incorrectly.
161     */
162    private void ParseParams(final byte[] appParams) throws ParseException,
163              IllegalArgumentException {
164        int i = 0;
165        int tagId, tagLength;
166        ByteBuffer appParamBuf = ByteBuffer.wrap(appParams);
167        appParamBuf.order(ByteOrder.BIG_ENDIAN);
168        while (i < appParams.length) {
169            tagId = appParams[i++] & 0xff;     // Convert to unsigned to support values above 127
170            tagLength = appParams[i++] & 0xff; // Convert to unsigned to support values above 127
171            switch (tagId) {
172            case MAX_LIST_COUNT:
173                if (tagLength != MAX_LIST_COUNT_LEN) {
174                    Log.w(TAG, "MAX_LIST_COUNT: Wrong length received: " + tagLength
175                               + " expected: " + MAX_LIST_COUNT_LEN);
176                    break;
177                }
178                setMaxListCount(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
179                break;
180            case START_OFFSET:
181                if (tagLength != START_OFFSET_LEN) {
182                    Log.w(TAG, "START_OFFSET: Wrong length received: " + tagLength + " expected: "
183                               + START_OFFSET_LEN);
184                    break;
185                }
186                setStartOffset(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
187                break;
188            case FILTER_MESSAGE_TYPE:
189                if (tagLength != FILTER_MESSAGE_TYPE_LEN) {
190                    Log.w(TAG, "FILTER_MESSAGE_TYPE: Wrong length received: " + tagLength + " expected: "
191                            + FILTER_MESSAGE_TYPE_LEN);
192                    break;
193                }
194                    setFilterMessageType(appParams[i] & 0x0f);
195                break;
196            case FILTER_PERIOD_BEGIN:
197                if(tagLength != 0) {
198                    setFilterPeriodBegin(new String(appParams, i, tagLength));
199                }
200                break;
201            case FILTER_PERIOD_END:
202                if(tagLength != 0) {
203                    setFilterPeriodEnd(new String(appParams, i, tagLength));
204                }
205                break;
206            case FILTER_READ_STATUS:
207                if (tagLength != FILTER_READ_STATUS_LEN) {
208                     Log.w(TAG, "FILTER_READ_STATUS: Wrong length received: " + tagLength + " expected: "
209                             + FILTER_READ_STATUS_LEN);
210                     break;
211                 }
212                setFilterReadStatus(appParams[i] & 0x03); // Lower two bits
213                break;
214            case FILTER_RECIPIENT:
215                setFilterRecipient(new String(appParams, i, tagLength));
216                break;
217            case FILTER_ORIGINATOR:
218                setFilterOriginator(new String(appParams, i, tagLength));
219                break;
220            case FILTER_PRIORITY:
221                if (tagLength != FILTER_PRIORITY_LEN) {
222                     Log.w(TAG, "FILTER_PRIORITY: Wrong length received: " + tagLength + " expected: "
223                             + FILTER_PRIORITY_LEN);
224                     break;
225                }
226                setFilterPriority(appParams[i] & 0x03); // Lower two bits
227                break;
228            case ATTACHMENT:
229                if (tagLength != ATTACHMENT_LEN) {
230                     Log.w(TAG, "ATTACHMENT: Wrong length received: " + tagLength + " expected: "
231                             + ATTACHMENT_LEN);
232                     break;
233                }
234                setAttachment(appParams[i] & 0x01); // Lower bit
235                break;
236            case TRANSPARENT:
237                if (tagLength != TRANSPARENT_LEN) {
238                     Log.w(TAG, "TRANSPARENT: Wrong length received: " + tagLength + " expected: "
239                             + TRANSPARENT_LEN);
240                     break;
241                }
242                setTransparent(appParams[i] & 0x01); // Lower bit
243                break;
244            case RETRY:
245                if (tagLength != RETRY_LEN) {
246                     Log.w(TAG, "RETRY: Wrong length received: " + tagLength + " expected: "
247                             + RETRY_LEN);
248                     break;
249                }
250                setRetry(appParams[i] & 0x01); // Lower bit
251                break;
252            case NEW_MESSAGE:
253                if (tagLength != NEW_MESSAGE_LEN) {
254                     Log.w(TAG, "NEW_MESSAGE: Wrong length received: " + tagLength + " expected: "
255                             + NEW_MESSAGE_LEN);
256                     break;
257                }
258                setNewMessage(appParams[i] & 0x01); // Lower bit
259                break;
260            case NOTIFICATION_STATUS:
261                if (tagLength != NOTIFICATION_STATUS_LEN) {
262                     Log.w(TAG, "NOTIFICATION_STATUS: Wrong length received: " + tagLength + " expected: "
263                             + NOTIFICATION_STATUS_LEN);
264                     break;
265                }
266                setNotificationStatus(appParams[i] & 0x01); // Lower bit
267                break;
268            case MAS_INSTANCE_ID:
269                if (tagLength != MAS_INSTANCE_ID_LEN) {
270                    Log.w(TAG, "MAS_INSTANCE_ID: Wrong length received: " + tagLength + " expected: "
271                            + MAS_INSTANCE_ID_LEN);
272                    break;
273                }
274                setMasInstanceId(appParams[i] & 0xff);
275                break;
276            case PARAMETER_MASK:
277                if (tagLength != PARAMETER_MASK_LEN) {
278                    Log.w(TAG, "PARAMETER_MASK: Wrong length received: " + tagLength + " expected: "
279                            + PARAMETER_MASK_LEN);
280                    break;
281                }
282                setParameterMask(appParamBuf.getInt(i) & 0xffffffffL); // Make it unsigned
283                break;
284            case FOLDER_LISTING_SIZE:
285                if (tagLength != FOLDER_LISTING_SIZE_LEN) {
286                    Log.w(TAG, "FOLDER_LISTING_SIZE: Wrong length received: " + tagLength + " expected: "
287                            + FOLDER_LISTING_SIZE_LEN);
288                    break;
289                }
290                setFolderListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
291                break;
292            case MESSAGE_LISTING_SIZE:
293                if (tagLength != MESSAGE_LISTING_SIZE_LEN) {
294                    Log.w(TAG, "MESSAGE_LISTING_SIZE: Wrong length received: " + tagLength + " expected: "
295                            + MESSAGE_LISTING_SIZE_LEN);
296                    break;
297                }
298                setMessageListingSize(appParamBuf.getShort(i) & 0xffff); // Make it unsigned
299                break;
300            case SUBJECT_LENGTH:
301                if (tagLength != SUBJECT_LENGTH_LEN) {
302                    Log.w(TAG, "SUBJECT_LENGTH: Wrong length received: " + tagLength + " expected: "
303                            + SUBJECT_LENGTH_LEN);
304                    break;
305                }
306                setSubjectLength(appParams[i] & 0xff);
307                break;
308            case CHARSET:
309                if (tagLength != CHARSET_LEN) {
310                    Log.w(TAG, "CHARSET: Wrong length received: " + tagLength + " expected: "
311                            + CHARSET_LEN);
312                    break;
313                }
314                setCharset(appParams[i] & 0x01); // Lower bit
315                break;
316            case FRACTION_REQUEST:
317                if (tagLength != FRACTION_REQUEST_LEN) {
318                    Log.w(TAG, "FRACTION_REQUEST: Wrong length received: " + tagLength + " expected: "
319                            + FRACTION_REQUEST_LEN);
320                    break;
321                }
322                setFractionRequest(appParams[i] & 0x01); // Lower bit
323                break;
324            case FRACTION_DELIVER:
325                if (tagLength != FRACTION_DELIVER_LEN) {
326                    Log.w(TAG, "FRACTION_DELIVER: Wrong length received: " + tagLength + " expected: "
327                            + FRACTION_DELIVER_LEN);
328                    break;
329                }
330                setFractionDeliver(appParams[i] & 0x01); // Lower bit
331                break;
332            case STATUS_INDICATOR:
333                if (tagLength != STATUS_INDICATOR_LEN) {
334                    Log.w(TAG, "STATUS_INDICATOR: Wrong length received: " + tagLength + " expected: "
335                            + STATUS_INDICATOR_LEN);
336                    break;
337                }
338                setStatusIndicator(appParams[i] & 0x01); // Lower bit
339                break;
340            case STATUS_VALUE:
341                if (tagLength != STATUS_VALUE_LEN) {
342                    Log.w(TAG, "STATUS_VALUER: Wrong length received: " + tagLength + " expected: "
343                            + STATUS_VALUE_LEN);
344                    break;
345                }
346                setStatusValue(appParams[i] & 0x01); // Lower bit
347                break;
348            case MSE_TIME:
349                setMseTime(new String(appParams, i, tagLength));
350                break;
351            default:
352                // Just skip unknown Tags, no need to report error
353                Log.w(TAG, "Unknown TagId received ( 0x" + Integer.toString(tagId, 16)
354                           + "), skipping...");
355                break;
356            }
357            i += tagLength; // Offset to next TagId
358        }
359    }
360
361    /**
362     * Get the approximate length needed to store the appParameters in a byte
363     * array.
364     *
365     * @return the length in bytes
366     * @throws UnsupportedEncodingException
367     *             if the platform does not support UTF-8 encoding.
368     */
369    private int getParamMaxLength() throws UnsupportedEncodingException {
370        int length = 0;
371        length += 25 * 2; // tagId + tagLength
372        length += 27; // fixed sizes
373        length += getFilterPeriodBegin() == INVALID_VALUE_PARAMETER ? 0 : 15;
374        length += getFilterPeriodEnd() == INVALID_VALUE_PARAMETER ? 0 : 15;
375        if (getFilterRecipient() != null)
376            length += getFilterRecipient().getBytes("UTF-8").length;
377        if (getFilterOriginator() != null)
378            length += getFilterOriginator().getBytes("UTF-8").length;
379        length += getMseTime() == INVALID_VALUE_PARAMETER ? 0 : 20;
380        return length;
381    }
382
383    /**
384     * Encode the application parameter object to a byte array.
385     *
386     * @return a byte Array representation of the application parameter object.
387     * @throws UnsupportedEncodingException
388     *             if the platform does not support UTF-8 encoding.
389     */
390    public byte[] EncodeParams() throws UnsupportedEncodingException {
391        ByteBuffer appParamBuf = ByteBuffer.allocate(getParamMaxLength());
392        appParamBuf.order(ByteOrder.BIG_ENDIAN);
393        byte[] retBuf;
394
395        if (getMaxListCount() != INVALID_VALUE_PARAMETER) {
396            appParamBuf.put((byte) MAX_LIST_COUNT);
397            appParamBuf.put((byte) MAX_LIST_COUNT_LEN);
398            appParamBuf.putShort((short) getMaxListCount());
399        }
400        if (getStartOffset() != INVALID_VALUE_PARAMETER) {
401            appParamBuf.put((byte) START_OFFSET);
402            appParamBuf.put((byte) START_OFFSET_LEN);
403            appParamBuf.putShort((short) getStartOffset());
404        }
405        if (getFilterMessageType() != INVALID_VALUE_PARAMETER) {
406            appParamBuf.put((byte) FILTER_MESSAGE_TYPE);
407            appParamBuf.put((byte) FILTER_MESSAGE_TYPE_LEN);
408            appParamBuf.put((byte) getFilterMessageType());
409        }
410        if (getFilterPeriodBegin() != INVALID_VALUE_PARAMETER) {
411            appParamBuf.put((byte) FILTER_PERIOD_BEGIN);
412            appParamBuf.put((byte) getFilterPeriodBeginString().getBytes("UTF-8").length);
413            appParamBuf.put(getFilterPeriodBeginString().getBytes("UTF-8"));
414        }
415        if (getFilterPeriodEnd() != INVALID_VALUE_PARAMETER) {
416            appParamBuf.put((byte) FILTER_PERIOD_END);
417            appParamBuf.put((byte) getFilterPeriodEndString().getBytes("UTF-8").length);
418            appParamBuf.put(getFilterPeriodEndString().getBytes("UTF-8"));
419        }
420        if (getFilterReadStatus() != INVALID_VALUE_PARAMETER) {
421            appParamBuf.put((byte) FILTER_READ_STATUS);
422            appParamBuf.put((byte) FILTER_READ_STATUS_LEN);
423            appParamBuf.put((byte) getFilterReadStatus());
424        }
425        if (getFilterRecipient() != null) {
426            appParamBuf.put((byte) FILTER_RECIPIENT);
427            appParamBuf.put((byte) getFilterRecipient().getBytes("UTF-8").length);
428            appParamBuf.put(getFilterRecipient().getBytes("UTF-8"));
429        }
430        if (getFilterOriginator() != null) {
431            appParamBuf.put((byte) FILTER_ORIGINATOR);
432            appParamBuf.put((byte) getFilterOriginator().getBytes("UTF-8").length);
433            appParamBuf.put(getFilterOriginator().getBytes("UTF-8"));
434        }
435        if (getFilterPriority() != INVALID_VALUE_PARAMETER) {
436            appParamBuf.put((byte) FILTER_PRIORITY);
437            appParamBuf.put((byte) FILTER_PRIORITY_LEN);
438            appParamBuf.put((byte) getFilterPriority());
439        }
440        if (getAttachment() != INVALID_VALUE_PARAMETER) {
441            appParamBuf.put((byte) ATTACHMENT);
442            appParamBuf.put((byte) ATTACHMENT_LEN);
443            appParamBuf.put((byte) getAttachment());
444        }
445        if (getTransparent() != INVALID_VALUE_PARAMETER) {
446            appParamBuf.put((byte) TRANSPARENT);
447            appParamBuf.put((byte) TRANSPARENT_LEN);
448            appParamBuf.put((byte) getTransparent());
449        }
450        if (getRetry() != INVALID_VALUE_PARAMETER) {
451            appParamBuf.put((byte) RETRY);
452            appParamBuf.put((byte) RETRY_LEN);
453            appParamBuf.put((byte) getRetry());
454        }
455        if (getNewMessage() != INVALID_VALUE_PARAMETER) {
456            appParamBuf.put((byte) NEW_MESSAGE);
457            appParamBuf.put((byte) NEW_MESSAGE_LEN);
458            appParamBuf.put((byte) getNewMessage());
459        }
460        if (getNotificationStatus() != INVALID_VALUE_PARAMETER) {
461            appParamBuf.put((byte) NOTIFICATION_STATUS);
462            appParamBuf.put((byte) NOTIFICATION_STATUS_LEN);
463            appParamBuf.putShort((short) getNotificationStatus());
464        }
465        if (getMasInstanceId() != INVALID_VALUE_PARAMETER) {
466            appParamBuf.put((byte) MAS_INSTANCE_ID);
467            appParamBuf.put((byte) MAS_INSTANCE_ID_LEN);
468            appParamBuf.put((byte) getMasInstanceId());
469        }
470        if (getParameterMask() != INVALID_VALUE_PARAMETER) {
471            appParamBuf.put((byte) PARAMETER_MASK);
472            appParamBuf.put((byte) PARAMETER_MASK_LEN);
473            appParamBuf.putInt((int) getParameterMask());
474        }
475        if (getFolderListingSize() != INVALID_VALUE_PARAMETER) {
476            appParamBuf.put((byte) FOLDER_LISTING_SIZE);
477            appParamBuf.put((byte) FOLDER_LISTING_SIZE_LEN);
478            appParamBuf.putShort((short) getFolderListingSize());
479        }
480        if (getMessageListingSize() != INVALID_VALUE_PARAMETER) {
481            appParamBuf.put((byte) MESSAGE_LISTING_SIZE);
482            appParamBuf.put((byte) MESSAGE_LISTING_SIZE_LEN);
483            appParamBuf.putShort((short) getMessageListingSize());
484        }
485        if (getSubjectLength() != INVALID_VALUE_PARAMETER) {
486            appParamBuf.put((byte) SUBJECT_LENGTH);
487            appParamBuf.put((byte) SUBJECT_LENGTH_LEN);
488            appParamBuf.put((byte) getSubjectLength());
489        }
490        if (getCharset() != INVALID_VALUE_PARAMETER) {
491            appParamBuf.put((byte) CHARSET);
492            appParamBuf.put((byte) CHARSET_LEN);
493            appParamBuf.put((byte) getCharset());
494        }
495        if (getFractionRequest() != INVALID_VALUE_PARAMETER) {
496            appParamBuf.put((byte) FRACTION_REQUEST);
497            appParamBuf.put((byte) FRACTION_REQUEST_LEN);
498            appParamBuf.put((byte) getFractionRequest());
499        }
500        if (getFractionDeliver() != INVALID_VALUE_PARAMETER) {
501            appParamBuf.put((byte) FRACTION_DELIVER);
502            appParamBuf.put((byte) FRACTION_DELIVER_LEN);
503            appParamBuf.put((byte) getFractionDeliver());
504        }
505        if (getStatusIndicator() != INVALID_VALUE_PARAMETER) {
506            appParamBuf.put((byte) STATUS_INDICATOR);
507            appParamBuf.put((byte) STATUS_INDICATOR_LEN);
508            appParamBuf.put((byte) getStatusIndicator());
509        }
510        if (getStatusValue() != INVALID_VALUE_PARAMETER) {
511            appParamBuf.put((byte) STATUS_VALUE);
512            appParamBuf.put((byte) STATUS_VALUE_LEN);
513            appParamBuf.put((byte) getStatusValue());
514        }
515        if (getMseTime() != INVALID_VALUE_PARAMETER) {
516            appParamBuf.put((byte) MSE_TIME);
517            appParamBuf.put((byte) getMseTimeString().getBytes("UTF-8").length);
518            appParamBuf.put(getMseTimeString().getBytes("UTF-8"));
519        }
520        // We need to reduce the length of the array to match the content
521        retBuf = Arrays.copyOfRange(appParamBuf.array(), appParamBuf.arrayOffset(),
522                                    appParamBuf.arrayOffset() + appParamBuf.position());
523        return retBuf;
524    }
525
526    public int getMaxListCount() {
527        return maxListCount;
528    }
529
530    public void setMaxListCount(int maxListCount) throws IllegalArgumentException {
531        if (maxListCount < 0 || maxListCount > 0xFFFF)
532            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
533        this.maxListCount = maxListCount;
534    }
535
536    public int getStartOffset() {
537        return startOffset;
538    }
539
540    public void setStartOffset(int startOffset) throws IllegalArgumentException {
541        if (startOffset < 0 || startOffset > 0xFFFF)
542            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
543        this.startOffset = startOffset;
544    }
545
546    public int getFilterMessageType() {
547        return filterMessageType;
548    }
549
550    public void setFilterMessageType(int filterMessageType) throws IllegalArgumentException {
551        if (filterMessageType < 0 || filterMessageType > 0x000F)
552            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x000F");
553        this.filterMessageType = filterMessageType;
554    }
555
556    public long getFilterPeriodBegin() {
557        return filterPeriodBegin;
558    }
559
560    public String getFilterPeriodBeginString() {
561        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
562        Date date = new Date(filterPeriodBegin);
563        return format.format(date); // Format to YYYYMMDDTHHMMSS local time
564    }
565
566    public void setFilterPeriodBegin(long filterPeriodBegin) {
567        this.filterPeriodBegin = filterPeriodBegin;
568    }
569
570    public void setFilterPeriodBegin(String filterPeriodBegin) throws ParseException {
571        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
572        Date date = format.parse(filterPeriodBegin);
573        this.filterPeriodBegin = date.getTime();
574    }
575
576    public long getFilterPeriodEnd() {
577        return filterPeriodEnd;
578    }
579
580    public String getFilterPeriodEndString() {
581        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
582        Date date = new Date(filterPeriodEnd);
583        return format.format(date); // Format to YYYYMMDDTHHMMSS local time
584    }
585
586    public void setFilterPeriodEnd(long filterPeriodEnd) {
587        this.filterPeriodEnd = filterPeriodEnd;
588    }
589
590    public void setFilterPeriodEnd(String filterPeriodEnd) throws ParseException {
591        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmss");
592        Date date = format.parse(filterPeriodEnd);
593        this.filterPeriodEnd = date.getTime();
594    }
595
596    public int getFilterReadStatus() {
597        return filterReadStatus;
598    }
599
600    public void setFilterReadStatus(int filterReadStatus) throws IllegalArgumentException {
601        if (filterReadStatus < 0 || filterReadStatus > 0x0002)
602            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
603        this.filterReadStatus = filterReadStatus;
604    }
605
606    public String getFilterRecipient() {
607        return filterRecipient;
608    }
609
610    public void setFilterRecipient(String filterRecipient) {
611        this.filterRecipient = filterRecipient;
612    }
613
614    public String getFilterOriginator() {
615        return filterOriginator;
616    }
617
618    public void setFilterOriginator(String filterOriginator) {
619        this.filterOriginator = filterOriginator;
620    }
621
622    public int getFilterPriority() {
623        return filterPriority;
624    }
625
626    public void setFilterPriority(int filterPriority) throws IllegalArgumentException {
627        if (filterPriority < 0 || filterPriority > 0x0002)
628            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0002");
629        this.filterPriority = filterPriority;
630    }
631
632    public int getAttachment() {
633        return attachment;
634    }
635
636    public void setAttachment(int attachment) throws IllegalArgumentException {
637        if (attachment < 0 || attachment > 0x0001)
638            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
639        this.attachment = attachment;
640    }
641
642    public int getTransparent() {
643        return transparent;
644    }
645
646    public void setTransparent(int transparent) throws IllegalArgumentException {
647        if (transparent < 0 || transparent > 0x0001)
648            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
649        this.transparent = transparent;
650    }
651
652    public int getRetry() {
653        return retry;
654    }
655
656    public void setRetry(int retry) throws IllegalArgumentException {
657        if (retry < 0 || retry > 0x0001)
658            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
659        this.retry = retry;
660    }
661
662    public int getNewMessage() {
663        return newMessage;
664    }
665
666    public void setNewMessage(int newMessage) throws IllegalArgumentException {
667        if (newMessage < 0 || newMessage > 0x0001)
668            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
669        this.newMessage = newMessage;
670    }
671
672    public int getNotificationStatus() {
673        return notificationStatus;
674    }
675
676    public void setNotificationStatus(int notificationStatus) throws IllegalArgumentException {
677        if (notificationStatus < 0 || notificationStatus > 0x0001)
678            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
679        this.notificationStatus = notificationStatus;
680    }
681
682    public int getMasInstanceId() {
683        return masInstanceId;
684    }
685
686    public void setMasInstanceId(int masInstanceId) {
687        if (masInstanceId < 0 || masInstanceId > 0x00FF)
688            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
689        this.masInstanceId = masInstanceId;
690    }
691
692    public long getParameterMask() {
693        return parameterMask;
694    }
695
696    public void setParameterMask(long parameterMask) {
697        if (parameterMask < 0 || parameterMask > 0xFFFFFFFFL)
698            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFFFFFF");
699        this.parameterMask = parameterMask;
700    }
701
702    public int getFolderListingSize() {
703        return folderListingSize;
704    }
705
706    public void setFolderListingSize(int folderListingSize) {
707        if (folderListingSize < 0 || folderListingSize > 0xFFFF)
708            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
709        this.folderListingSize = folderListingSize;
710    }
711
712    public int getMessageListingSize() {
713        return messageListingSize;
714    }
715
716    public void setMessageListingSize(int messageListingSize) {
717        if (messageListingSize < 0 || messageListingSize > 0xFFFF)
718            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0xFFFF");
719        this.messageListingSize = messageListingSize;
720    }
721
722    public int getSubjectLength() {
723        return subjectLength;
724    }
725
726    public void setSubjectLength(int subjectLength) {
727        if (subjectLength < 0 || subjectLength > 0xFF)
728            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x00FF");
729        this.subjectLength = subjectLength;
730    }
731
732    public int getCharset() {
733        return charset;
734    }
735
736    public void setCharset(int charset) {
737        if (charset < 0 || charset > 0x1)
738            throw new IllegalArgumentException("Out of range: " + charset + ", valid range is 0x0000 to 0x0001");
739        this.charset = charset;
740    }
741
742    public int getFractionRequest() {
743        return fractionRequest;
744    }
745
746    public void setFractionRequest(int fractionRequest) {
747        if (fractionRequest < 0 || fractionRequest > 0x1)
748            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
749        this.fractionRequest = fractionRequest;
750    }
751
752    public int getFractionDeliver() {
753        return fractionDeliver;
754    }
755
756    public void setFractionDeliver(int fractionDeliver) {
757        if (fractionDeliver < 0 || fractionDeliver > 0x1)
758            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
759        this.fractionDeliver = fractionDeliver;
760    }
761
762    public int getStatusIndicator() {
763        return statusIndicator;
764    }
765
766    public void setStatusIndicator(int statusIndicator) {
767        if (statusIndicator < 0 || statusIndicator > 0x1)
768            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
769        this.statusIndicator = statusIndicator;
770    }
771
772    public int getStatusValue() {
773        return statusValue;
774    }
775
776    public void setStatusValue(int statusValue) {
777        if (statusValue < 0 || statusValue > 0x1)
778            throw new IllegalArgumentException("Out of range, valid range is 0x0000 to 0x0001");
779        this.statusValue = statusValue;
780    }
781
782    public long getMseTime() {
783        return mseTime;
784    }
785
786    public String getMseTimeString() {
787        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
788        Date date = new Date(getMseTime());
789        return format.format(date); // Format to YYYYMMDDTHHMMSS±hhmm UTC time ± offset
790    }
791
792    public void setMseTime(long mseTime) {
793        this.mseTime = mseTime;
794    }
795
796    public void setMseTime(String mseTime) throws ParseException {
797        SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd'T'HHmmssZ");
798        Date date = format.parse(mseTime);
799        this.mseTime = date.getTime();
800    }
801}
802