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