Bug 1003663 - Handle the case that user turn off BT during the middle of BT reply. r=echou, f=shuang
authorJamin Liu <jaliu@mozilla.com>
Thu, 08 May 2014 19:20:15 +0800
changeset 190939 5bc7a1c7054c0c1603f9012c76e0a7cd609c4115
parent 190936 d7650df4283668c0d688aa937b7624725a4db4e0
child 190942 1e540e25dd2d61f166814469d8f13447846442b0
push idunknown
push userunknown
push dateunknown
reviewersechou
bugs1003663
milestone32.0a1
Bug 1003663 - Handle the case that user turn off BT during the middle of BT reply. r=echou, f=shuang - End the session if BT is turn off during the middle of BT profile connection. - Clear static queues(array) when BT is on.
dom/bluetooth/BluetoothProfileController.cpp
dom/bluetooth/BluetoothProfileController.h
dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
--- a/dom/bluetooth/BluetoothProfileController.cpp
+++ b/dom/bluetooth/BluetoothProfileController.cpp
@@ -1,20 +1,21 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothProfileController.h"
-#include "BluetoothReplyRunnable.h"
 
 #include "BluetoothA2dpManager.h"
 #include "BluetoothHfpManager.h"
 #include "BluetoothHidManager.h"
+#include "BluetoothReplyRunnable.h"
+#include "BluetoothService.h"
 #include "BluetoothUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "nsComponentManagerUtils.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 #define BT_LOGR_PROFILE(mgr, msg, ...)               \
@@ -212,16 +213,21 @@ CheckProfileStatusCallback::Notify(nsITi
 void
 BluetoothProfileController::StartSession()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mDeviceAddress.IsEmpty());
   MOZ_ASSERT(mProfilesIndex == -1);
   MOZ_ASSERT(mTimer);
 
+  if (!IsBtServiceAvailable()) {
+    EndSession();
+    return;
+  }
+
   if (mProfiles.Length() < 1) {
     BT_LOGR("No queued profile.");
     EndSession();
     return;
   }
 
   if (mTimer) {
     mTimer->InitWithCallback(new CheckProfileStatusCallback(this),
@@ -235,16 +241,22 @@ BluetoothProfileController::StartSession
 
 void
 BluetoothProfileController::EndSession()
 {
   MOZ_ASSERT(mRunnable && mCallback);
 
   BT_LOGR("mSuccess %d", mSuccess);
 
+  // Don't have to check profile status and retrigger session after connection
+  // timeout, since session is end.
+  if (mTimer) {
+    mTimer->Cancel();
+  }
+
   // The action has completed, so the DOM request should be replied then invoke
   // the callback.
   if (mSuccess) {
     DispatchBluetoothReply(mRunnable, BluetoothValue(true), EmptyString());
   } else if (mConnect) {
     DispatchBluetoothReply(mRunnable, BluetoothValue(true),
                            NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
   } else {
@@ -260,30 +272,42 @@ BluetoothProfileController::Next()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mDeviceAddress.IsEmpty());
   MOZ_ASSERT(mProfilesIndex < (int)mProfiles.Length());
   MOZ_ASSERT(mTimer);
 
   mCurrentProfileFinished = false;
 
+  if (!IsBtServiceAvailable()) {
+    EndSession();
+    return;
+  }
+
   if (++mProfilesIndex >= (int)mProfiles.Length()) {
     EndSession();
     return;
   }
 
   BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "");
 
   if (mConnect) {
     mProfiles[mProfilesIndex]->Connect(mDeviceAddress, this);
   } else {
     mProfiles[mProfilesIndex]->Disconnect(this);
   }
 }
 
+bool
+BluetoothProfileController::IsBtServiceAvailable() const
+{
+  BluetoothService* bs = BluetoothService::Get();
+  return (bs && bs->IsEnabled() && !bs->IsToggling());
+}
+
 void
 BluetoothProfileController::NotifyCompletion(const nsAString& aErrorStr)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mTimer);
   MOZ_ASSERT(mProfiles.Length() > 0);
 
   BT_LOGR_PROFILE(mProfiles[mProfilesIndex], "<%s>",
@@ -303,11 +327,16 @@ BluetoothProfileController::NotifyComple
 void
 BluetoothProfileController::GiveupAndContinue()
 {
   MOZ_ASSERT(!mCurrentProfileFinished);
   MOZ_ASSERT(mProfilesIndex < (int)mProfiles.Length());
 
   BT_LOGR_PROFILE(mProfiles[mProfilesIndex], ERR_OPERATION_TIMEOUT);
   mProfiles[mProfilesIndex]->Reset();
-  Next();
+
+  if (IsBtServiceAvailable()) {
+    Next();
+  } else {
+    EndSession();
+  }
 }
 
--- a/dom/bluetooth/BluetoothProfileController.h
+++ b/dom/bluetooth/BluetoothProfileController.h
@@ -117,16 +117,19 @@ private:
                   bool aCheckConnected = false);
 
   // Add specified profile into array
   void AddProfileWithServiceClass(BluetoothServiceClass aClass);
 
   // Connect/Disconnect next profile in the array
   void Next();
 
+  // Is Bluetooth service available for profile connection/disconnection ?
+  bool IsBtServiceAvailable() const;
+
   const bool mConnect;
   nsString mDeviceAddress;
   nsRefPtr<BluetoothReplyRunnable> mRunnable;
   BluetoothProfileControllerCallback mCallback;
 
   bool mCurrentProfileFinished;
   bool mSuccess;
   int8_t mProfilesIndex;
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -90,16 +90,24 @@ public:
   SetupAfterEnabledTask()
   { }
 
   NS_IMETHOD
   Run()
   {
     MOZ_ASSERT(NS_IsMainThread());
 
+    // Bluetooth just enabled, clear profile controllers and runnable arrays.
+    sControllerArray.Clear();
+    sBondingRunnableArray.Clear();
+    sChangeDiscoveryRunnableArray.Clear();
+    sGetDeviceRunnableArray.Clear();
+    sSetPropertyRunnableArray.Clear();
+    sUnbondingRunnableArray.Clear();
+
     // Bluetooth scan mode is NONE by default
     bt_scan_mode_t mode = BT_SCAN_MODE_CONNECTABLE;
     bt_property_t prop;
     prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
     prop.val = (void*)&mode;
     prop.len = sizeof(mode);
 
     NS_ENSURE_TRUE(sBtInterface, NS_ERROR_FAILURE);
@@ -1144,18 +1152,19 @@ static void
 NextBluetoothProfileController()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // First, remove the task at the front which has been already done.
   NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty());
   sControllerArray.RemoveElementAt(0);
   // Re-check if the task array is empty, if it's not, the next task will begin.
-  NS_ENSURE_FALSE_VOID(sControllerArray.IsEmpty());
-  sControllerArray[0]->StartSession();
+  if (!sControllerArray.IsEmpty()) {
+    sControllerArray[0]->StartSession();
+  }
 }
 
 static void
 ConnectDisconnect(bool aConnect, const nsAString& aDeviceAddress,
                   BluetoothReplyRunnable* aRunnable,
                   uint16_t aServiceUuid, uint32_t aCod = 0)
 {
   MOZ_ASSERT(NS_IsMainThread());