BluetoothMapObexServer.java revision 72014e2b0523c72ba34ca43d91bc4e8be104d95a
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 } catch (IllegalArgumentException e) { 678 Log.w(TAG, "Message type not found in handle string: " + msgHandle); 679 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 680 } 681 682 if( indicator == BluetoothMapAppParams.STATUS_INDICATOR_DELETED) { 683 if (!mObserver.setMessageStatusDeleted(handle, msgType, mCurrentFolder, 684 mBaseUriString, value)) { 685 if(D) Log.w(TAG,"setMessageStatusDeleted failed"); 686 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 687 } 688 } else if( indicator == BluetoothMapAppParams.STATUS_INDICATOR_READ) { 689 try { 690 if (!mObserver.setMessageStatusRead(handle, msgType, mBaseUriString, value)) { 691 if(D) Log.w(TAG,"not able to update the message"); 692 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 693 } 694 } catch (RemoteException e) { 695 if(D) Log.w(TAG,"Error in setMessageStatusRead()", e); 696 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 697 } 698 } 699 if (extendedData != null) { 700 701 } 702 703 return ResponseCodes.OBEX_HTTP_OK; 704 } 705 706 private int setOwnerStatus(String msgHandle, BluetoothMapAppParams appParams) 707 throws RemoteException{ 708 // This does only work for IM 709 if (mAccount != null && mAccount.getType() == BluetoothMapUtils.TYPE.IM) { 710 final Bundle extras = new Bundle(5); 711 712 int presenceState = appParams.getPresenceAvailability(); 713 String presenceStatus = appParams.getPresenceStatus(); 714 long lastActivity = appParams.getLastActivity(); 715 int chatState = appParams.getChatState(); 716 String chatStatusConvoId = appParams.getChatStateConvoIdString(); 717 718 if(presenceState == BluetoothMapAppParams.INVALID_VALUE_PARAMETER && 719 presenceStatus == null && 720 lastActivity == BluetoothMapAppParams.INVALID_VALUE_PARAMETER && 721 chatState == BluetoothMapAppParams.INVALID_VALUE_PARAMETER && 722 chatStatusConvoId == null) { 723 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 724 } 725 726 if(presenceState != BluetoothMapAppParams.INVALID_VALUE_PARAMETER) { 727 extras.putInt(BluetoothMapContract.EXTRA_PRESENCE_STATE, presenceState); 728 } 729 if (presenceStatus != null){ 730 extras.putString(BluetoothMapContract.EXTRA_PRESENCE_STATUS, presenceStatus); 731 } 732 if (lastActivity != BluetoothMapAppParams.INVALID_VALUE_PARAMETER){ 733 extras.putLong(BluetoothMapContract.EXTRA_LAST_ACTIVE, lastActivity); 734 } 735 if (chatState != BluetoothMapAppParams.INVALID_VALUE_PARAMETER && 736 chatStatusConvoId != null){ 737 extras.putInt(BluetoothMapContract.EXTRA_CHAT_STATE, chatState); 738 extras.putString(BluetoothMapContract.EXTRA_CONVERSATION_ID, chatStatusConvoId); 739 } 740 741 Uri uri = Uri.parse(mBaseUriString); 742 if (D) Log.d(TAG,"setOwnerStatus in: " + uri.toString()); 743 try { 744 if (D) Log.d(TAG,"setOwnerStatus call()..."); 745 Bundle myBundle = mProviderClient.call( 746 BluetoothMapContract.METHOD_SET_OWNER_STATUS, null, extras); 747 if (myBundle != null) 748 return ResponseCodes.OBEX_HTTP_OK; 749 else { 750 if (D) Log.d(TAG,"setOwnerStatus call failed"); 751 return ResponseCodes.OBEX_HTTP_NOT_IMPLEMENTED; 752 } 753 } catch (RemoteException e){ 754 mProviderClient = acquireUnstableContentProviderOrThrow(); 755 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 756 } catch (NullPointerException e) { 757 if(D) Log.e(TAG, "setOwnerStatus - if uri or method is null", e); 758 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 759 } catch (IllegalArgumentException e) { 760 if(D) Log.e(TAG, "setOwnerStatus - if uri is not known", e); 761 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 762 } 763 } 764 return ResponseCodes.OBEX_HTTP_UNAVAILABLE; 765 } 766 767 @Override 768 public int onSetPath(final HeaderSet request, final HeaderSet reply, final boolean backup, 769 final boolean create) { 770 String folderName; 771 BluetoothMapFolderElement folder; 772 notifyUpdateWakeLock(); 773 try { 774 folderName = (String)request.getHeader(HeaderSet.NAME); 775 } catch (Exception e) { 776 if(D) { 777 Log.e(TAG, "request headers error" , e); 778 } else { 779 Log.e(TAG, "request headers error"); 780 } 781 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 782 } 783 784 if (V) logHeader(request); 785 if (D) Log.d(TAG, "onSetPath name is " + folderName + 786 " backup: " + backup + 787 " create: " + create); 788 789 if(backup == true){ 790 if(mCurrentFolder.getParent() != null) 791 mCurrentFolder = mCurrentFolder.getParent(); 792 else 793 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 794 } 795 796 if (folderName == null || folderName.trim().isEmpty()) { 797 if(backup == false) 798 mCurrentFolder = mCurrentFolder.getRoot(); 799 } 800 else { 801 folder = mCurrentFolder.getSubFolder(folderName); 802 if(folder != null) 803 mCurrentFolder = folder; 804 else 805 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 806 } 807 if (V) Log.d(TAG, "Current Folder: " + mCurrentFolder.getName()); 808 return ResponseCodes.OBEX_HTTP_OK; 809 } 810 811 @Override 812 public void onClose() { 813 if (mCallback != null) { 814 Message msg = Message.obtain(mCallback); 815 msg.what = BluetoothMapService.MSG_SERVERSESSION_CLOSE; 816 msg.arg1 = mMasId; 817 msg.sendToTarget(); 818 if (D) Log.d(TAG, "onClose(): msg MSG_SERVERSESSION_CLOSE sent out."); 819 820 } 821 if(mProviderClient != null){ 822 mProviderClient.release(); 823 mProviderClient = null; 824 } 825 826 } 827 828 @Override 829 public int onGet(Operation op) { 830 notifyUpdateWakeLock(); 831 mIsAborted = false; 832 HeaderSet request; 833 String type; 834 String name; 835 byte[] appParamRaw = null; 836 BluetoothMapAppParams appParams = null; 837 try { 838 request = op.getReceivedHeader(); 839 type = (String)request.getHeader(HeaderSet.TYPE); 840 841 appParamRaw = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER); 842 if(appParamRaw != null) 843 appParams = new BluetoothMapAppParams(appParamRaw); 844 845 if (V) logHeader(request); 846 if (D) Log.d(TAG, "OnGet type is " + type ); 847 848 if (type == null) { 849 if (V) Log.d(TAG, "type is null?" + type); 850 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 851 } 852 853 if (type.equals(TYPE_GET_FOLDER_LISTING)) { 854 if (V && appParams != null) { 855 Log.d(TAG,"TYPE_GET_FOLDER_LISTING: MaxListCount = " 856 + appParams.getMaxListCount() 857 + ", ListStartOffset = " + appParams.getStartOffset()); 858 } 859 // Block until all packets have been send. 860 return sendFolderListingRsp(op, appParams); 861 } else if (type.equals(TYPE_GET_MESSAGE_LISTING)){ 862 name = (String)request.getHeader(HeaderSet.NAME); 863 if (V && appParams != null) { 864 Log.d(TAG,"TYPE_GET_MESSAGE_LISTING: folder name is: " + name + 865 ", MaxListCount = " + appParams.getMaxListCount() + 866 ", ListStartOffset = " + appParams.getStartOffset()); 867 Log.d(TAG,"SubjectLength = " + appParams.getSubjectLength() + 868 ", ParameterMask = " + appParams.getParameterMask()); 869 Log.d(TAG,"FilterMessageType = " + appParams.getFilterMessageType() ); 870 Log.d(TAG,"FilterPeriodBegin = " + appParams.getFilterPeriodBeginString() + 871 ", FilterPeriodEnd = " + appParams.getFilterPeriodEndString() + 872 ", FilterReadStatus = " + appParams.getFilterReadStatus()); 873 Log.d(TAG,"FilterRecipient = " + appParams.getFilterRecipient() + 874 ", FilterOriginator = " + appParams.getFilterOriginator()); 875 Log.d(TAG,"FilterPriority = " + appParams.getFilterPriority()); 876 long tmpLong = appParams.getFilterMsgHandle(); 877 Log.d(TAG,"FilterMsgHandle = " + ( 878 (tmpLong == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) ? "" : 879 Long.toHexString(tmpLong))); 880 SignedLongLong tmpLongLong = appParams.getFilterConvoId(); 881 Log.d(TAG,"FilterConvoId = " + ((tmpLongLong == null) ? "" : 882 Long.toHexString(tmpLongLong.getLeastSignificantBits()) ) ); 883 } 884 // Block until all packets have been send. 885 return sendMessageListingRsp(op, appParams, name); 886 887 } else if (type.equals(TYPE_GET_CONVO_LISTING)){ 888 name = (String)request.getHeader(HeaderSet.NAME); 889 if (V && appParams != null) { 890 Log.d(TAG,"TYPE_GET_CONVO_LISTING: name is" + name + 891 ", MaxListCount = " + appParams.getMaxListCount() + 892 ", ListStartOffset = " + appParams.getStartOffset()); 893 Log.d(TAG,"FilterLastActivityBegin = "+appParams.getFilterLastActivityBegin()); 894 Log.d(TAG,"FilterLastActivityEnd = " + appParams.getFilterLastActivityEnd()); 895 Log.d(TAG,"FilterReadStatus = " + appParams.getFilterReadStatus()); 896 Log.d(TAG,"FilterRecipient = " + appParams.getFilterRecipient()); 897 } 898 // Block until all packets have been send. 899 return sendConvoListingRsp(op, appParams,name); 900 } else if (type.equals(TYPE_GET_MAS_INSTANCE_INFORMATION)) { 901 if(V && appParams != null) { 902 Log.d(TAG,"TYPE_MESSAGE (GET): MASInstandeId = " 903 + appParams.getMasInstanceId()); 904 } 905 // Block until all packets have been send. 906 return sendMASInstanceInformationRsp(op, appParams); 907 } else if (type.equals(TYPE_MESSAGE)){ 908 name = (String)request.getHeader(HeaderSet.NAME); 909 if(V && appParams != null) { 910 Log.d(TAG,"TYPE_MESSAGE (GET): name is" + name + 911 ", Attachment = " + appParams.getAttachment() + 912 ", Charset = " + appParams.getCharset() + 913 ", FractionRequest = " + appParams.getFractionRequest()); 914 } 915 // Block until all packets have been send. 916 return sendGetMessageRsp(op, name, appParams, mMessageVersion); 917 } else { 918 Log.w(TAG, "unknown type request: " + type); 919 return ResponseCodes.OBEX_HTTP_NOT_ACCEPTABLE; 920 } 921 922 } catch (IllegalArgumentException e) { 923 Log.e(TAG, "Exception:", e); 924 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 925 } catch (ParseException e) { 926 Log.e(TAG, "Exception:", e); 927 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 928 } catch (Exception e) { 929 if(D) { 930 Log.e(TAG, "Exception occured while handling request",e); 931 } else { 932 Log.e(TAG, "Exception occured while handling request"); 933 } 934 if(mIsAborted == true) { 935 if(D) Log.d(TAG, "onGet Operation Aborted"); 936 return ResponseCodes.OBEX_HTTP_OK; 937 } else { 938 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 939 } 940 } 941 } 942 943 /** 944 * Generate and send the message listing response based on an application 945 * parameter header. This function call will block until complete or aborted 946 * by the peer. Fragmentation of packets larger than the obex packet size 947 * will be handled by this function. 948 * 949 * @param op 950 * The OBEX operation. 951 * @param appParams 952 * The application parameter header 953 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 954 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 955 */ 956 private int sendMessageListingRsp(Operation op, 957 BluetoothMapAppParams appParams, 958 String folderName){ 959 OutputStream outStream = null; 960 byte[] outBytes = null; 961 int maxChunkSize, bytesToWrite, bytesWritten = 0, listSize; 962 boolean hasUnread = false; 963 HeaderSet replyHeaders = new HeaderSet(); 964 BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); 965 BluetoothMapMessageListing outList; 966 if(appParams == null){ 967 appParams = new BluetoothMapAppParams(); 968 appParams.setMaxListCount(1024); 969 appParams.setStartOffset(0); 970 } 971 972 /* MAP Spec 1.3 introduces the following 973 * Messagehandle filtering: 974 * msgListing (messageHandle=X) -> other allowed filters: parametereMask, subjectMaxLength 975 * ConversationID filtering: 976 * msgListing (convoId empty) -> should work as normal msgListing in valid folders 977 * msgListing (convoId=0, no other filters) -> should return all messages in all folders 978 * msgListing (convoId=N, other filters) -> should return all messages in conversationID=N 979 * according to filters requested 980 */ 981 BluetoothMapFolderElement folderToList = null; 982 if (appParams.getFilterMsgHandle() != BluetoothMapAppParams.INVALID_VALUE_PARAMETER 983 || appParams.getFilterConvoId() != null) { 984 // If messageHandle or convoId filtering ignore folder 985 Log.v(TAG,"sendMessageListingRsp: ignore folder "); 986 folderToList = mCurrentFolder.getRoot(); 987 folderToList.setIngore(true); 988 } else { 989 folderToList = getFolderElementFromName(folderName); 990 if(folderToList == null) { 991 Log.w(TAG,"sendMessageListingRsp: folderToList == "+ 992 "null-sending OBEX_HTTP_BAD_REQUEST"); 993 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 994 } 995 Log.v(TAG,"sendMessageListingRsp: has sms " + folderToList.hasSmsMmsContent() + 996 "has email " + folderToList.hasEmailContent() + 997 "has IM " + folderToList.hasImContent() ); 998 } 999 1000 try { 1001 // Open the OBEX body stream 1002 outStream = op.openOutputStream(); 1003 1004 if(appParams.getMaxListCount() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1005 appParams.setMaxListCount(1024); 1006 1007 if(appParams.getStartOffset() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1008 appParams.setStartOffset(0); 1009 1010 // Check to see if we only need to send the size - hence no need to encode. 1011 if(appParams.getMaxListCount() != 0) { 1012 outList = mOutContent.msgListing(folderToList, appParams); 1013 // Generate the byte stream 1014 outAppParams.setMessageListingSize(outList.getCount()); 1015 String version; 1016 if(0 < (mRemoteFeatureMask & 1017 BluetoothMapUtils.MAP_FEATURE_MESSAGE_LISTING_FORMAT_V11_BIT)) { 1018 version = BluetoothMapUtils.MAP_V11_STR; 1019 } else { 1020 version = BluetoothMapUtils.MAP_V10_STR; 1021 } 1022 /* This will only set the version, the bit must also be checked before adding any 1023 * 1.1 bits to the listing. */ 1024 outBytes = outList.encode(mThreadIdSupport, version); 1025 hasUnread = outList.hasUnread(); 1026 } else { 1027 listSize = mOutContent.msgListingSize(folderToList, appParams); 1028 hasUnread = mOutContent.msgListingHasUnread(folderToList, appParams); 1029 outAppParams.setMessageListingSize(listSize); 1030 op.noBodyHeader(); 1031 } 1032 folderToList.setIngore(false); 1033 // Build the application parameter header 1034 // let the peer know if there are unread messages in the list 1035 if(hasUnread) { 1036 outAppParams.setNewMessage(1); 1037 }else{ 1038 outAppParams.setNewMessage(0); 1039 } 1040 if ((mRemoteFeatureMask & BluetoothMapUtils.MAP_FEATURE_DATABASE_INDENTIFIER_BIT) 1041 == BluetoothMapUtils.MAP_FEATURE_DATABASE_INDENTIFIER_BIT ) { 1042 outAppParams.setDatabaseIdentifier(0, mMasInstance.getDbIdentifier()); 1043 } 1044 if((mRemoteFeatureMask & BluetoothMapUtils.MAP_FEATURE_FOLDER_VERSION_COUNTER_BIT) 1045 == BluetoothMapUtils.MAP_FEATURE_FOLDER_VERSION_COUNTER_BIT) { 1046 // Force update of version counter if needed 1047 mObserver.refreshFolderVersionCounter(); 1048 outAppParams.setFolderVerCounter(mMasInstance.getFolderVersionCounter(), 0); 1049 } 1050 outAppParams.setMseTime(Calendar.getInstance().getTime().getTime()); 1051 replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, outAppParams.EncodeParams()); 1052 op.sendHeaders(replyHeaders); 1053 1054 } catch (IOException e) { 1055 Log.w(TAG,"sendMessageListingRsp: IOException - sending OBEX_HTTP_BAD_REQUEST", e); 1056 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1057 if(mIsAborted == true) { 1058 if(D) Log.d(TAG, "sendMessageListingRsp Operation Aborted"); 1059 return ResponseCodes.OBEX_HTTP_OK; 1060 } else { 1061 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1062 } 1063 } catch (IllegalArgumentException e) { 1064 Log.w(TAG,"sendMessageListingRsp: IllegalArgumentException"+ 1065 " - sending OBEX_HTTP_BAD_REQUEST", e); 1066 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1067 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1068 } 1069 1070 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1071 if(outBytes != null) { 1072 try { 1073 while (bytesWritten < outBytes.length && mIsAborted == false) { 1074 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1075 outStream.write(outBytes, bytesWritten, bytesToWrite); 1076 bytesWritten += bytesToWrite; 1077 } 1078 } catch (IOException e) { 1079 if(D) Log.w(TAG,e); 1080 // We were probably aborted or disconnected 1081 } finally { 1082 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1083 } 1084 if(bytesWritten != outBytes.length && !mIsAborted) { 1085 Log.w(TAG,"sendMessageListingRsp: bytesWritten != outBytes.length" + 1086 " - sending OBEX_HTTP_BAD_REQUEST"); 1087 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1088 } 1089 } else { 1090 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1091 } 1092 return ResponseCodes.OBEX_HTTP_OK; 1093 } 1094 1095 /** 1096 * Update the {@link BluetoothMapAppParams} object message type filter mask to only contain 1097 * message types supported by this mas instance. 1098 * Could the folder be used in stead? 1099 * @param appParams Reference to the object to update 1100 * @param overwrite True: The msgType will be overwritten to match the message types supported 1101 * by this MAS instance. False: any unsupported message types will be masked out. 1102 */ 1103 private void setMsgTypeFilterParams(BluetoothMapAppParams appParams, boolean overwrite) { 1104 int masFilterMask = 0; 1105 if(!mEnableSmsMms) { 1106 masFilterMask |= BluetoothMapAppParams.FILTER_NO_SMS_CDMA; 1107 masFilterMask |= BluetoothMapAppParams.FILTER_NO_SMS_GSM; 1108 masFilterMask |= BluetoothMapAppParams.FILTER_NO_MMS; 1109 } 1110 if(mAccount==null){ 1111 masFilterMask |= BluetoothMapAppParams.FILTER_NO_EMAIL; 1112 masFilterMask |= BluetoothMapAppParams.FILTER_NO_IM; 1113 } else { 1114 if(!(mAccount.getType() == BluetoothMapUtils.TYPE.EMAIL)) { 1115 masFilterMask |= BluetoothMapAppParams.FILTER_NO_EMAIL; 1116 } 1117 if(!(mAccount.getType() == BluetoothMapUtils.TYPE.IM)) { 1118 masFilterMask |= BluetoothMapAppParams.FILTER_NO_IM; 1119 } 1120 } 1121 if(overwrite) { 1122 appParams.setFilterMessageType(masFilterMask); 1123 } else { 1124 int newMask = appParams.getFilterMessageType(); 1125 if(newMask == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) { 1126 appParams.setFilterMessageType(newMask); 1127 } else { 1128 newMask |= masFilterMask; 1129 appParams.setFilterMessageType(newMask); 1130 } 1131 } 1132 } 1133 1134 /** 1135 * Generate and send the Conversation listing response based on an application 1136 * parameter header. This function call will block until complete or aborted 1137 * by the peer. Fragmentation of packets larger than the obex packet size 1138 * will be handled by this function. 1139 * 1140 * @param op 1141 * The OBEX operation. 1142 * @param appParams 1143 * The application parameter header 1144 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 1145 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 1146 */ 1147 private int sendConvoListingRsp(Operation op, 1148 BluetoothMapAppParams appParams, 1149 String folderName){ 1150 OutputStream outStream = null; 1151 byte[] outBytes = null; 1152 int maxChunkSize, bytesToWrite, bytesWritten = 0; 1153 //boolean hasUnread = false; 1154 HeaderSet replyHeaders = new HeaderSet(); 1155 BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); 1156 BluetoothMapConvoListing outList; 1157 if(appParams == null){ 1158 appParams = new BluetoothMapAppParams(); 1159 appParams.setMaxListCount(1024); 1160 appParams.setStartOffset(0); 1161 } 1162 // As the app parameters do not carry which message types to list, we set the filter here 1163 // to all message types supported by this instance. 1164 setMsgTypeFilterParams(appParams, true); 1165 1166 // Check to see if we only need to send the size - hence no need to encode. 1167 try { 1168 // Open the OBEX body stream 1169 outStream = op.openOutputStream(); 1170 1171 if(appParams.getMaxListCount() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1172 appParams.setMaxListCount(1024); 1173 1174 if(appParams.getStartOffset() == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1175 appParams.setStartOffset(0); 1176 1177 if(appParams.getMaxListCount() != 0) { 1178 outList = mOutContent.convoListing(appParams, false); 1179 outAppParams.setConvoListingSize(outList.getCount()); 1180 // Generate the byte stream 1181 outBytes = outList.encode(); // Include thread ID for clients that supports it. 1182 // hasUnread = outList.hasUnread(); 1183 if(D) Log.d(TAG, "outBytes size:"+ outBytes.length); 1184 } else { 1185 outList = mOutContent.convoListing(appParams, true); 1186 outAppParams.setConvoListingSize(outList.getCount()); 1187 if(mEnableSmsMms) { 1188 mOutContent.refreshSmsMmsConvoVersions(); 1189 } 1190 if(mAccount != null) { 1191 mOutContent.refreshImEmailConvoVersions(); 1192 } 1193 // Force update of version counter if needed 1194 mObserver.refreshConvoListVersionCounter(); 1195 if(0 < (mRemoteFeatureMask & 1196 BluetoothMapUtils.MAP_FEATURE_CONVERSATION_VERSION_COUNTER_BIT)) { 1197 outAppParams.setConvoListingVerCounter( 1198 mMasInstance.getCombinedConvoListVersionCounter(), 0); 1199 } 1200 op.noBodyHeader(); 1201 } 1202 if(D) Log.d(TAG, "outList size:"+ outList.getCount() 1203 + " MaxListCount: "+appParams.getMaxListCount()); 1204 outList = null; // We don't need it anymore - we might as well give it up for GC 1205 outAppParams.setDatabaseIdentifier(0, mMasInstance.getDbIdentifier()); 1206 1207 // Build the application parameter header 1208 // The MseTime is not in the CR - but I think it is missing. 1209 outAppParams.setMseTime(Calendar.getInstance().getTime().getTime()); 1210 replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, outAppParams.EncodeParams()); 1211 op.sendHeaders(replyHeaders); 1212 1213 } catch (IOException e) { 1214 Log.w(TAG,"sendConvoListingRsp: IOException - sending OBEX_HTTP_BAD_REQUEST", e); 1215 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1216 if(mIsAborted == true) { 1217 if(D) Log.d(TAG, "sendConvoListingRsp Operation Aborted"); 1218 return ResponseCodes.OBEX_HTTP_OK; 1219 } else { 1220 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1221 } 1222 } catch (IllegalArgumentException e) { 1223 Log.w(TAG,"sendConvoListingRsp: IllegalArgumentException" + 1224 " - sending OBEX_HTTP_BAD_REQUEST", e); 1225 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1226 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1227 } 1228 1229 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1230 if(outBytes != null) { 1231 try { 1232 while (bytesWritten < outBytes.length && mIsAborted == false) { 1233 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1234 outStream.write(outBytes, bytesWritten, bytesToWrite); 1235 bytesWritten += bytesToWrite; 1236 } 1237 } catch (IOException e) { 1238 if(D) Log.w(TAG,e); 1239 // We were probably aborted or disconnected 1240 } finally { 1241 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1242 } 1243 if(bytesWritten != outBytes.length && !mIsAborted) { 1244 Log.w(TAG,"sendConvoListingRsp: bytesWritten != outBytes.length" + 1245 " - sending OBEX_HTTP_BAD_REQUEST"); 1246 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1247 } 1248 } else { 1249 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1250 } 1251 return ResponseCodes.OBEX_HTTP_OK; 1252 } 1253 1254 /** 1255 * Generate and send the Folder listing response based on an application 1256 * parameter header. This function call will block until complete or aborted 1257 * by the peer. Fragmentation of packets larger than the obex packet size 1258 * will be handled by this function. 1259 * 1260 * @param op 1261 * The OBEX operation. 1262 * @param appParams 1263 * The application parameter header 1264 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 1265 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 1266 */ 1267 private int sendFolderListingRsp(Operation op, BluetoothMapAppParams appParams){ 1268 OutputStream outStream = null; 1269 byte[] outBytes = null; 1270 BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); 1271 int maxChunkSize, bytesWritten = 0; 1272 HeaderSet replyHeaders = new HeaderSet(); 1273 int bytesToWrite, maxListCount, listStartOffset; 1274 if(appParams == null){ 1275 appParams = new BluetoothMapAppParams(); 1276 appParams.setMaxListCount(1024); 1277 } 1278 1279 if(V) 1280 Log.v(TAG,"sendFolderList for " + mCurrentFolder.getName()); 1281 1282 try { 1283 maxListCount = appParams.getMaxListCount(); 1284 listStartOffset = appParams.getStartOffset(); 1285 1286 if(listStartOffset == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1287 listStartOffset = 0; 1288 1289 if(maxListCount == BluetoothMapAppParams.INVALID_VALUE_PARAMETER) 1290 maxListCount = 1024; 1291 1292 if(maxListCount != 0) 1293 { 1294 outBytes = mCurrentFolder.encode(listStartOffset, maxListCount); 1295 outStream = op.openOutputStream(); 1296 } else { 1297 // ESR08 specified that this shall only be included for MaxListCount=0 1298 outAppParams.setFolderListingSize(mCurrentFolder.getSubFolderCount()); 1299 op.noBodyHeader(); 1300 } 1301 1302 // Build and set the application parameter header 1303 replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, outAppParams.EncodeParams()); 1304 op.sendHeaders(replyHeaders); 1305 1306 } catch (IOException e1) { 1307 Log.w(TAG,"sendFolderListingRsp: IOException" + 1308 " - sending OBEX_HTTP_BAD_REQUEST Exception:", e1); 1309 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1310 if(mIsAborted == true) { 1311 if(D) Log.d(TAG, "sendFolderListingRsp Operation Aborted"); 1312 return ResponseCodes.OBEX_HTTP_OK; 1313 } else { 1314 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1315 } 1316 } catch (IllegalArgumentException e1) { 1317 Log.w(TAG,"sendFolderListingRsp: IllegalArgumentException" + 1318 " - sending OBEX_HTTP_BAD_REQUEST Exception:", e1); 1319 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1320 return ResponseCodes.OBEX_HTTP_PRECON_FAILED; 1321 } 1322 1323 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1324 1325 if(outBytes != null) { 1326 try { 1327 while (bytesWritten < outBytes.length && mIsAborted == false) { 1328 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1329 outStream.write(outBytes, bytesWritten, bytesToWrite); 1330 bytesWritten += bytesToWrite; 1331 } 1332 } catch (IOException e) { 1333 // We were probably aborted or disconnected 1334 } finally { 1335 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1336 } 1337 if(V) 1338 Log.v(TAG,"sendFolderList sent " + bytesWritten+" bytes out of "+ outBytes.length); 1339 if(bytesWritten == outBytes.length || mIsAborted) 1340 return ResponseCodes.OBEX_HTTP_OK; 1341 else 1342 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1343 } 1344 1345 return ResponseCodes.OBEX_HTTP_OK; 1346 } 1347 1348 /** 1349 * Generate and send the get MAS Instance Information response based on an MAS Instance 1350 * 1351 * @param op 1352 * The OBEX operation. 1353 * @param appParams 1354 * The application parameter header 1355 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 1356 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 1357 */ 1358 private int sendMASInstanceInformationRsp(Operation op, BluetoothMapAppParams appParams){ 1359 1360 OutputStream outStream = null; 1361 byte[] outBytes = null; 1362 String outString = null; 1363 int maxChunkSize, bytesToWrite, bytesWritten = 0; 1364 1365 try { 1366 if(mMasId == appParams.getMasInstanceId()) { 1367 if(mAccount != null) { 1368 if(mAccount.getType() == TYPE.EMAIL) { 1369 outString = (mAccount.getName() != null) ? mAccount.getName() : 1370 BluetoothMapMasInstance.TYPE_EMAIL_STR; 1371 } else if(mAccount.getType() == TYPE.IM){ 1372 outString = mAccount.getUciFull(); 1373 if(outString == null) { 1374 String uci = mAccount.getUci(); 1375 // TODO: Do we need to align this with HF/PBAP 1376 StringBuilder sb = 1377 new StringBuilder(uci == null ? 5 : 5 + uci.length()); 1378 sb.append("un"); 1379 if(mMasId < 10) { 1380 sb.append("00"); 1381 } else if(mMasId < 100) { 1382 sb.append("0"); 1383 } 1384 sb.append(mMasId); 1385 if(uci != null) { 1386 sb.append(":").append(uci); 1387 } 1388 outString = sb.toString(); 1389 } 1390 } 1391 } else { 1392 outString = BluetoothMapMasInstance.TYPE_SMS_MMS_STR; 1393 // TODO: Add phone number if possible 1394 } 1395 } else { 1396 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1397 } 1398 1399 /* Ensure byte array max length is 200 containing valid UTF-8 characters */ 1400 outBytes = BluetoothMapUtils.truncateUtf8StringToBytearray(outString, 1401 MAS_INSTANCE_INFORMATION_LENGTH); 1402 1403 // Open the OBEX body stream 1404 outStream = op.openOutputStream(); 1405 1406 } catch (IOException e) { 1407 Log.w(TAG,"sendMASInstanceInformationRsp: IOException" + 1408 " - sending OBEX_HTTP_BAD_REQUEST", e); 1409 if(mIsAborted == true) { 1410 if(D) Log.d(TAG, "sendMASInstanceInformationRsp Operation Aborted"); 1411 return ResponseCodes.OBEX_HTTP_OK; 1412 } else { 1413 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1414 } 1415 } 1416 1417 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1418 1419 if(outBytes != null) { 1420 try { 1421 while (bytesWritten < outBytes.length && mIsAborted == false) { 1422 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1423 outStream.write(outBytes, bytesWritten, bytesToWrite); 1424 bytesWritten += bytesToWrite; 1425 } 1426 } catch (IOException e) { 1427 // We were probably aborted or disconnected 1428 } finally { 1429 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1430 } 1431 if(V) 1432 Log.v(TAG,"sendMASInstanceInformationRsp sent " + bytesWritten + 1433 " bytes out of "+ outBytes.length); 1434 if(bytesWritten == outBytes.length || mIsAborted) 1435 return ResponseCodes.OBEX_HTTP_OK; 1436 else 1437 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1438 } 1439 return ResponseCodes.OBEX_HTTP_OK; 1440 } 1441 1442 /** 1443 * Generate and send the get message response based on an application 1444 * parameter header and a handle. 1445 * 1446 * @param op 1447 * The OBEX operation. 1448 * @param handle 1449 * The handle of the requested message 1450 * @param appParams 1451 * The application parameter header 1452 * @param version 1453 * The string representation of the version number(i.e. "1.0") 1454 * @return {@link ResponseCodes.OBEX_HTTP_OK} on success or 1455 * {@link ResponseCodes.OBEX_HTTP_BAD_REQUEST} on error. 1456 */ 1457 private int sendGetMessageRsp(Operation op, String handle, 1458 BluetoothMapAppParams appParams, String version){ 1459 OutputStream outStream = null; 1460 byte[] outBytes = null; 1461 int maxChunkSize, bytesToWrite, bytesWritten = 0; 1462 1463 try { 1464 outBytes = mOutContent.getMessage(handle, appParams, mCurrentFolder, version); 1465 outStream = op.openOutputStream(); 1466 1467 // If it is a fraction request of Email message, set header before responding 1468 if ((BluetoothMapUtils.getMsgTypeFromHandle(handle).equals(TYPE.EMAIL)|| 1469 (BluetoothMapUtils.getMsgTypeFromHandle(handle).equals(TYPE.IM))) && 1470 (appParams.getFractionRequest() == 1471 BluetoothMapAppParams.FRACTION_REQUEST_FIRST)) { 1472 BluetoothMapAppParams outAppParams = new BluetoothMapAppParams(); 1473 HeaderSet replyHeaders = new HeaderSet(); 1474 outAppParams.setFractionDeliver(BluetoothMapAppParams.FRACTION_DELIVER_LAST); 1475 // Build and set the application parameter header 1476 replyHeaders.setHeader(HeaderSet.APPLICATION_PARAMETER, 1477 outAppParams.EncodeParams()); 1478 op.sendHeaders(replyHeaders); 1479 if(V) Log.v(TAG,"sendGetMessageRsp fractionRequest - " + 1480 "set FRACTION_DELIVER_LAST header"); 1481 } 1482 1483 } catch (IOException e) { 1484 Log.w(TAG,"sendGetMessageRsp: IOException - sending OBEX_HTTP_BAD_REQUEST", e); 1485 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1486 if(mIsAborted == true) { 1487 if(D) Log.d(TAG, "sendGetMessageRsp Operation Aborted"); 1488 return ResponseCodes.OBEX_HTTP_OK; 1489 } else { 1490 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1491 } 1492 } catch (IllegalArgumentException e) { 1493 Log.w(TAG,"sendGetMessageRsp: IllegalArgumentException (e.g. invalid handle) - " + 1494 "sending OBEX_HTTP_BAD_REQUEST", e); 1495 if(outStream != null) { try { outStream.close(); } catch (IOException ex) {} } 1496 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1497 } 1498 1499 maxChunkSize = op.getMaxPacketSize(); // This must be called after setting the headers. 1500 1501 if(outBytes != null) { 1502 try { 1503 while (bytesWritten < outBytes.length && mIsAborted == false) { 1504 bytesToWrite = Math.min(maxChunkSize, outBytes.length - bytesWritten); 1505 outStream.write(outBytes, bytesWritten, bytesToWrite); 1506 bytesWritten += bytesToWrite; 1507 } 1508 } catch (IOException e) { 1509 // We were probably aborted or disconnected 1510 if(D && e.getMessage().equals("Abort Received")) { 1511 Log.w(TAG, "getMessage() Aborted...", e); 1512 } 1513 } finally { 1514 if(outStream != null) { try { outStream.close(); } catch (IOException e) {} } 1515 } 1516 if(bytesWritten == outBytes.length || mIsAborted) 1517 return ResponseCodes.OBEX_HTTP_OK; 1518 else 1519 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1520 } 1521 1522 return ResponseCodes.OBEX_HTTP_OK; 1523 } 1524 1525 @Override 1526 public int onDelete(HeaderSet request, HeaderSet reply) { 1527 if(D) Log.v(TAG, "onDelete() " + request.toString()); 1528 mIsAborted = false; 1529 notifyUpdateWakeLock(); 1530 String type, name; 1531 byte[] appParamRaw; 1532 BluetoothMapAppParams appParams = null; 1533 1534 /* TODO: If this is to be placed here, we need to cleanup - e.g. the exception handling */ 1535 try { 1536 type = (String)request.getHeader(HeaderSet.TYPE); 1537 1538 name = (String)request.getHeader(HeaderSet.NAME); 1539 appParamRaw = (byte[])request.getHeader(HeaderSet.APPLICATION_PARAMETER); 1540 if(appParamRaw != null) 1541 appParams = new BluetoothMapAppParams(appParamRaw); 1542 if(D) Log.d(TAG,"type = " + type + ", name = " + name); 1543 if(type.equals(TYPE_SET_NOTIFICATION_FILTER)) { 1544 if(V) { 1545 Log.d(TAG,"TYPE_SET_NOTIFICATION_FILTER: NotificationFilter: " 1546 + appParams.getNotificationFilter()); 1547 } 1548 mObserver.setNotificationFilter(appParams.getNotificationFilter()); 1549 return ResponseCodes.OBEX_HTTP_OK; 1550 } else if (type.equals(TYPE_SET_OWNER_STATUS)) { 1551 if(V) { 1552 Log.d(TAG,"TYPE_SET_OWNER_STATUS:" + 1553 " PresenceAvailability " + appParams.getPresenceAvailability() + 1554 ", PresenceStatus: " + appParams.getPresenceStatus() + 1555 ", LastActivity: " + appParams.getLastActivityString() + 1556 ", ChatStatus: " + appParams.getChatState() + 1557 ", ChatStatusConvoId: " + appParams.getChatStateConvoIdString()); 1558 } 1559 return setOwnerStatus(name, appParams); 1560 } 1561 1562 } catch (RemoteException e){ 1563 //reload the providerClient and return error 1564 try { 1565 mProviderClient = acquireUnstableContentProviderOrThrow(); 1566 }catch (RemoteException e2){ 1567 //should not happen 1568 } 1569 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1570 }catch (Exception e) { 1571 1572 if(D) { 1573 Log.e(TAG, "Exception occured while handling request",e); 1574 } else { 1575 Log.e(TAG, "Exception occured while handling request"); 1576 } 1577 if(mIsAborted) { 1578 return ResponseCodes.OBEX_HTTP_OK; 1579 } else { 1580 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1581 } 1582 } 1583 return ResponseCodes.OBEX_HTTP_BAD_REQUEST; 1584 } 1585 1586 private void notifyUpdateWakeLock() { 1587 if(mCallback != null) { 1588 Message msg = Message.obtain(mCallback); 1589 msg.what = BluetoothMapService.MSG_ACQUIRE_WAKE_LOCK; 1590 msg.sendToTarget(); 1591 } 1592 } 1593 1594 private static final void logHeader(HeaderSet hs) { 1595 Log.v(TAG, "Dumping HeaderSet " + hs.toString()); 1596 try { 1597 Log.v(TAG, "CONNECTION_ID : " + hs.getHeader(HeaderSet.CONNECTION_ID)); 1598 Log.v(TAG, "NAME : " + hs.getHeader(HeaderSet.NAME)); 1599 Log.v(TAG, "TYPE : " + hs.getHeader(HeaderSet.TYPE)); 1600 Log.v(TAG, "TARGET : " + hs.getHeader(HeaderSet.TARGET)); 1601 Log.v(TAG, "WHO : " + hs.getHeader(HeaderSet.WHO)); 1602 Log.v(TAG, "APPLICATION_PARAMETER : " + hs.getHeader(HeaderSet.APPLICATION_PARAMETER)); 1603 } catch (IOException e) { 1604 Log.e(TAG, "dump HeaderSet error " + e); 1605 } 1606 Log.v(TAG, "NEW!!! Dumping HeaderSet END"); 1607 } 1608} 1609