Bluetooth OPP Profile

用這個profile之前,要確保oppservice啓動,在在BluetoothOppProvider的public Uri insert(Uri uri, ContentValues values) 方法中去啓動。OPP可用來發送文件,也可用接收文件,這篇日誌記錄簡單的opp發送文件和接收文件的過程。

手機發送文件,其他模塊調用ChooserActivity,創建出共享的dialog。選擇用藍牙發送,將啓動BluetoothOppLauncherActivity,在搜索完設備選擇了一個設備後:
1)調用DevicePickerFragment類裏的sendDevicePickedIntent方法,將BluetoothDevicePicker.ACTION_DEVICE_SELECTED廣播給BluetoothOppReceiver處理:
            // Insert transfer session record to database
            mOppManager.startTransfer(remoteDevice);
BluetoothOppManager調用內部類InsertShareInfoThread將發送的文件加入數據庫的線程啓動。文件加入DB後,將由BluetoothOppProvider向其他APP提供數據。
code: insertSingleShare()
{
     final Uri contentUri = mContext.getContentResolver().insert(BluetoothShare.CONTENT_URI,values);
}
監聽數據庫變化的:
mObserver = new BluetoothShareContentObserver();
        getContentResolver().registerContentObserver(BluetoothShare.CONTENT_URI, true, mObserver);
注:將文件加入數據庫後,在BluetoothOppService的內部類BluetoothShareContentObserver會收到數據改變的事件,調用onChange()-----updateFromProvider()---updatethread;
updatethread裏調用insertShare,這函數裏面用到BluetoothOppTransfer,然後啓動了BluetoothOppTransfer(mTransfer.start();)。

2)BluetoothOppTransfer的start裏 Check Bluetooth status, Start handler thread, new a thread to connect to target device.......
(選擇設備之後,和藍牙耳機連接一樣,會收到BOND_STATE_CHANGED和Property Changed,調用onPropertyChanged()在bluetootheventloop類中,獲取UUID。然後在BluetoothOppTransfer的 mReceiver中處理BluetoothDevice.ACTION_UUID,此操作執行構建opush channel.)
在startConnectSession開始connect to target socket,channel沒有創建成功就先doOpushSdp(做opush channel)。連接過程處理完畢,收到RFCOMM_CONNECTED連接後startObexSession。
具體的發送的實現在BluetoothOppObexClientSession實現。

 

接收文件的過程:
1)BluetoothServerSocket監聽其他設備發過來的連接請求(socket監聽到請求時,在opprfcommlistener裏clientSocket = mBtServerSocket.accept();然後把消息發給bluetoothoppservice),在BluetoothOppService收到 BluetoothOppRfcommListener.MSG_INCOMING_BTOPP_CONNECTION:{createServerSession(transport);}開始一個server session(自動連接,已經授權)。
2)BluetoothServerSocket監聽其他設備發過來的連接請求,BluetoothOppReceiver收到ACTION_INCOMING_FILE_CONFIRM,啓動BluetoothOppIncomingFileConfirmActivity彈出對話框給用戶確認是否接收文件,點擊確定按鈕:
                   // Update database
                    mUpdateValues = new ContentValues();
                    mUpdateValues.put(BluetoothShare.USER_CONFIRMATION,
                            BluetoothShare.USER_CONFIRMATION_CONFIRMED);
                    this.getContentResolver().update(mUri, mUpdateValues, null, null);

數據庫有變化時,處理跟發送文件一致,在insertShare,這函數裏面用到BluetoothOppTransfer,然後啓動了BluetoothOppTransfer(mServerTransfer.start();)。

通過調用BluetoothAdapter的listenUsingRfcommWithServiceRecord(String, UUID)方法來獲取BluetoothServerSocket(UUID用於客戶端與服務器端之間的配對)
調用BluetoothServerSocket的accept()方法監聽連接請求,如果收到請求,則返回一個BluetoothSocket實例(此方法爲block方法,應置於新線程中)
如果不想在accept其他的連接,則調用BluetoothServerSocket的close()方法釋放資源(調用該方法後,之前獲得的BluetoothSocket實例並沒有close。但由於RFCOMM一個時刻只允許在一條channel中有一個連接,則一般在accept一個連接後,便close掉BluetoothServerSocket).BluetoothOppReceiveFileInfo處理接收文件的東西,包括存儲位置(存儲於卡上,沒有則返回)       if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
判斷存儲空間,文件名是否正確,有重複文件則用chooseUniquefilename()加一個隨機數。

發佈了25 篇原創文章 · 獲贊 2 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章