BluetoothMapObexServer.java revision 165d7facb456fe3c15a07692a70723fda1ad135f
1/* 2* Copyright (C) 2015 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 android.content.ContentProviderClient; 18import android.content.ContentResolver; 19import android.content.Context; 20import android.database.Cursor; 21import android.net.Uri; 22import android.os.Bundle; 23import android.os.Handler; 24import android.os.Message; 25import android.os.ParcelUuid; 26import android.os.RemoteException; 27import android.text.format.DateUtils; 28import android.util.Log; 29 30import com.android.bluetooth.SignedLongLong; 31import com.android.bluetooth.map.BluetoothMapUtils.TYPE; 32import com.android.bluetooth.map.BluetoothMapMasInstance; 33import com.android.bluetooth.mapapi.BluetoothMapContract; 34 35import java.io.IOException; 36import java.io.InputStream; 37import java.io.OutputStream; 38import java.text.ParseException; 39import java.util.Arrays; 40import java.util.Calendar; 41 42import javax.obex.HeaderSet; 43import javax.obex.Operation; 44import javax.obex.ResponseCodes; 45import javax.obex.ServerRequestHandler; 46 47 48public class BluetoothMapObexServer extends ServerRequestHandler { 49 50 private static final String TAG = "BluetoothMapObexServer"; 51 52 private static final boolean D = BluetoothMapService.DEBUG; 53 private static final boolean V = BluetoothMapService.VERBOSE; 54 55 private static final int UUID_LENGTH = 16; 56 57 private static final long PROVIDER_ANR_TIMEOUT = 20 * DateUtils.SECOND_IN_MILLIS; 58 59 /* OBEX header and value used to detect clients that support threadId in the message listing. */ 60 private static final int THREADED_MAIL_HEADER_ID = 0xFA; 61 private static final long THREAD_MAIL_KEY = 0x534c5349; 62 63 // 128 bit UUID for MAP 64 private static final byte[] MAP_TARGET = new byte[] { 65 (byte)0xBB, (byte)0x58, (byte)0x2B, (byte)0x40, 66 (byte)0x42, (byte)0x0C, (byte)0x11, (byte)0xDB, 67 (byte)0xB0, (byte)0xDE, (byte)0x08, (byte)0x00, 68 (byte)0x20, (byte)0x0C, (byte)0x9A, (byte)0x66 69 }; 70 public static final ParcelUuid MAP = 71 ParcelUuid.fromString("00001134-0000-1000-8000-00805F9B34FB"); 72 public static final ParcelUuid MNS = 73 ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB"); 74 public static final ParcelUuid MAS = 75 ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB"); 76 /* Message types */ 77 private static final String TYPE_GET_FOLDER_LISTING = "x-obex/folder-listing"; 78 private static final String TYPE_GET_MESSAGE_LISTING = "x-bt/MAP-msg-listing"; 79 private static final String TYPE_GET_CONVO_LISTING = "x-bt/MAP-convo-listing"; 80 private static final String TYPE_MESSAGE = "x-bt/message"; 81 private static final String TYPE_SET_MESSAGE_STATUS = "x-bt/messageStatus"; 82 private static final String TYPE_SET_NOTIFICATION_REGISTRATION 83 = "x-bt/MAP-NotificationRegistration"; 84 private static final String TYPE_MESSAGE_UPDATE = "x-bt/MAP-messageUpdate"; 85 private static final String TYPE_GET_MAS_INSTANCE_INFORMATION 86 = "x-bt/MASInstanceInformation"; 87 private static final String TYPE_SET_OWNER_STATUS = "x-bt/participant"; 88 private static final String TYPE_SET_NOTIFICATION_FILTER 89 = "x-bt/MAP-notification-filter"; 90 91 private static final int MAS_INSTANCE_INFORMATION_LENGTH = 200; 92 93 private BluetoothMapFolderElement mCurrentFolder; 94 private BluetoothMapContentObserver mObserver = null; 95 private Handler mCallback = null; 96 private Context mContext; 97 private boolean mIsAborted = false; 98 BluetoothMapContent mOutContent; 99 private String mBaseUriString = null; 100 private long mAccountId = 0; 101 private BluetoothMapAccountItem mAccount = null; 102 private Uri mEmailFolderUri = null; 103 private int mMasId = 0; 104 private BluetoothMapMasInstance mMasInstance; // TODO: change to interface? 105 // updated during connect if remote has alternative value 106 private int mRemoteFeatureMask = BluetoothMapUtils.MAP_FEATURE_DEFAULT_BITMASK; 107 private boolean mEnableSmsMms = false; 108 private boolean mThreadIdSupport = false; // true if peer supports threadId in msg listing 109 // Defaults message version is 1.0 but 1.1+ if feature bit is set 110 private String mMessageVersion = BluetoothMapUtils.MAP_V10_STR; 111 private String mAuthority; 112 private ContentResolver mResolver; 113 private ContentProviderClient mProviderClient = null; 114 115 public BluetoothMapObexServer(Handler callback, 116 Context context, 117 BluetoothMapContentObserver observer, 118 BluetoothMapMasInstance mas, 119 BluetoothMapAccountItem account, 120 boolean enableSmsMms) throws RemoteException { 121 super(); 122 mCallback = callback; 123 mContext = context; 124 mObserver = observer; 125 mEnableSmsMms = enableSmsMms; 126 mAccount = account; 127 mMasId = mas.getMasId(); 128 mMasInstance = mas; 129 mRemoteFeatureMask = mMasInstance.getRemoteFeatureMask(); 130 131 if(account != null && account.getProviderAuthority() != null) { 132 mAccountId = account.getAccountId(); 133 mAuthority = account.getProviderAuthority(); 134 mResolver = mContext.getContentResolver(); 135 if (D) Log.d(TAG, "BluetoothMapObexServer(): accountId=" + mAccountId); 136 mBaseUriString = account.mBase_uri + "/"; 137 if (D) Log.d(TAG, "BluetoothMapObexServer(): baseUri=" + mBaseUriString); 138 if (account.getType() == TYPE.EMAIL) { 139 mEmailFolderUri = BluetoothMapContract.buildFolderUri(mAuthority, 140 Long.toString(mAccountId)); 141 if (D) Log.d(TAG, "BluetoothMapObexServer(): mEmailFolderUri=" + mEmailFolderUri); 142 } 143 mProviderClient = acquireUnstableContentProviderOrThrow(); 144 } 145 146 buildFolderStructure(); /* Build the default folder structure, and set 147 mCurrentFolder to root folder */ 148 mObserver.setFolderStructure(mCurrentFolder.getRoot()); 149 150 mOutContent = new BluetoothMapContent(mContext, mAccount, mMasInstance); 151 152 } 153 154 /** 155 * 156 */ 157 private ContentProviderClient acquireUnstableContentProviderOrThrow() throws RemoteException{ 158 ContentProviderClient providerClient = 159 mResolver.acquireUnstableContentProviderClient(mAuthority); 160 if (providerClient == null) { 161 throw new RemoteException("Failed to acquire provider for " + mAuthority); 162 } 163 providerClient.setDetectNotResponding(PROVIDER_ANR_TIMEOUT); 164 return providerClient; 165 } 166 167 /** 168 * Build the default minimal folder structure, as defined in the MAP specification. 169 */ 170 private void buildFolderStructure() throws RemoteException{ 171 mCurrentFolder = new BluetoothMapFolderElement("root", null);//This will be the root element 172 mCurrentFolder.setHasSmsMmsContent(mEnableSmsMms); 173 boolean hasIM = false; 174 boolean hasEmail = false; 175 if (mAccount != null) { 176 if (mAccount.getType() == TYPE.IM) 177 hasIM = true; 178 if( mAccount.getType() == TYPE.EMAIL) 179 hasEmail = true; 180 } 181 mCurrentFolder.setHasImContent(hasIM); 182 mCurrentFolder.setHasEmailContent(hasEmail); 183 184 BluetoothMapFolderElement tmpFolder; 185 tmpFolder = mCurrentFolder.addFolder("telecom"); // root/telecom 186 tmpFolder.setHasSmsMmsContent(mEnableSmsMms); 187 tmpFolder.setHasImContent(hasIM); 188 tmpFolder.setHasEmailContent(hasEmail); 189 190 tmpFolder = tmpFolder.addFolder("msg"); // root/telecom/msg 191 tmpFolder.setHasSmsMmsContent(mEnableSmsMms); 192 tmpFolder.setHasImContent(hasIM); 193 tmpFolder.setHasEmailContent(hasEmail); 194 195 // Add the mandatory folders 196 addBaseFolders(tmpFolder); 197 if(mEnableSmsMms) { 198 addSmsMmsFolders(tmpFolder); 199 } 200 if(hasEmail) { 201 if (D) Log.d(TAG, "buildFolderStructure(): " + mEmailFolderUri.toString()); 202 addEmailFolders(tmpFolder); 203 } 204 if (hasIM) { 205 addImFolders(tmpFolder); 206 } 207 } 208 209 /** 210 * Add 211 * @param root 212 */ 213 private void addBaseFolders(BluetoothMapFolderElement root) { 214 root.addFolder(BluetoothMapContract.FOLDER_NAME_INBOX); // root/telecom/msg/inbox 215 root.addFolder(BluetoothMapContract.FOLDER_NAME_OUTBOX); 216 root.addFolder(BluetoothMapContract.FOLDER_NAME_SENT); 217 root.addFolder(BluetoothMapContract.FOLDER_NAME_DELETED); 218 } 219 220 /** 221 * Add 222 * @param root 223 */ 224 private void addSmsMmsFolders(BluetoothMapFolderElement root) { 225 root.addSmsMmsFolder(BluetoothMapContract.FOLDER_NAME_INBOX); // root/telecom/msg/inbox 226 root.addSmsMmsFolder(BluetoothMapContract.FOLDER_NAME_OUTBOX); 227 root.addSmsMmsFolder(BluetoothMapContract.FOLDER_NAME_SENT); 228 root.addSmsMmsFolder(BluetoothMapContract.FOLDER_NAME_DELETED); 229 root.addSmsMmsFolder(BluetoothMapContract.FOLDER_NAME_DRAFT); 230 } 231 232 233 private void addImFolders(BluetoothMapFolderElement root) throws RemoteException { 234 // Select all parent folders 235 root.addImFolder(BluetoothMapContract.FOLDER_NAME_INBOX, 236 BluetoothMapContract.FOLDER_ID_INBOX); // root/telecom/msg/inbox 237 root.addImFolder(BluetoothMapContract.FOLDER_NAME_OUTBOX, 238 BluetoothMapContract.FOLDER_ID_OUTBOX); 239 root.addImFolder(BluetoothMapContract.FOLDER_NAME_SENT, 240 BluetoothMapContract.FOLDER_ID_SENT); 241 root.addImFolder(BluetoothMapContract.FOLDER_NAME_DELETED, 242 BluetoothMapContract.FOLDER_ID_DELETED); 243 root.addImFolder(BluetoothMapContract.FOLDER_NAME_DRAFT, 244 BluetoothMapContract.FOLDER_ID_DRAFT); 245 } 246 247 /** 248 * Recursively adds folders based on the folders in the email content provider. 249 * Add a content observer? - to refresh the folder list if any change occurs. 250 * Consider simply deleting the entire table, and then rebuild using 251 * buildFolderStructure() 252 * WARNING: there is no way to notify the client about these changes - hence 253 * we need to either keep the folder structure constant, disconnect or fail anything 254 * referring to currentFolder. 255 * It is unclear what to set as current folder to be able to go one level up... 256 * The best solution would be to keep the folder structure constant during a connection. 257 * @param folder the parent folder to which subFolders needs to be added. The 258 * folder.getFolderId() will be used to query sub-folders. 259 * Use a parentFolder with id -1 to get all folders from root. 260 */ 261 private void addEmailFolders(BluetoothMapFolderElement parentFolder) throws RemoteException { 262 // Select all parent folders 263 BluetoothMapFolderElement newFolder; 264 265 String where = BluetoothMapContract.FolderColumns.PARENT_FOLDER_ID + 266 " = " + parentFolder.getFolderId(); 267 Cursor c = mProviderClient.query(mEmailFolderUri, 268 BluetoothMapContract.BT_FOLDER_PROJECTION, where, null, null); 269 try { 270 if (c != null) { 271 c.moveToPosition(-1); 272 while (c.moveToNext()) { 273 String name = c.getString(c.getColumnIndex( 274 BluetoothMapContract.FolderColumns.NAME)); 275 long id = c.getLong(c.getColumnIndex(BluetoothMapContract.FolderColumns._ID)); 276 newFolder = parentFolder.addEmailFolder(name, id); 277 addEmailFolders(newFolder); // Use recursion to add any sub folders 278 } 279 280 } else { 281 if (D) Log.d(TAG, "addEmailFolders(): no elements found"); 282 } 283 } finally { 284 if (c != null) c.close(); 285 } 286 } 287 288 @Override 289 public boolean isSrmSupported() { 290 // TODO: Update based on the transport used 291 return true; 292 } 293 294 public int getRemoteFeatureMask() { 295 return mRemoteFeatureMask; 296 } 297 298 public void setRemoteFeatureMask(int mRemoteFeatureMask) { 299 if(D) Log.d(TAG, "setRemoteFeatureMask() " + Integer.toHexString(mRemoteFeatureMask)); 300 this.mRemoteFeatureMask = mRemoteFeatureMask; 301 this.mOutContent.setRemoteFeatureMask(mRemoteFeatureMask); 302 } 303 304 @Override 305 public int onConnect(final HeaderSet request, HeaderSet reply) { 306 if (D) Log.d(TAG, "onConnect():"); 307 if (V) logHeader(request); 308 mThreadIdSupport = false; // Always assume not supported at new connect. 309 mMessageVersion = BluetoothMapUtils.MAP_V10_STR;//always assume version 1.0 to start with 310 notifyUpdateWakeLock(); 311 Long threadedMailKey = null; 312 try { 313 byte[] uuid = (byte[])request.getHeader(HeaderSet.TARGET); 314 threadedMailKey = (Long)request.getHeader(THREADED_MAIL_HEADER_ID); 315 if (uuid == null) { 316 return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; 317 } 318 if (D) Log.d(TAG, "onConnect(): uuid=" + Arrays.toString(uuid)); 319 320 if (uuid.length != UUID_LENGTH) { 321 Log.w(TAG, "Wrong UUID length"); 322 return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; 323 } 324 for (int i = 0; i < UUID_LENGTH; i++) { 325 if (uuid[i] != MAP_TARGET[i]) { 326 Log.w(TAG, "Wrong UUID"); 327 return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; 328 } 329 } 330 reply.setHeader(HeaderSet.WHO, uuid); 331 } catch (IOException e) { 332 Log.e(TAG,"Exception during onConnect:", e); 333 return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 334 } 335 336 try { 337 byte[] remote = (byte[])request.getHeader(HeaderSet.WHO); 338 if (remote != null) { 339 if (D) Log.d(TAG, "onConnect(): remote=" + Arrays.toString(remote)); 340 reply.setHeader(HeaderSet.TARGET, remote); 341 } 342 if(threadedMailKey != null && threadedMailKey.longValue() == THREAD_MAIL_KEY) 343 { 344 /* If the client provides the correct key we enable threaded e-mail support 345 * and reply to the client that we support the requested feature. 346 * This is currently an Android only feature. */ 347 mThreadIdSupport = true; 348 reply.setHeader(THREADED_MAIL_HEADER_ID, THREAD_MAIL_KEY); 349 } 350 } catch (IOException e) { 351 Log.e(TAG,"Exception during onConnect:", e); 352 mThreadIdSupport = false; 353 return ResponseCodes.OBEX_HTTP_INTERNAL_ERROR; 354 } 355 356 if((mRemoteFeatureMask & BluetoothMapUtils.MAP_FEATURE_MESSAGE_LISTING_FORMAT_V11_BIT) 357 == BluetoothMapUtils.MAP_FEATURE_MESSAGE_LISTING_FORMAT_V11_BIT) { 358 mThreadIdSupport = true; 359 } 360 361 if((mRemoteFeatureMask & BluetoothMapUtils.MAP_FEATURE_MESSAGE_FORMAT_V11_BIT) 362 == BluetoothMapUtils.MAP_FEATURE_MESSAGE_FORMAT_V11_BIT){ 363 mMessageVersion = BluetoothMapUtils.MAP_V11_STR; 364 } 365 366 if (V) Log.v(TAG, "onConnect(): uuid is ok, will send out " + 367 "MSG_SESSION_ESTABLISHED msg."); 368 369 if(mCallback != null) { 370 Message msg = Message.obtain(mCallback); 371 msg.what = BluetoothMapService.MSG_SESSION_ESTABLISHED; 372 msg.sendToTarget(); 373 } 374 375 return ResponseCodes.OBEX_HTTP_OK; 376 } 377 378 @Override 379 public void onDisconnect(final HeaderSet req, final HeaderSet resp) { 380 if (D) Log.d(TAG, "onDisconnect(): enter"); 381 if (V) logHeader(req); 382 notifyUpdateWakeLock(); 383 resp.responseCode = ResponseCodes.OBEX_HTTP_OK; 384 if (mCallback != null) { 385 Message msg = Message.obtain(mCallback); 386 msg.what = BluetoothMapService.MSG_SESSION_DISCONNECTED; 387 msg.sendToTarget(); 388 if (V) Log.v(TAG, "onDisconnect(): msg MSG_SESSION_DISCONNECTED sent out."); 389 } 390 } 391 392 @Override 393 public int onAbort(HeaderSet request, HeaderSet reply) { 394 if (D) Log.d(TAG, "onAbort(): enter."); 395 notifyUpdateWakeLock(); 396 mIsAborted = true; 397 return ResponseCodes.OBEX_HTTP_OK; 398 } 399 400 @Override 401 public int onPut(final Operation op) { 402 if (D) Log.d(TAG, "onPut(): enter"); 403 mIsAborted = false; 404 notifyUpdateWakeLock(); 405 HeaderSet request = null; 406 String type, name; 407 byte[] appParamRaw; 408 BluetoothMapAppParams appParams = null; 409 410 try { 411 request = op.getReceivedHeader(); 412 if (V) logHeader(request); 413 type = (String)request.getHeader(HeaderSet.TYPE); 414 name = (String)request.getHeader(HeaderSet.NAME); 415 appParamRaw = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER); 416 if(appParamRaw != null) 417 appParams = new BluetoothMapAppParams(appParamRaw); 418 if(D) Log.d(TAG,"type = " + type + ", name = " + name); 419 if (type.equals(TYPE_MESSAGE_UPDATE)) { 420 if(V) { 421 Log.d(TAG,"TYPE_MESSAGE_UPDATE:"); 422 } 423 return updateInbox(); 424 }else if(type.equals(TYPE_SET_NOTIFICATION_REGISTRATION)) { 425 if(V) { 426 Log.d(TAG,"TYPE_SET_NOTIFICATION_REGISTRATION: NotificationStatus: " 427 + appParams.getNotificationStatus()); 428 } 429 return mObserver.setNotificationRegistration(appParams.getNotificationStatus()); 430 }else if(type.equals(TYPE_SET_NOTIFICATION_FILTER)) { 431 if(V) { 432 Log.d(TAG,"TYPE_SET_NOTIFICATION_FILTER: NotificationFilter: " 433 + appParams.getNotificationFilter()); 434 } 435 mObserver.setNotificationFilter(appParams.getNotificationFilter()); 436 return ResponseCodes.OBEX_HTTP_OK; 437 } else if(type.equals(TYPE_SET_MESSAGE_STATUS)) { 438 if(V) { 439 Log.d(TAG,"TYPE_SET_MESSAGE_STATUS: " + 440 "StatusIndicator: " + appParams.getStatusIndicator() 441 + ", StatusValue: " + appParams.getStatusValue() 442 + ", ExtentedData: " + "" ); // TODO: appParams.getExtendedImData()); 443 } 444 return setMessageStatus(name, appParams); 445 } else if (type.equals(TYPE_MESSAGE)) { 446 if(V) { 447 Log.d(TAG,"TYPE_MESSAGE: Transparet: " + appParams.getTransparent() 448 + ", retry: " + appParams.getRetry() 449 + ", charset: " + appParams.getCharset()); 450 } 451 return pushMessage(op, name, appParams, mMessageVersion); 452 } else if (type.equals(TYPE_SET_OWNER_STATUS)) { 453 if(V) { 454 Log.d(TAG,"TYPE_SET_OWNER_STATUS:" + 455 " PresenceAvailability " + appParams.getPresenceAvailability() + 456 ", PresenceStatus: " + appParams.getPresenceStatus() + 457 ", LastActivity: " + appParams.getLastActivityString() + 458 ", ChatStatus: " + appParams.getChatState() + 459 ", ChatStatusConvoId: " + appParams.getChatStateConvoIdString()); 460 } 461 return setOwnerStatus(name, appParams); 462 } 463 464 } catch (RemoteException e){ 465 //reload the providerClient and return error 466 try { 467 mProviderClient = acquireUnstableContentProviderOrThrow(); 468 }catch (RemoteException e2){ 469 //should not happen 470 } 471 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 472 }catch (Exception e) { 473 474 if(D) { 475 Log.e(TAG, "Exception occured while handling request",e); 476 } else { 477 Log.e(TAG, "Exception occured while handling request"); 478 } 479 if(mIsAborted) { 480 return ResponseCodes.OBEX_HTTP_OK; 481 } else { 482 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 483 } 484 } 485 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 486 } 487 488 private int updateInbox() throws RemoteException{ 489 if (mAccount != null) { 490 BluetoothMapFolderElement inboxFolder = mCurrentFolder.getFolderByName( 491 BluetoothMapContract.FOLDER_NAME_INBOX); 492 if (inboxFolder != null) { 493 long accountId = mAccountId; 494 if (D) Log.d(TAG,"updateInbox inbox=" + inboxFolder.getName() + "id=" 495 + inboxFolder.getFolderId()); 496 497 final Bundle extras = new Bundle(2); 498 if (accountId != -1) { 499 if (D) Log.d(TAG,"updateInbox accountId=" + accountId); 500 extras.putLong(BluetoothMapContract.EXTRA_UPDATE_FOLDER_ID, 501 inboxFolder.getFolderId()); 502 extras.putLong(BluetoothMapContract.EXTRA_UPDATE_ACCOUNT_ID, accountId); 503 } else { 504 // Only error code allowed on an UpdateInbox is OBEX_HTTP_NOT_IMPLEMENTED, 505 // i.e. if e.g. update not allowed on the mailbox 506 if (D) Log.d(TAG,"updateInbox accountId=0 -> OBEX_HTTP_NOT_IMPLEMENTED"); 507 return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; 508 } 509 510 Uri emailUri = Uri.parse(mBaseUriString); 511 if (D) Log.d(TAG,"updateInbox in: " + emailUri.toString()); 512 try { 513 if (D) Log.d(TAG,"updateInbox call()..."); 514 Bundle myBundle = mProviderClient.call( 515 BluetoothMapContract.METHOD_UPDATE_FOLDER, null, extras); 516 if (myBundle != null) 517 return ResponseCodes.OBEX_HTTP_OK; 518 else { 519 if (D) Log.d(TAG,"updateInbox call failed"); 520 return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; 521 } 522 } catch (RemoteException e){ 523 mProviderClient = acquireUnstableContentProviderOrThrow(); 524 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 525 }catch (NullPointerException e) { 526 if(D) Log.e(TAG, "UpdateInbox - if uri or method is null", e); 527 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 528 529 } catch (IllegalArgumentException e) { 530 if(D) Log.e(TAG, "UpdateInbox - if uri is not known", e); 531 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 532 } 533 } 534 } 535 536 return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; 537 } 538 539 private BluetoothMapFolderElement getFolderElementFromName(String folderName) { 540 BluetoothMapFolderElement folderElement = null; 541 542 if(folderName == null || folderName.trim().isEmpty() ) { 543 folderElement = mCurrentFolder; 544 if(D) Log.d(TAG, "no folder name supplied, setting folder to current: " 545 + folderElement.getName()); 546 } else { 547 folderElement = mCurrentFolder.getSubFolder(folderName); 548 if (folderElement != null) { 549 if(D) Log.d(TAG, "Folder name: " + folderName + 550 " resulted in this element: " + folderElement.getName()); 551 } 552 } 553 return folderElement; 554 } 555 556 private int pushMessage(final Operation op, String folderName, 557 BluetoothMapAppParams appParams, String messageVersion) { 558 if(appParams.getCharset() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) { 559 if(D) Log.d(TAG, "pushMessage: Missing charset - unable to decode message content. " + 560 "appParams.getCharset() = " + appParams.getCharset()); 561 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 562 } 563 InputStream bMsgStream = null; 564 try { 565 BluetoothMapFolderElement folderElement = getFolderElementFromName(folderName); 566 if(folderElement == null) { 567 Log.w(TAG,"pushMessage: folderElement == null - sending OBEX_HTTP_PRECON_FAILED"); 568 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 569 } else { 570 folderName = folderElement.getName(); 571 } 572 if (!folderName.equalsIgnoreCase(BluetoothMapContract.FOLDER_NAME_OUTBOX) && 573 !folderName.equalsIgnoreCase(BluetoothMapContract.FOLDER_NAME_DRAFT)) { 574 if(D) Log.d(TAG, "pushMessage: Is only allowed to outbox and draft. " + 575 "folderName=" + folderName); 576 return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; 577 } 578 579 /* - Read out the message 580 * - Decode into a bMessage 581 * - send it. 582 */ 583 BluetoothMapbMessage message; 584 bMsgStream = op.openInputStream(); 585 // Decode the messageBody 586 message = BluetoothMapbMessage.parse(bMsgStream, appParams.getCharset()); 587 message.setVersionString(messageVersion); 588 // Send message 589 if (mObserver == null || message == null) { 590 // Should not happen except at shutdown. 591 if(D) Log.w(TAG, "mObserver or parsed message not available" ); 592 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 593 } 594 595 if ((message.getType().equals(TYPE.EMAIL) && (folderElement.getFolderId() == -1)) 596 || ((message.getType().equals(TYPE.SMS_GSM) || 597 message.getType().equals(TYPE.SMS_CDMA) || 598 message.getType().equals(TYPE.MMS)) 599 && !folderElement.hasSmsMmsContent()) ) { 600 if(D) Log.w(TAG, "Wrong message type recieved" ); 601 return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; 602 } 603 604 long handle = mObserver.pushMessage(message, folderElement, appParams, mBaseUriString); 605 if (D) Log.d(TAG, "pushMessage handle: " + handle); 606 if (handle < 0) { 607 if(D) Log.w(TAG, "Message handle not created" ); 608 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; // Should not happen. 609 } 610 HeaderSet replyHeaders = new HeaderSet(); 611 String handleStr = BluetoothMapUtils.getMapHandle(handle, message.getType()); 612 if (D) Log.d(TAG, "handleStr: " + handleStr + " message.getType(): " 613 + message.getType()); 614 replyHeaders.setHeader(HeaderSet.NAME, handleStr); 615 op.sendHeaders(replyHeaders); 616 617 } catch (RemoteException e) { 618 //reload the providerClient and return error 619 try { 620 mProviderClient = acquireUnstableContentProviderOrThrow(); 621 }catch (RemoteException e2){ 622 //should not happen 623 if(D) Log.w(TAG, "acquireUnstableContentProviderOrThrow FAILED"); 624 } 625 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 626 } catch (IllegalArgumentException e) { 627 if (D) Log.e(TAG, "Wrongly formatted bMessage received", e); 628 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 629 } catch (IOException e) { 630 if (D) Log.e(TAG, "Exception occured: ", e); 631 if(mIsAborted == true) { 632 if(D) Log.d(TAG, "PushMessage Operation Aborted"); 633 return ResponseCodes.OBEX_HTTP_OK; 634 } else { 635 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 636 } 637 } catch (Exception e) { 638 if (D) Log.e(TAG, "Exception:", e); 639 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 640 } finally { 641 if(bMsgStream != null) { 642 try { 643 bMsgStream.close(); 644 } catch (IOException e) {} 645 } 646 } 647 return ResponseCodes.OBEX_HTTP_OK; 648 } 649 650 private int setMessageStatus(String msgHandle, BluetoothMapAppParams appParams) { 651 int indicator = appParams.getStatusIndicator(); 652 int value = appParams.getStatusValue(); 653 String extendedData = ""; // TODO: appParams.getExtendedImData(); 654 655 long handle; 656 BluetoothMapUtils.TYPE msgType; 657 658 if (msgHandle == null) { 659 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 660 } else if ((indicator == BluetoothMapAppParams.INVALID_VALUE_PARAMETER || 661 value == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) && 662 extendedData == null) { 663 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 664 } 665 if (mObserver == null) { 666 if(D) Log.e(TAG, "Error: no mObserver!"); 667 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; // Should not happen. 668 } 669 670 try { 671 handle = BluetoothMapUtils.getCpHandle(msgHandle); 672 msgType = BluetoothMapUtils.getMsgTypeFromHandle(msgHandle); 673 if(D) Log.d(TAG,"setMessageStatus. Handle:" + handle+", MsgType: "+ msgType); 674 } catch (NumberFormatException e) { 675 Log.w(TAG, "Wrongly formatted message handle: " + msgHandle); 676 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 677 } 678 679 if( indicator == BluetoothMapAppParams.STATUS_INDICATOR_DELETED) { 680 if (!mObserver.setMessageStatusDeleted(handle, msgType, mCurrentFolder, 681 mBaseUriString, value)) { 682 if(D) Log.w(TAG,"setMessageStatusDeleted failed"); 683 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 684 } 685 } else if( indicator == BluetoothMapAppParams.STATUS_INDICATOR_READ) { 686 try { 687 if (!mObserver.setMessageStatusRead(handle, msgType, mBaseUriString, value)) { 688 if(D) Log.w(TAG,"not able to update the message"); 689 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 690 } 691 } catch (RemoteException e) { 692 if(D) Log.w(TAG,"Error in setMessageStatusRead()", e); 693 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 694 } 695 } 696 if (extendedData != null) { 697 698 } 699 700 return ResponseCodes.OBEX_HTTP_OK; 701 } 702 703 private int setOwnerStatus(String msgHandle, BluetoothMapAppParams appParams) 704 throws RemoteException{ 705 // This does only work for IM 706 if (mAccount != null && mAccount.getType() == BluetoothMapUtils.TYPE.IM) { 707 final Bundle extras = new Bundle(5); 708 709 int presenceState = appParams.getPresenceAvailability(); 710 String presenceStatus = appParams.getPresenceStatus(); 711 long lastActivity = appParams.getLastActivity(); 712 int chatState = appParams.getChatState(); 713 String chatStatusConvoId = appParams.getChatStateConvoIdString(); 714 715 if(presenceState == BluetoothMapAppParams.INVALID_VALUE_PARAMETER && 716 presenceStatus == null && 717 lastActivity == BluetoothMapAppParams.INVALID_VALUE_PARAMETER && 718 chatState == BluetoothMapAppParams.INVALID_VALUE_PARAMETER && 719 chatStatusConvoId == null) { 720 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 721 } 722 723 if(presenceState != BluetoothMapAppParams.INVALID_VALUE_PARAMETER) { 724 extras.putInt(BluetoothMapContract.EXTRA_PRESENCE_STATE, presenceState); 725 } 726 if (presenceStatus != null){ 727 extras.putString(BluetoothMapContract.EXTRA_PRESENCE_STATUS, presenceStatus); 728 } 729 if (lastActivity != BluetoothMapAppParams.INVALID_VALUE_PARAMETER){ 730 extras.putLong(BluetoothMapContract.EXTRA_LAST_ACTIVE, lastActivity); 731 } 732 if (chatState != BluetoothMapAppParams.INVALID_VALUE_PARAMETER && 733 chatStatusConvoId != null){ 734 extras.putInt(BluetoothMapContract.EXTRA_CHAT_STATE, chatState); 735 extras.putString(BluetoothMapContract.EXTRA_CONVERSATION_ID, chatStatusConvoId); 736 } 737 738 Uri uri = Uri.parse(mBaseUriString); 739 if (D) Log.d(TAG,"setOwnerStatus in: " + uri.toString()); 740 try { 741 if (D) Log.d(TAG,"setOwnerStatus call()..."); 742 Bundle myBundle = mProviderClient.call( 743 BluetoothMapContract.METHOD_SET_OWNER_STATUS, null, extras); 744 if (myBundle != null) 745 return ResponseCodes.OBEX_HTTP_OK; 746 else { 747 if (D) Log.d(TAG,"setOwnerStatus call failed"); 748 return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; 749 } 750 } catch (RemoteException e){ 751 mProviderClient = acquireUnstableContentProviderOrThrow(); 752 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 753 } catch (NullPointerException e) { 754 if(D) Log.e(TAG, "setOwnerStatus - if uri or method is null", e); 755 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 756 } catch (IllegalArgumentException e) { 757 if(D) Log.e(TAG, "setOwnerStatus - if uri is not known", e); 758 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 759 } 760 } 761 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 762 } 763 764 @Override 765 public int onSetPath(final HeaderSet request, final HeaderSet reply, final boolean backup, 766 final boolean create) { 767 String folderName; 768 BluetoothMapFolderElement folder; 769 notifyUpdateWakeLock(); 770 try { 771 folderName = (String)request.getHeader(HeaderSet.NAME); 772 } catch (Exception e) { 773 if(D) { 774 Log.e(TAG, "request headers error" , e); 775 } else { 776 Log.e(TAG, "request headers error"); 777 } 778 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 779 } 780 781 if (V) logHeader(request); 782 if (D) Log.d(TAG, "onSetPath name is " + folderName + 783 " backup: " + backup + 784 " create: " + create); 785 786 if(backup == true){ 787 if(mCurrentFolder.getParent() != null) 788 mCurrentFolder = mCurrentFolder.getParent(); 789 else 790 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 791 } 792 793 if (folderName == null || folderName.trim().isEmpty()) { 794 if(backup == false) 795 mCurrentFolder = mCurrentFolder.getRoot(); 796 } 797 else { 798 folder = mCurrentFolder.getSubFolder(folderName); 799 if(folder != null) 800 mCurrentFolder = folder; 801 else 802 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 803 } 804 if (V) Log.d(TAG, "Current Folder: " + mCurrentFolder.getName()); 805 return ResponseCodes.OBEX_HTTP_OK; 806 } 807 808 @Override 809 public void onClose() { 810 if (mCallback != null) { 811 Message msg = Message.obtain(mCallback); 812 msg.what = BluetoothMapService.MSG_SERVERSESSION_CLOSE; 813 msg.arg1 = mMasId; 814 msg.sendToTarget(); 815 if (D) Log.d(TAG, "onClose(): msg MSG_SERVERSESSION_CLOSE sent out."); 816 817 } 818 if(mProviderClient != null){ 819 mProviderClient.release(); 820 mProviderClient = null; 821 } 822 823 } 824 825 @Override 826 public int onGet(Operation op) { 827 notifyUpdateWakeLock(); 828 mIsAborted = false; 829 HeaderSet request; 830 String type; 831 String name; 832 byte[] appParamRaw = null; 833 BluetoothMapAppParams appParams = null; 834 try { 835 request = op.getReceivedHeader(); 836 type = (String)request.getHeader(HeaderSet.TYPE); 837 838 appParamRaw = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER); 839 if(appParamRaw != null) 840 appParams = new BluetoothMapAppParams(appParamRaw); 841 842 if (V) logHeader(request); 843 if (D) Log.d(TAG, "OnGet type is " + type ); 844 845 if (type == null) { 846 if (V) Log.d(TAG, "type is null?" + type); 847 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 848 } 849 850 if (type.equals(TYPE_GET_FOLDER_LISTING)) { 851 if (V && appParams != null) { 852 Log.d(TAG,"TYPE_GET_FOLDER_LISTING: MaxListCount = " 853 + appParams.getMaxListCount() 854 + ", ListStartOffset = " + appParams.getStartOffset()); 855 } 856 // Block until all packets have been send. 857 return sendFolderListingRsp(op, appParams); 858 } else if (type.equals(TYPE_GET_MESSAGE_LISTING)){ 859 name = (String)request.getHeader(HeaderSet.NAME); 860 if (V && appParams != null) { 861 Log.d(TAG,"TYPE_GET_MESSAGE_LISTING: folder name is: " + name + 862 ", MaxListCount = " + appParams.getMaxListCount() + 863 ", ListStartOffset = " + appParams.getStartOffset()); 864 Log.d(TAG,"SubjectLength = " + appParams.getSubjectLength() + 865 ", ParameterMask = " + appParams.getParameterMask()); 866 Log.d(TAG,"FilterMessageType = " + appParams.getFilterMessageType() ); 867 Log.d(TAG,"FilterPeriodBegin = " + appParams.getFilterPeriodBeginString() + 868 ", FilterPeriodEnd = " + appParams.getFilterPeriodEndString() + 869 ", FilterReadStatus = " + appParams.getFilterReadStatus()); 870 Log.d(TAG,"FilterRecipient = " + appParams.getFilterRecipient() + 871 ", FilterOriginator = " + appParams.getFilterOriginator()); 872 Log.d(TAG,"FilterPriority = " + appParams.getFilterPriority()); 873 long tmpLong = appParams.getFilterMsgHandle(); 874 Log.d(TAG,"FilterMsgHandle = " + ( 875 (tmpLong == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) ? "" : 876 Long.toHexString(tmpLong))); 877 SignedLongLong tmpLongLong = appParams.getFilterConvoId(); 878 Log.d(TAG,"FilterConvoId = " + ((tmpLongLong == null) ? "" : 879 Long.toHexString(tmpLongLong.getLeastSignificantBits()) ) ); 880 } 881 // Block until all packets have been send. 882 return sendMessageListingRsp(op, appParams, name); 883 884 } else if (type.equals(TYPE_GET_CONVO_LISTING)){ 885 name = (String)request.getHeader(HeaderSet.NAME); 886 if (V && appParams != null) { 887 Log.d(TAG,"TYPE_GET_CONVO_LISTING: name is" + name + 888 ", MaxListCount = " + appParams.getMaxListCount() + 889 ", ListStartOffset = " + appParams.getStartOffset()); 890 Log.d(TAG,"FilterLastActivityBegin = "+appParams.getFilterLastActivityBegin()); 891 Log.d(TAG,"FilterLastActivityEnd = " + appParams.getFilterLastActivityEnd()); 892 Log.d(TAG,"FilterReadStatus = " + appParams.getFilterReadStatus()); 893 Log.d(TAG,"FilterRecipient = " + appParams.getFilterRecipient()); 894 } 895 // Block until all packets have been send. 896 return sendConvoListingRsp(op, appParams,name); 897 } else if (type.equals(TYPE_GET_MAS_INSTANCE_INFORMATION)) { 898 if(V && appParams != null) { 899 Log.d(TAG,"TYPE_MESSAGE (GET): MASInstandeId = " 900 + appParams.getMasInstanceId()); 901 } 902 // Block until all packets have been send. 903 return sendMASInstanceInformationRsp(op, appParams); 904 } else if (type.equals(TYPE_MESSAGE)){ 905 name = (String)request.getHeader(HeaderSet.NAME); 906 if(V && appParams != null) { 907 Log.d(TAG,"TYPE_MESSAGE (GET): name is" + name + 908 ", Attachment = " + appParams.getAttachment() + 909 ", Charset = " + appParams.getCharset() + 910 ", FractionRequest = " + appParams.getFractionRequest()); 911 } 912 // Block until all packets have been send. 913 return sendGetMessageRsp(op, name, appParams, mMessageVersion); 914 } else { 915 Log.w(TAG, "unknown type request: " + type); 916 return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; 917 } 918 919 } catch (IllegalArgumentException e) { 920 Log.e(TAG, "Exception:", e); 921 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 922 } catch (ParseException e) { 923 Log.e(TAG, "Exception:", e); 924 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 925 } catch (Exception e) { 926 if(D) { 927 Log.e(TAG, "Exception occured while handling request",e); 928 } else { 929 Log.e(TAG, "Exception occured while handling request"); 930 } 931 if(mIsAborted == true) { 932 if(D) Log.d(TAG, "onGet Operation Aborted"); 933 return ResponseCodes.OBEX_HTTP_OK; 934 } else { 935 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 936 } 937 } 938 } 939 940 /** 941 * Generate and send the message listing response based on an application 942 * parameter header. This function call will block until complete or aborted 943 * by the peer. Fragmentation of packets larger than the obex packet size 944 * will be handled by this function. 945 * 946 * @param op 947 * The OBEX operation. 948 * @param appParams 949 * The application parameter header 950 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 951 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 952 */ 953 private int sendMessageListingRsp(Operation op, 954 BluetoothMapAppParams appParams, 955 String folderName){ 956 OutputStream outStream = null; 957 byte[] outBytes = null; 958 int maxChunkSize, bytesToWrite, bytesWritten = 0, listSize; 959 boolean hasUnread = false; 960 HeaderSet replyHeaders = new HeaderSet(); 961 BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); 962 BluetoothMapMessageListing outList; 963 if(appParams == null){ 964 appParams = new BluetoothMapAppParams(); 965 appParams.setMaxListCount(1024); 966 appParams.setStartOffset(0); 967 } 968 969 /* MAP Spec 1.3 introduces the following 970 * Messagehandle filtering: 971 * msgListing (messageHandle=X) -> other allowed filters: parametereMask, subjectMaxLength 972 * ConversationID filtering: 973 * msgListing (convoId empty) -> should work as normal msgListing in valid folders 974 * msgListing (convoId=0, no other filters) -> should return all messages in all folders 975 * msgListing (convoId=N, other filters) -> should return all messages in conversationID=N 976 * according to filters requested 977 */ 978 BluetoothMapFolderElement folderToList = null; 979 if (appParams.getFilterMsgHandle() != BluetoothMapAppParams.INVALID_VALUE_PARAMETER 980 || appParams.getFilterConvoId() != null) { 981 // If messageHandle or convoId filtering ignore folder 982 Log.v(TAG,"sendMessageListingRsp: ignore folder "); 983 folderToList = mCurrentFolder.getRoot(); 984 folderToList.setIngore(true); 985 } else { 986 folderToList = getFolderElementFromName(folderName); 987 if(folderToList == null) { 988 Log.w(TAG,"sendMessageListingRsp: folderToList == "+ 989 "null-sending OBEX_HTTP_BAD_REQUEST"); 990 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 991 } 992 Log.v(TAG,"sendMessageListingRsp: has sms " + folderToList.hasSmsMmsContent() + 993 "has email " + folderToList.hasEmailContent() + 994 "has IM " + folderToList.hasImContent() ); 995 } 996 997 try { 998 // Open the OBEX body stream 999 outStream = op.openOutputStream(); 1000 1001 if(appParams.getMaxListCount() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1002 appParams.setMaxListCount(1024); 1003 1004 if(appParams.getStartOffset() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1005 appParams.setStartOffset(0); 1006 1007 // Check to see if we only need to send the size - hence no need to encode. 1008 if(appParams.getMaxListCount() != 0) { 1009 outList = mOutContent.msgListing(folderToList, appParams); 1010 // Generate the byte stream 1011 outAppParams.setMessageListingSize(outList.getCount()); 1012 String version; 1013 if(0 < (mRemoteFeatureMask & 1014 BluetoothMapUtils.MAP_FEATURE_MESSAGE_LISTING_FORMAT_V11_BIT)) { 1015 version = BluetoothMapUtils.MAP_V11_STR; 1016 } else { 1017 version = BluetoothMapUtils.MAP_V10_STR; 1018 } 1019 /* This will only set the version, the bit must also be checked before adding any 1020 * 1.1 bits to the listing. */ 1021 outBytes = outList.encode(mThreadIdSupport, version); 1022 hasUnread = outList.hasUnread(); 1023 } else { 1024 listSize = mOutContent.msgListingSize(folderToList, appParams); 1025 hasUnread = mOutContent.msgListingHasUnread(folderToList, appParams); 1026 outAppParams.setMessageListingSize(listSize); 1027 op.noBodyHeader(); 1028 } 1029 folderToList.setIngore(false); 1030 // Build the application parameter header 1031 // let the peer know if there are unread messages in the list 1032 if(hasUnread) { 1033 outAppParams.setNewMessage(1); 1034 }else{ 1035 outAppParams.setNewMessage(0); 1036 } 1037 if ((mRemoteFeatureMask & BluetoothMapUtils.MAP_FEATURE_DATABASE_INDENTIFIER_BIT) 1038 == BluetoothMapUtils.MAP_FEATURE_DATABASE_INDENTIFIER_BIT ) { 1039 outAppParams.setDatabaseIdentifier(0, mMasInstance.getDbIdentifier()); 1040 } 1041 if((mRemoteFeatureMask & BluetoothMapUtils.MAP_FEATURE_FOLDER_VERSION_COUNTER_BIT) 1042 == BluetoothMapUtils.MAP_FEATURE_FOLDER_VERSION_COUNTER_BIT) { 1043 // Force update of version counter if needed 1044 mObserver.refreshFolderVersionCounter(); 1045 outAppParams.setFolderVerCounter(mMasInstance.getFolderVersionCounter(), 0); 1046 } 1047 outAppParams.setMseTime(Calendar.getInstance().getTime().getTime()); 1048 replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, outAppParams.EncodeParams()); 1049 op.sendHeaders(replyHeaders); 1050 1051 } catch (IOException e) { 1052 Log.w(TAG,"sendMessageListingRsp: IOException - sending OBEX_HTTP_BAD_REQUEST", e); 1053 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1054 if(mIsAborted == true) { 1055 if(D) Log.d(TAG, "sendMessageListingRsp Operation Aborted"); 1056 return ResponseCodes.OBEX_HTTP_OK; 1057 } else { 1058 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1059 } 1060 } catch (IllegalArgumentException e) { 1061 Log.w(TAG,"sendMessageListingRsp: IllegalArgumentException"+ 1062 " - sending OBEX_HTTP_BAD_REQUEST", e); 1063 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1064 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1065 } 1066 1067 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1068 if(outBytes != null) { 1069 try { 1070 while (bytesWritten < outBytes.length && mIsAborted == false) { 1071 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1072 outStream.write(outBytes, bytesWritten, bytesToWrite); 1073 bytesWritten += bytesToWrite; 1074 } 1075 } catch (IOException e) { 1076 if(D) Log.w(TAG,e); 1077 // We were probably aborted or disconnected 1078 } finally { 1079 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1080 } 1081 if(bytesWritten != outBytes.length && !mIsAborted) { 1082 Log.w(TAG,"sendMessageListingRsp: bytesWritten != outBytes.length" + 1083 " - sending OBEX_HTTP_BAD_REQUEST"); 1084 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1085 } 1086 } else { 1087 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1088 } 1089 return ResponseCodes.OBEX_HTTP_OK; 1090 } 1091 1092 /** 1093 * Update the {@link BluetoothMapAppParams} object message type filter mask to only contain 1094 * message types supported by this mas instance. 1095 * Could the folder be used in stead? 1096 * @param appParams Reference to the object to update 1097 * @param overwrite True: The msgType will be overwritten to match the message types supported 1098 * by this MAS instance. False: any unsupported message types will be masked out. 1099 */ 1100 private void setMsgTypeFilterParams(BluetoothMapAppParams appParams, boolean overwrite) { 1101 int masFilterMask = 0; 1102 if(!mEnableSmsMms) { 1103 masFilterMask |= BluetoothMapAppParams.FILTER_NO_SMS_CDMA; 1104 masFilterMask |= BluetoothMapAppParams.FILTER_NO_SMS_GSM; 1105 masFilterMask |= BluetoothMapAppParams.FILTER_NO_MMS; 1106 } 1107 if(mAccount==null){ 1108 masFilterMask |= BluetoothMapAppParams.FILTER_NO_EMAIL; 1109 masFilterMask |= BluetoothMapAppParams.FILTER_NO_IM; 1110 } else { 1111 if(!(mAccount.getType() == BluetoothMapUtils.TYPE.EMAIL)) { 1112 masFilterMask |= BluetoothMapAppParams.FILTER_NO_EMAIL; 1113 } 1114 if(!(mAccount.getType() == BluetoothMapUtils.TYPE.IM)) { 1115 masFilterMask |= BluetoothMapAppParams.FILTER_NO_IM; 1116 } 1117 } 1118 if(overwrite) { 1119 appParams.setFilterMessageType(masFilterMask); 1120 } else { 1121 int newMask = appParams.getFilterMessageType(); 1122 if(newMask == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) { 1123 appParams.setFilterMessageType(newMask); 1124 } else { 1125 newMask |= masFilterMask; 1126 appParams.setFilterMessageType(newMask); 1127 } 1128 } 1129 } 1130 1131 /** 1132 * Generate and send the Conversation listing response based on an application 1133 * parameter header. This function call will block until complete or aborted 1134 * by the peer. Fragmentation of packets larger than the obex packet size 1135 * will be handled by this function. 1136 * 1137 * @param op 1138 * The OBEX operation. 1139 * @param appParams 1140 * The application parameter header 1141 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 1142 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 1143 */ 1144 private int sendConvoListingRsp(Operation op, 1145 BluetoothMapAppParams appParams, 1146 String folderName){ 1147 OutputStream outStream = null; 1148 byte[] outBytes = null; 1149 int maxChunkSize, bytesToWrite, bytesWritten = 0; 1150 //boolean hasUnread = false; 1151 HeaderSet replyHeaders = new HeaderSet(); 1152 BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); 1153 BluetoothMapConvoListing outList; 1154 if(appParams == null){ 1155 appParams = new BluetoothMapAppParams(); 1156 appParams.setMaxListCount(1024); 1157 appParams.setStartOffset(0); 1158 } 1159 // As the app parameters do not carry which message types to list, we set the filter here 1160 // to all message types supported by this instance. 1161 setMsgTypeFilterParams(appParams, true); 1162 1163 // Check to see if we only need to send the size - hence no need to encode. 1164 try { 1165 // Open the OBEX body stream 1166 outStream = op.openOutputStream(); 1167 1168 if(appParams.getMaxListCount() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1169 appParams.setMaxListCount(1024); 1170 1171 if(appParams.getStartOffset() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1172 appParams.setStartOffset(0); 1173 1174 if(appParams.getMaxListCount() != 0) { 1175 outList = mOutContent.convoListing(appParams, false); 1176 outAppParams.setConvoListingSize(outList.getCount()); 1177 // Generate the byte stream 1178 outBytes = outList.encode(); // Include thread ID for clients that supports it. 1179 // hasUnread = outList.hasUnread(); 1180 if(D) Log.d(TAG, "outBytes size:"+ outBytes.length); 1181 } else { 1182 outList = mOutContent.convoListing(appParams, true); 1183 outAppParams.setConvoListingSize(outList.getCount()); 1184 if(mEnableSmsMms) { 1185 mOutContent.refreshSmsMmsConvoVersions(); 1186 } 1187 if(mAccount != null) { 1188 mOutContent.refreshImEmailConvoVersions(); 1189 } 1190 // Force update of version counter if needed 1191 mObserver.refreshConvoListVersionCounter(); 1192 if(0 < (mRemoteFeatureMask & 1193 BluetoothMapUtils.MAP_FEATURE_CONVERSATION_VERSION_COUNTER_BIT)) { 1194 outAppParams.setConvoListingVerCounter( 1195 mMasInstance.getCombinedConvoListVersionCounter(), 0); 1196 } 1197 op.noBodyHeader(); 1198 } 1199 if(D) Log.d(TAG, "outList size:"+ outList.getCount() 1200 + " MaxListCount: "+appParams.getMaxListCount()); 1201 outList = null; // We don't need it anymore - we might as well give it up for GC 1202 outAppParams.setDatabaseIdentifier(0, mMasInstance.getDbIdentifier()); 1203 1204 // Build the application parameter header 1205 // The MseTime is not in the CR - but I think it is missing. 1206 outAppParams.setMseTime(Calendar.getInstance().getTime().getTime()); 1207 replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, outAppParams.EncodeParams()); 1208 op.sendHeaders(replyHeaders); 1209 1210 } catch (IOException e) { 1211 Log.w(TAG,"sendConvoListingRsp: IOException - sending OBEX_HTTP_BAD_REQUEST", e); 1212 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1213 if(mIsAborted == true) { 1214 if(D) Log.d(TAG, "sendConvoListingRsp Operation Aborted"); 1215 return ResponseCodes.OBEX_HTTP_OK; 1216 } else { 1217 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1218 } 1219 } catch (IllegalArgumentException e) { 1220 Log.w(TAG,"sendConvoListingRsp: IllegalArgumentException" + 1221 " - sending OBEX_HTTP_BAD_REQUEST", e); 1222 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1223 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1224 } 1225 1226 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1227 if(outBytes != null) { 1228 try { 1229 while (bytesWritten < outBytes.length && mIsAborted == false) { 1230 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1231 outStream.write(outBytes, bytesWritten, bytesToWrite); 1232 bytesWritten += bytesToWrite; 1233 } 1234 } catch (IOException e) { 1235 if(D) Log.w(TAG,e); 1236 // We were probably aborted or disconnected 1237 } finally { 1238 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1239 } 1240 if(bytesWritten != outBytes.length && !mIsAborted) { 1241 Log.w(TAG,"sendConvoListingRsp: bytesWritten != outBytes.length" + 1242 " - sending OBEX_HTTP_BAD_REQUEST"); 1243 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1244 } 1245 } else { 1246 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1247 } 1248 return ResponseCodes.OBEX_HTTP_OK; 1249 } 1250 1251 /** 1252 * Generate and send the Folder listing response based on an application 1253 * parameter header. This function call will block until complete or aborted 1254 * by the peer. Fragmentation of packets larger than the obex packet size 1255 * will be handled by this function. 1256 * 1257 * @param op 1258 * The OBEX operation. 1259 * @param appParams 1260 * The application parameter header 1261 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 1262 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 1263 */ 1264 private int sendFolderListingRsp(Operation op, BluetoothMapAppParams appParams){ 1265 OutputStream outStream = null; 1266 byte[] outBytes = null; 1267 BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); 1268 int maxChunkSize, bytesWritten = 0; 1269 HeaderSet replyHeaders = new HeaderSet(); 1270 int bytesToWrite, maxListCount, listStartOffset; 1271 if(appParams == null){ 1272 appParams = new BluetoothMapAppParams(); 1273 appParams.setMaxListCount(1024); 1274 } 1275 1276 if(V) 1277 Log.v(TAG,"sendFolderList for " + mCurrentFolder.getName()); 1278 1279 try { 1280 maxListCount = appParams.getMaxListCount(); 1281 listStartOffset = appParams.getStartOffset(); 1282 1283 if(listStartOffset == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1284 listStartOffset = 0; 1285 1286 if(maxListCount == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1287 maxListCount = 1024; 1288 1289 if(maxListCount != 0) 1290 { 1291 outBytes = mCurrentFolder.encode(listStartOffset, maxListCount); 1292 outStream = op.openOutputStream(); 1293 } else { 1294 // ESR08 specified that this shall only be included for MaxListCount=0 1295 outAppParams.setFolderListingSize(mCurrentFolder.getSubFolderCount()); 1296 op.noBodyHeader(); 1297 } 1298 1299 // Build and set the application parameter header 1300 replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, outAppParams.EncodeParams()); 1301 op.sendHeaders(replyHeaders); 1302 1303 } catch (IOException e1) { 1304 Log.w(TAG,"sendFolderListingRsp: IOException" + 1305 " - sending OBEX_HTTP_BAD_REQUEST Exception:", e1); 1306 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1307 if(mIsAborted == true) { 1308 if(D) Log.d(TAG, "sendFolderListingRsp Operation Aborted"); 1309 return ResponseCodes.OBEX_HTTP_OK; 1310 } else { 1311 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1312 } 1313 } catch (IllegalArgumentException e1) { 1314 Log.w(TAG,"sendFolderListingRsp: IllegalArgumentException" + 1315 " - sending OBEX_HTTP_BAD_REQUEST Exception:", e1); 1316 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1317 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 1318 } 1319 1320 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1321 1322 if(outBytes != null) { 1323 try { 1324 while (bytesWritten < outBytes.length && mIsAborted == false) { 1325 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1326 outStream.write(outBytes, bytesWritten, bytesToWrite); 1327 bytesWritten += bytesToWrite; 1328 } 1329 } catch (IOException e) { 1330 // We were probably aborted or disconnected 1331 } finally { 1332 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1333 } 1334 if(V) 1335 Log.v(TAG,"sendFolderList sent " + bytesWritten+" bytes out of "+ outBytes.length); 1336 if(bytesWritten == outBytes.length || mIsAborted) 1337 return ResponseCodes.OBEX_HTTP_OK; 1338 else 1339 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1340 } 1341 1342 return ResponseCodes.OBEX_HTTP_OK; 1343 } 1344 1345 /** 1346 * Generate and send the get MAS Instance Information response based on an MAS Instance 1347 * 1348 * @param op 1349 * The OBEX operation. 1350 * @param appParams 1351 * The application parameter header 1352 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 1353 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 1354 */ 1355 private int sendMASInstanceInformationRsp(Operation op, BluetoothMapAppParams appParams){ 1356 1357 OutputStream outStream = null; 1358 byte[] outBytes = null; 1359 String outString = null; 1360 int maxChunkSize, bytesToWrite, bytesWritten = 0; 1361 1362 try { 1363 if(mMasId == appParams.getMasInstanceId()) { 1364 if(mAccount != null) { 1365 if(mAccount.getType() == TYPE.EMAIL) { 1366 outString = (mAccount.getName() != null) ? mAccount.getName() : 1367 BluetoothMapMasInstance.TYPE_EMAIL_STR; 1368 } else if(mAccount.getType() == TYPE.IM){ 1369 outString = mAccount.getUciFull(); 1370 if(outString == null) { 1371 String uci = mAccount.getUci(); 1372 // TODO: Do we need to align this with HF/PBAP 1373 StringBuilder sb = 1374 new StringBuilder(uci == null ? 5 : 5 + uci.length()); 1375 sb.append("un"); 1376 if(mMasId < 10) { 1377 sb.append("00"); 1378 } else if(mMasId < 100) { 1379 sb.append("0"); 1380 } 1381 sb.append(mMasId); 1382 if(uci != null) { 1383 sb.append(":").append(uci); 1384 } 1385 outString = sb.toString(); 1386 } 1387 } 1388 } else { 1389 outString = BluetoothMapMasInstance.TYPE_SMS_MMS_STR; 1390 // TODO: Add phone number if possible 1391 } 1392 } else { 1393 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1394 } 1395 1396 /* Ensure byte array max length is 200 containing valid UTF-8 characters */ 1397 outBytes = BluetoothMapUtils.truncateUtf8StringToBytearray(outString, 1398 MAS_INSTANCE_INFORMATION_LENGTH); 1399 1400 // Open the OBEX body stream 1401 outStream = op.openOutputStream(); 1402 1403 } catch (IOException e) { 1404 Log.w(TAG,"sendMASInstanceInformationRsp: IOException" + 1405 " - sending OBEX_HTTP_BAD_REQUEST", e); 1406 if(mIsAborted == true) { 1407 if(D) Log.d(TAG, "sendMASInstanceInformationRsp Operation Aborted"); 1408 return ResponseCodes.OBEX_HTTP_OK; 1409 } else { 1410 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1411 } 1412 } 1413 1414 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1415 1416 if(outBytes != null) { 1417 try { 1418 while (bytesWritten < outBytes.length && mIsAborted == false) { 1419 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1420 outStream.write(outBytes, bytesWritten, bytesToWrite); 1421 bytesWritten += bytesToWrite; 1422 } 1423 } catch (IOException e) { 1424 // We were probably aborted or disconnected 1425 } finally { 1426 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1427 } 1428 if(V) 1429 Log.v(TAG,"sendMASInstanceInformationRsp sent " + bytesWritten + 1430 " bytes out of "+ outBytes.length); 1431 if(bytesWritten == outBytes.length || mIsAborted) 1432 return ResponseCodes.OBEX_HTTP_OK; 1433 else 1434 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1435 } 1436 return ResponseCodes.OBEX_HTTP_OK; 1437 } 1438 1439 /** 1440 * Generate and send the get message response based on an application 1441 * parameter header and a handle. 1442 * 1443 * @param op 1444 * The OBEX operation. 1445 * @param handle 1446 * The handle of the requested message 1447 * @param appParams 1448 * The application parameter header 1449 * @param version 1450 * The string representation of the version number(i.e. "1.0") 1451 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 1452 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 1453 */ 1454 private int sendGetMessageRsp(Operation op, String handle, 1455 BluetoothMapAppParams appParams, String version){ 1456 OutputStream outStream = null; 1457 byte[] outBytes = null; 1458 int maxChunkSize, bytesToWrite, bytesWritten = 0; 1459 1460 try { 1461 outBytes = mOutContent.getMessage(handle, appParams, mCurrentFolder, version); 1462 outStream = op.openOutputStream(); 1463 1464 // If it is a fraction request of Email message, set header before responding 1465 if ((BluetoothMapUtils.getMsgTypeFromHandle(handle).equals(TYPE.EMAIL)|| 1466 (BluetoothMapUtils.getMsgTypeFromHandle(handle).equals(TYPE.IM))) && 1467 (appParams.getFractionRequest() == 1468 BluetoothMapAppParams.FRACTION_REQUEST_FIRST)) { 1469 BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); 1470 HeaderSet replyHeaders = new HeaderSet(); 1471 outAppParams.setFractionDeliver(BluetoothMapAppParams.FRACTION_DELIVER_LAST); 1472 // Build and set the application parameter header 1473 replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, 1474 outAppParams.EncodeParams()); 1475 op.sendHeaders(replyHeaders); 1476 if(V) Log.v(TAG,"sendGetMessageRsp fractionRequest - " + 1477 "set FRACTION_DELIVER_LAST header"); 1478 } 1479 1480 } catch (IOException e) { 1481 Log.w(TAG,"sendGetMessageRsp: IOException - sending OBEX_HTTP_BAD_REQUEST", e); 1482 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1483 if(mIsAborted == true) { 1484 if(D) Log.d(TAG, "sendGetMessageRsp Operation Aborted"); 1485 return ResponseCodes.OBEX_HTTP_OK; 1486 } else { 1487 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1488 } 1489 } catch (IllegalArgumentException e) { 1490 Log.w(TAG,"sendGetMessageRsp: IllegalArgumentException (e.g. invalid handle) - " + 1491 "sending OBEX_HTTP_BAD_REQUEST", e); 1492 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1493 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1494 } 1495 1496 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1497 1498 if(outBytes != null) { 1499 try { 1500 while (bytesWritten < outBytes.length && mIsAborted == false) { 1501 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1502 outStream.write(outBytes, bytesWritten, bytesToWrite); 1503 bytesWritten += bytesToWrite; 1504 } 1505 } catch (IOException e) { 1506 // We were probably aborted or disconnected 1507 if(D && e.getMessage().equals("Abort Received")) { 1508 Log.w(TAG, "getMessage() Aborted...", e); 1509 } 1510 } finally { 1511 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1512 } 1513 if(bytesWritten == outBytes.length || mIsAborted) 1514 return ResponseCodes.OBEX_HTTP_OK; 1515 else 1516 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1517 } 1518 1519 return ResponseCodes.OBEX_HTTP_OK; 1520 } 1521 1522 @Override 1523 public int onDelete(HeaderSet request, HeaderSet reply) { 1524 if(D) Log.v(TAG, "onDelete() " + request.toString()); 1525 mIsAborted = false; 1526 notifyUpdateWakeLock(); 1527 String type, name; 1528 byte[] appParamRaw; 1529 BluetoothMapAppParams appParams = null; 1530 1531 /* TODO: If this is to be placed here, we need to cleanup - e.g. the exception handling */ 1532 try { 1533 type = (String)request.getHeader(HeaderSet.TYPE); 1534 1535 name = (String)request.getHeader(HeaderSet.NAME); 1536 appParamRaw = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER); 1537 if(appParamRaw != null) 1538 appParams = new BluetoothMapAppParams(appParamRaw); 1539 if(D) Log.d(TAG,"type = " + type + ", name = " + name); 1540 if(type.equals(TYPE_SET_NOTIFICATION_FILTER)) { 1541 if(V) { 1542 Log.d(TAG,"TYPE_SET_NOTIFICATION_FILTER: NotificationFilter: " 1543 + appParams.getNotificationFilter()); 1544 } 1545 mObserver.setNotificationFilter(appParams.getNotificationFilter()); 1546 return ResponseCodes.OBEX_HTTP_OK; 1547 } else if (type.equals(TYPE_SET_OWNER_STATUS)) { 1548 if(V) { 1549 Log.d(TAG,"TYPE_SET_OWNER_STATUS:" + 1550 " PresenceAvailability " + appParams.getPresenceAvailability() + 1551 ", PresenceStatus: " + appParams.getPresenceStatus() + 1552 ", LastActivity: " + appParams.getLastActivityString() + 1553 ", ChatStatus: " + appParams.getChatState() + 1554 ", ChatStatusConvoId: " + appParams.getChatStateConvoIdString()); 1555 } 1556 return setOwnerStatus(name, appParams); 1557 } 1558 1559 } catch (RemoteException e){ 1560 //reload the providerClient and return error 1561 try { 1562 mProviderClient = acquireUnstableContentProviderOrThrow(); 1563 }catch (RemoteException e2){ 1564 //should not happen 1565 } 1566 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1567 }catch (Exception e) { 1568 1569 if(D) { 1570 Log.e(TAG, "Exception occured while handling request",e); 1571 } else { 1572 Log.e(TAG, "Exception occured while handling request"); 1573 } 1574 if(mIsAborted) { 1575 return ResponseCodes.OBEX_HTTP_OK; 1576 } else { 1577 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1578 } 1579 } 1580 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1581 } 1582 1583 private void notifyUpdateWakeLock() { 1584 if(mCallback != null) { 1585 Message msg = Message.obtain(mCallback); 1586 msg.what = BluetoothMapService.MSG_ACQUIRE_WAKE_LOCK; 1587 msg.sendToTarget(); 1588 } 1589 } 1590 1591 private static final void logHeader(HeaderSet hs) { 1592 Log.v(TAG, "Dumping HeaderSet " + hs.toString()); 1593 try { 1594 Log.v(TAG, "CONNECTION_ID : " + hs.getHeader(HeaderSet.CONNECTION_ID)); 1595 Log.v(TAG, "NAME : " + hs.getHeader(HeaderSet.NAME)); 1596 Log.v(TAG, "TYPE : " + hs.getHeader(HeaderSet.TYPE)); 1597 Log.v(TAG, "TARGET : " + hs.getHeader(HeaderSet.TARGET)); 1598 Log.v(TAG, "WHO : " + hs.getHeader(HeaderSet.WHO)); 1599 Log.v(TAG, "APPLICATION_PARAMETER : " + hs.getHeader(HeaderSet.APPLICATION_PARAMETER)); 1600 } catch (IOException e) { 1601 Log.e(TAG, "dump HeaderSet error " + e); 1602 } 1603 Log.v(TAG, "NEW!!! Dumping HeaderSet END"); 1604 } 1605} 1606