blob: 87f5a3856ef021d85579a3e894fe8157fa15d0e1 [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.bluetooth.client.map;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothMasInstance;
import android.bluetooth.BluetoothSocket;
import android.bluetooth.SdpMasRecord;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.bluetooth.client.map.BluetoothMasRequestSetMessageStatus.StatusIndicator;
import android.bluetooth.client.map.utils.ObexTime;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.math.BigInteger;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import javax.obex.ObexTransport;
public class BluetoothMasClient {
private final static String TAG = "BluetoothMasClient";
private static final int SOCKET_CONNECTED = 10;
private static final int SOCKET_ERROR = 11;
/**
* Callback message sent when connection state changes
* <p>
* <code>arg1</code> is set to {@link #STATUS_OK} when connection is
* established successfully and {@link #STATUS_FAILED} when connection
* either failed or was disconnected (depends on request from application)
*
* @see #connect()
* @see #disconnect()
*/
public static final int EVENT_CONNECT = 1;
/**
* Callback message sent when MSE accepted update inbox request
*
* @see #updateInbox()
*/
public static final int EVENT_UPDATE_INBOX = 2;
/**
* Callback message sent when path is changed
* <p>
* <code>obj</code> is set to path currently set on MSE
*
* @see #setFolderRoot()
* @see #setFolderUp()
* @see #setFolderDown(String)
*/
public static final int EVENT_SET_PATH = 3;
/**
* Callback message sent when folder listing is received
* <p>
* <code>obj</code> contains ArrayList of sub-folder names
*
* @see #getFolderListing()
* @see #getFolderListing(int, int)
*/
public static final int EVENT_GET_FOLDER_LISTING = 4;
/**
* Callback message sent when folder listing size is received
* <p>
* <code>obj</code> contains number of items in folder listing
*
* @see #getFolderListingSize()
*/
public static final int EVENT_GET_FOLDER_LISTING_SIZE = 5;
/**
* Callback message sent when messages listing is received
* <p>
* <code>obj</code> contains ArrayList of {@link BluetoothMapBmessage}
*
* @see #getMessagesListing(String, int)
* @see #getMessagesListing(String, int, MessagesFilter, int)
* @see #getMessagesListing(String, int, MessagesFilter, int, int, int)
*/
public static final int EVENT_GET_MESSAGES_LISTING = 6;
/**
* Callback message sent when message is received
* <p>
* <code>obj</code> contains {@link BluetoothMapBmessage}
*
* @see #getMessage(String, CharsetType, boolean)
*/
public static final int EVENT_GET_MESSAGE = 7;
/**
* Callback message sent when message status is changed
*
* @see #setMessageDeletedStatus(String, boolean)
* @see #setMessageReadStatus(String, boolean)
*/
public static final int EVENT_SET_MESSAGE_STATUS = 8;
/**
* Callback message sent when message is pushed to MSE
* <p>
* <code>obj</code> contains handle of message as allocated by MSE
*
* @see #pushMessage(String, BluetoothMapBmessage, CharsetType)
* @see #pushMessage(String, BluetoothMapBmessage, CharsetType, boolean,
* boolean)
*/
public static final int EVENT_PUSH_MESSAGE = 9;
/**
* Callback message sent when notification status is changed
* <p>
* <code>obj</code> contains <code>1</code> if notifications are enabled and
* <code>0</code> otherwise
*
* @see #setNotificationRegistration(boolean)
*/
public static final int EVENT_SET_NOTIFICATION_REGISTRATION = 10;
/**
* Callback message sent when event report is received from MSE to MNS
* <p>
* <code>obj</code> contains {@link BluetoothMapEventReport}
*
* @see #setNotificationRegistration(boolean)
*/
public static final int EVENT_EVENT_REPORT = 11;
/**
* Callback message sent when messages listing size is received
* <p>
* <code>obj</code> contains number of items in messages listing
*
* @see #getMessagesListingSize()
*/
public static final int EVENT_GET_MESSAGES_LISTING_SIZE = 12;
/**
* Status for callback message when request is successful
*/
public static final int STATUS_OK = 0;
/**
* Status for callback message when request is not successful
*/
public static final int STATUS_FAILED = 1;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_DEFAULT = 0x00000000;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_SUBJECT = 0x00000001;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_DATETIME = 0x00000002;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_SENDER_NAME = 0x00000004;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_SENDER_ADDRESSING = 0x00000008;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_RECIPIENT_NAME = 0x00000010;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_RECIPIENT_ADDRESSING = 0x00000020;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_TYPE = 0x00000040;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_SIZE = 0x00000080;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_RECEPTION_STATUS = 0x00000100;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_TEXT = 0x00000200;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_ATTACHMENT_SIZE = 0x00000400;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_PRIORITY = 0x00000800;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_READ = 0x00001000;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_SENT = 0x00002000;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_PROTECTED = 0x00004000;
/**
* Constant corresponding to <code>ParameterMask</code> application
* parameter value in MAP specification
*/
public static final int PARAMETER_REPLYTO_ADDRESSING = 0x00008000;
public enum ConnectionState {
DISCONNECTED, CONNECTING, CONNECTED, DISCONNECTING;
}
public enum CharsetType {
NATIVE, UTF_8;
}
/** device associated with client */
private final BluetoothDevice mDevice;
/** MAS instance associated with client */
private final SdpMasRecord mMas;
/** callback handler to application */
private final Handler mCallback;
private ConnectionState mConnectionState = ConnectionState.DISCONNECTED;
private boolean mNotificationEnabled = false;
private SocketConnectThread mConnectThread = null;
private ObexTransport mObexTransport = null;
private BluetoothMasObexClientSession mObexSession = null;
private SessionHandler mSessionHandler = null;
private BluetoothMnsService mMnsService = null;
private ArrayDeque<String> mPath = null;
private static class SessionHandler extends Handler {
private final WeakReference<BluetoothMasClient> mClient;
public SessionHandler(BluetoothMasClient client) {
super();
mClient = new WeakReference<BluetoothMasClient>(client);
}
@Override
public void handleMessage(Message msg) {
BluetoothMasClient client = mClient.get();
if (client == null) {
return;
}
Log.v(TAG, "handleMessage "+msg.what);
switch (msg.what) {
case SOCKET_ERROR:
client.mConnectThread = null;
client.sendToClient(EVENT_CONNECT, false);
break;
case SOCKET_CONNECTED:
client.mConnectThread = null;
client.mObexTransport = (ObexTransport) msg.obj;
client.mObexSession = new BluetoothMasObexClientSession(client.mObexTransport,
client.mSessionHandler);
client.mObexSession.start();
break;
case BluetoothMasObexClientSession.MSG_OBEX_CONNECTED:
client.mPath.clear(); // we're in root after connected
client.mConnectionState = ConnectionState.CONNECTED;
client.sendToClient(EVENT_CONNECT, true);
break;
case BluetoothMasObexClientSession.MSG_OBEX_DISCONNECTED:
client.mConnectionState = ConnectionState.DISCONNECTED;
client.mNotificationEnabled = false;
client.mObexSession = null;
client.sendToClient(EVENT_CONNECT, false);
break;
case BluetoothMasObexClientSession.MSG_REQUEST_COMPLETED:
BluetoothMasRequest request = (BluetoothMasRequest) msg.obj;
int status = request.isSuccess() ? STATUS_OK : STATUS_FAILED;
Log.v(TAG, "MSG_REQUEST_COMPLETED (" + status + ") for "
+ request.getClass().getName());
if (request instanceof BluetoothMasRequestUpdateInbox) {
client.sendToClient(EVENT_UPDATE_INBOX, request.isSuccess());
} else if (request instanceof BluetoothMasRequestSetPath) {
if (request.isSuccess()) {
BluetoothMasRequestSetPath req = (BluetoothMasRequestSetPath) request;
switch (req.mDir) {
case UP:
if (client.mPath.size() > 0) {
client.mPath.removeLast();
}
break;
case ROOT:
client.mPath.clear();
break;
case DOWN:
client.mPath.addLast(req.mName);
break;
}
}
client.sendToClient(EVENT_SET_PATH, request.isSuccess(),
client.getCurrentPath());
} else if (request instanceof BluetoothMasRequestGetFolderListing) {
BluetoothMasRequestGetFolderListing req = (BluetoothMasRequestGetFolderListing) request;
ArrayList<String> folders = req.getList();
client.sendToClient(EVENT_GET_FOLDER_LISTING, request.isSuccess(), folders);
} else if (request instanceof BluetoothMasRequestGetFolderListingSize) {
int size = ((BluetoothMasRequestGetFolderListingSize) request).getSize();
client.sendToClient(EVENT_GET_FOLDER_LISTING_SIZE, request.isSuccess(),
size);
} else if (request instanceof BluetoothMasRequestGetMessagesListing) {
BluetoothMasRequestGetMessagesListing req = (BluetoothMasRequestGetMessagesListing) request;
ArrayList<BluetoothMapMessage> msgs = req.getList();
client.sendToClient(EVENT_GET_MESSAGES_LISTING, request.isSuccess(), msgs);
} else if (request instanceof BluetoothMasRequestGetMessage) {
BluetoothMasRequestGetMessage req = (BluetoothMasRequestGetMessage) request;
BluetoothMapBmessage bmsg = req.getMessage();
client.sendToClient(EVENT_GET_MESSAGE, request.isSuccess(), bmsg);
} else if (request instanceof BluetoothMasRequestSetMessageStatus) {
client.sendToClient(EVENT_SET_MESSAGE_STATUS, request.isSuccess());
} else if (request instanceof BluetoothMasRequestPushMessage) {
BluetoothMasRequestPushMessage req = (BluetoothMasRequestPushMessage) request;
String handle = req.getMsgHandle();
client.sendToClient(EVENT_PUSH_MESSAGE, request.isSuccess(), handle);
} else if (request instanceof BluetoothMasRequestSetNotificationRegistration) {
BluetoothMasRequestSetNotificationRegistration req = (BluetoothMasRequestSetNotificationRegistration) request;
client.mNotificationEnabled = req.isSuccess() ? req.getStatus()
: client.mNotificationEnabled;
client.sendToClient(EVENT_SET_NOTIFICATION_REGISTRATION,
request.isSuccess(),
client.mNotificationEnabled ? 1 : 0);
} else if (request instanceof BluetoothMasRequestGetMessagesListingSize) {
int size = ((BluetoothMasRequestGetMessagesListingSize) request).getSize();
client.sendToClient(EVENT_GET_MESSAGES_LISTING_SIZE, request.isSuccess(),
size);
}
break;
case BluetoothMnsService.EVENT_REPORT:
/* pass event report directly to app */
client.sendToClient(EVENT_EVENT_REPORT, true, msg.obj);
break;
}
}
}
private void sendToClient(int event, boolean success) {
sendToClient(event, success, null);
}
private void sendToClient(int event, boolean success, int param) {
sendToClient(event, success, Integer.valueOf(param));
}
private void sendToClient(int event, boolean success, Object param) {
// Send event, status and notification state for both sucess and failure case.
mCallback.obtainMessage(event, success ? STATUS_OK : STATUS_FAILED, mMas.getMasInstanceId(),
param).sendToTarget();
}
private class SocketConnectThread extends Thread {
private BluetoothSocket socket = null;
public SocketConnectThread() {
super("SocketConnectThread");
}
@Override
public void run() {
try {
socket = mDevice.createRfcommSocket(mMas.getRfcommCannelNumber());
socket.connect();
BluetoothMapRfcommTransport transport;
transport = new BluetoothMapRfcommTransport(socket);
mSessionHandler.obtainMessage(SOCKET_CONNECTED, transport).sendToTarget();
} catch (IOException e) {
Log.e(TAG, "Error when creating/connecting socket", e);
closeSocket();
mSessionHandler.obtainMessage(SOCKET_ERROR).sendToTarget();
}
}
@Override
public void interrupt() {
closeSocket();
}
private void closeSocket() {
try {
if (socket != null) {
socket.close();
}
} catch (IOException e) {
Log.e(TAG, "Error when closing socket", e);
}
}
}
/**
* Object representation of filters to be applied on message listing
*
* @see #getMessagesListing(String, int, MessagesFilter, int)
* @see #getMessagesListing(String, int, MessagesFilter, int, int, int)
*/
public static final class MessagesFilter {
public final static byte MESSAGE_TYPE_ALL = 0x00;
public final static byte MESSAGE_TYPE_SMS_GSM = 0x01;
public final static byte MESSAGE_TYPE_SMS_CDMA = 0x02;
public final static byte MESSAGE_TYPE_EMAIL = 0x04;
public final static byte MESSAGE_TYPE_MMS = 0x08;
public final static byte READ_STATUS_ANY = 0x00;
public final static byte READ_STATUS_UNREAD = 0x01;
public final static byte READ_STATUS_READ = 0x02;
public final static byte PRIORITY_ANY = 0x00;
public final static byte PRIORITY_HIGH = 0x01;
public final static byte PRIORITY_NON_HIGH = 0x02;
byte messageType = MESSAGE_TYPE_ALL;
String periodBegin = null;
String periodEnd = null;
byte readStatus = READ_STATUS_ANY;
String recipient = null;
String originator = null;
byte priority = PRIORITY_ANY;
public MessagesFilter() {
}
public void setMessageType(byte filter) {
messageType = filter;
}
public void setPeriod(Date filterBegin, Date filterEnd) {
//Handle possible NPE for obexTime constructor utility
if(filterBegin != null )
periodBegin = (new ObexTime(filterBegin)).toString();
if(filterEnd != null)
periodEnd = (new ObexTime(filterEnd)).toString();
}
public void setReadStatus(byte readfilter) {
readStatus = readfilter;
}
public void setRecipient(String filter) {
if ("".equals(filter)) {
recipient = null;
} else {
recipient = filter;
}
}
public void setOriginator(String filter) {
if ("".equals(filter)) {
originator = null;
} else {
originator = filter;
}
}
public void setPriority(byte filter) {
priority = filter;
}
}
/**
* Constructs client object to communicate with single MAS instance on MSE
*
* @param device {@link BluetoothDevice} corresponding to remote device
* acting as MSE
* @param mas {@link BluetoothMasInstance} object describing MAS instance on
* remote device
* @param callback {@link Handler} object to which callback messages will be
* sent Each message will have <code>arg1</code> set to either
* {@link #STATUS_OK} or {@link #STATUS_FAILED} and
* <code>arg2</code> to MAS instance ID. <code>obj</code> in
* message is event specific.
*/
public BluetoothMasClient(BluetoothDevice device, SdpMasRecord mas,
Handler callback) {
mDevice = device;
mMas = mas;
mCallback = callback;
mPath = new ArrayDeque<String>();
}
/**
* Retrieves MAS instance data associated with client
*
* @return instance data object
*/
public SdpMasRecord getInstanceData() {
return mMas;
}
/**
* Connects to MAS instance
* <p>
* Upon completion callback handler will receive {@link #EVENT_CONNECT}
*/
public void connect() {
if (mSessionHandler == null) {
mSessionHandler = new SessionHandler(this);
}
if (mConnectThread == null && mObexSession == null) {
mConnectionState = ConnectionState.CONNECTING;
mConnectThread = new SocketConnectThread();
mConnectThread.start();
}
}
/**
* Disconnects from MAS instance
* <p>
* Upon completion callback handler will receive {@link #EVENT_CONNECT}
*/
public void disconnect() {
if (mConnectThread == null && mObexSession == null) {
return;
}
mConnectionState = ConnectionState.DISCONNECTING;
if (mConnectThread != null) {
mConnectThread.interrupt();
}
if (mObexSession != null) {
mObexSession.stop();
}
}
@Override
public void finalize() {
disconnect();
}
/**
* Gets current connection state
*
* @return current connection state
* @see ConnectionState
*/
public ConnectionState getState() {
return mConnectionState;
}
private boolean enableNotifications() {
Log.v(TAG, "enableNotifications()");
if (mMnsService == null) {
mMnsService = new BluetoothMnsService();
}
mMnsService.registerCallback(mMas.getMasInstanceId(), mSessionHandler);
BluetoothMasRequest request = new BluetoothMasRequestSetNotificationRegistration(true);
return mObexSession.makeRequest(request);
}
private boolean disableNotifications() {
Log.v(TAG, "enableNotifications()");
if (mMnsService != null) {
mMnsService.unregisterCallback(mMas.getMasInstanceId());
}
mMnsService = null;
BluetoothMasRequest request = new BluetoothMasRequestSetNotificationRegistration(false);
return mObexSession.makeRequest(request);
}
/**
* Sets state of notifications for MAS instance
* <p>
* Once notifications are enabled, callback handler will receive
* {@link #EVENT_EVENT_REPORT} when new notification is received
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_SET_NOTIFICATION_REGISTRATION}
*
* @param status <code>true</code> if notifications shall be enabled,
* <code>false</code> otherwise
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean setNotificationRegistration(boolean status) {
if (mObexSession == null) {
return false;
}
if (status) {
return enableNotifications();
} else {
return disableNotifications();
}
}
/**
* Gets current state of notifications for MAS instance
*
* @return <code>true</code> if notifications are enabled,
* <code>false</code> otherwise
*/
public boolean getNotificationRegistration() {
return mNotificationEnabled;
}
/**
* Goes back to root of folder hierarchy
* <p>
* Upon completion callback handler will receive {@link #EVENT_SET_PATH}
*
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean setFolderRoot() {
if (mObexSession == null) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestSetPath(true);
return mObexSession.makeRequest(request);
}
/**
* Goes back to parent folder in folder hierarchy
* <p>
* Upon completion callback handler will receive {@link #EVENT_SET_PATH}
*
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean setFolderUp() {
if (mObexSession == null) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestSetPath(false);
return mObexSession.makeRequest(request);
}
/**
* Goes down to specified sub-folder in folder hierarchy
* <p>
* Upon completion callback handler will receive {@link #EVENT_SET_PATH}
*
* @param name name of sub-folder
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean setFolderDown(String name) {
if (mObexSession == null) {
return false;
}
if (name == null || name.isEmpty() || name.contains("/")) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestSetPath(name);
return mObexSession.makeRequest(request);
}
/**
* Gets current path in folder hierarchy
*
* @return current path
*/
public String getCurrentPath() {
if (mPath.size() == 0) {
return "";
}
Iterator<String> iter = mPath.iterator();
StringBuilder sb = new StringBuilder(iter.next());
while (iter.hasNext()) {
sb.append("/").append(iter.next());
}
return sb.toString();
}
/**
* Gets list of sub-folders in current folder
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_GET_FOLDER_LISTING}
*
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean getFolderListing() {
return getFolderListing((short) 0, (short) 0);
}
/**
* Gets list of sub-folders in current folder
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_GET_FOLDER_LISTING}
*
* @param maxListCount maximum number of items returned or <code>0</code>
* for default value
* @param listStartOffset index of first item returned or <code>0</code> for
* default value
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
* @throws IllegalArgumentException if either maxListCount or
* listStartOffset are outside allowed range [0..65535]
*/
public boolean getFolderListing(int maxListCount, int listStartOffset) {
if (mObexSession == null) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestGetFolderListing(maxListCount,
listStartOffset);
return mObexSession.makeRequest(request);
}
/**
* Gets number of sub-folders in current folder
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_GET_FOLDER_LISTING_SIZE}
*
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean getFolderListingSize() {
if (mObexSession == null) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestGetFolderListingSize();
return mObexSession.makeRequest(request);
}
/**
* Gets list of messages in specified sub-folder
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_GET_MESSAGES_LISTING}
*
* @param folder name of sub-folder or <code>null</code> for current folder
* @param parameters bit-mask specifying requested parameters in listing or
* <code>0</code> for default value
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean getMessagesListing(String folder, int parameters) {
return getMessagesListing(folder, parameters, null, (byte) 0, 0, 0);
}
/**
* Gets list of messages in specified sub-folder
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_GET_MESSAGES_LISTING}
*
* @param folder name of sub-folder or <code>null</code> for current folder
* @param parameters corresponds to <code>ParameterMask</code> application
* parameter in MAP specification
* @param filter {@link MessagesFilter} object describing filters to be
* applied on listing by MSE
* @param subjectLength maximum length of message subject in returned
* listing or <code>0</code> for default value
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
* @throws IllegalArgumentException if subjectLength is outside allowed
* range [0..255]
*/
public boolean getMessagesListing(String folder, int parameters, MessagesFilter filter,
int subjectLength) {
return getMessagesListing(folder, parameters, filter, subjectLength, 0, 0);
}
/**
* Gets list of messages in specified sub-folder
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_GET_MESSAGES_LISTING}
*
* @param folder name of sub-folder or <code>null</code> for current folder
* @param parameters corresponds to <code>ParameterMask</code> application
* parameter in MAP specification
* @param filter {@link MessagesFilter} object describing filters to be
* applied on listing by MSE
* @param subjectLength maximum length of message subject in returned
* listing or <code>0</code> for default value
* @param maxListCount maximum number of items returned or <code>0</code>
* for default value
* @param listStartOffset index of first item returned or <code>0</code> for
* default value
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
* @throws IllegalArgumentException if subjectLength is outside allowed
* range [0..255] or either maxListCount or listStartOffset are
* outside allowed range [0..65535]
*/
public boolean getMessagesListing(String folder, int parameters, MessagesFilter filter,
int subjectLength, int maxListCount, int listStartOffset) {
if (mObexSession == null) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestGetMessagesListing(folder,
parameters, filter, subjectLength, maxListCount, listStartOffset);
return mObexSession.makeRequest(request);
}
/**
* Gets number of messages in current folder
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_GET_MESSAGES_LISTING_SIZE}
*
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean getMessagesListingSize() {
if (mObexSession == null) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestGetMessagesListingSize();
return mObexSession.makeRequest(request);
}
/**
* Retrieves message from MSE
* <p>
* Upon completion callback handler will receive {@link #EVENT_GET_MESSAGE}
*
* @param handle handle of message to retrieve
* @param charset {@link CharsetType} object corresponding to
* <code>Charset</code> application parameter in MAP
* specification
* @param attachment corresponds to <code>Attachment</code> application
* parameter in MAP specification
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean getMessage(String handle, boolean attachment) {
if (mObexSession == null) {
return false;
}
try {
/* just to validate */
new BigInteger(handle, 16);
} catch (NumberFormatException e) {
return false;
}
// Since we support only text messaging via Bluetooth, it is OK to restrict the requests to
// force conversion to UTF-8.
BluetoothMasRequest request =
new BluetoothMasRequestGetMessage(handle, CharsetType.UTF_8, attachment);
return mObexSession.makeRequest(request);
}
/**
* Sets read status of message on MSE
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_SET_MESSAGE_STATUS}
*
* @param handle handle of message
* @param read <code>true</code> for "read", <code>false</code> for "unread"
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean setMessageReadStatus(String handle, boolean read) {
if (mObexSession == null) {
return false;
}
try {
/* just to validate */
new BigInteger(handle, 16);
} catch (NumberFormatException e) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestSetMessageStatus(handle,
StatusIndicator.READ, read);
return mObexSession.makeRequest(request);
}
/**
* Sets deleted status of message on MSE
* <p>
* Upon completion callback handler will receive
* {@link #EVENT_SET_MESSAGE_STATUS}
*
* @param handle handle of message
* @param deleted <code>true</code> for "deleted", <code>false</code> for
* "undeleted"
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean setMessageDeletedStatus(String handle, boolean deleted) {
if (mObexSession == null) {
return false;
}
try {
/* just to validate */
new BigInteger(handle, 16);
} catch (NumberFormatException e) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestSetMessageStatus(handle,
StatusIndicator.DELETED, deleted);
return mObexSession.makeRequest(request);
}
/**
* Pushes new message to MSE
* <p>
* Upon completion callback handler will receive {@link #EVENT_PUSH_MESSAGE}
*
* @param folder name of sub-folder to push to or <code>null</code> for
* current folder
* @param charset {@link CharsetType} object corresponding to
* <code>Charset</code> application parameter in MAP
* specification
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean pushMessage(String folder, BluetoothMapBmessage bmsg, CharsetType charset) {
return pushMessage(folder, bmsg, charset, false, false);
}
/**
* Pushes new message to MSE
* <p>
* Upon completion callback handler will receive {@link #EVENT_PUSH_MESSAGE}
*
* @param folder name of sub-folder to push to or <code>null</code> for
* current folder
* @param bmsg {@link BluetoothMapBmessage} object representing message to
* be pushed
* @param charset {@link CharsetType} object corresponding to
* <code>Charset</code> application parameter in MAP
* specification
* @param transparent corresponds to <code>Transparent</code> application
* parameter in MAP specification
* @param retry corresponds to <code>Transparent</code> application
* parameter in MAP specification
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean pushMessage(String folder, BluetoothMapBmessage bmsg, CharsetType charset,
boolean transparent, boolean retry) {
if (mObexSession == null) {
return false;
}
String bmsgString = BluetoothMapBmessageBuilder.createBmessage(bmsg);
BluetoothMasRequest request =
new BluetoothMasRequestPushMessage(folder, bmsgString, charset, transparent, retry);
return mObexSession.makeRequest(request);
}
/**
* Requests MSE to initiate ubdate of inbox
* <p>
* Upon completion callback handler will receive {@link #EVENT_UPDATE_INBOX}
*
* @return <code>true</code> if request has been sent, <code>false</code>
* otherwise
*/
public boolean updateInbox() {
if (mObexSession == null) {
return false;
}
BluetoothMasRequest request = new BluetoothMasRequestUpdateInbox();
return mObexSession.makeRequest(request);
}
}