选择设备之后就是发送了一个BluetoothDevicePicker.ACTION_DEVICE_SELECTED的broadcast来通知我们选择了某个设备进行文件的传输。对这个broadcast的监听就只有一个,就是BluetoothOppReceiver.cpp
设备点击之后,会发送一个ACTION_DEVICE_SELECTED的broadcast,BluetoothOppReceiver收到这个broadcast后,会启动insertThread来把需要分享的文件内容加入到对应的数据库中并引起后续的发送操作,同时在ui上显示“正在向**发送文件”的toast。
else if (action->equals(BluetoothDevicePicker::ACTION_DEVICE_SELECTED())) {
sp<BluetoothOppManager> mOppManager = BluetoothOppManager::getInstance(context);//得到选中的设备
sp<BluetoothDevice> remoteDevice = safe_cast<BluetoothDevice *>(intent->getParcelableExtra(BluetoothDevice::EXTRA_DEVICE()));
GLOGV("Received BT device selected intent, bt device: %s", SP_TOSTRING_STR(remoteDevice));
// Insert transfer session record to database
mOppManager->startTransfer(remoteDevice);
//显示正在向。。。传输文件的信息
int32_t batchSize = mOppManager->getBatchSize();
if (mOppManager->mMultipleFlag) {
mToastText = context->getString(R::string::bt_toast_5, Integer::toString(batchSize)->string(),deviceName->string());
} else {
mToastText = context->getString(R::string::bt_toast_4, deviceName->string());
}
Toast::makeText(context,mToastText, Toast::LENGTH_SHORT)->show();
}
void BluetoothOppManager::startTransfer(const sp<BluetoothDevice>& device) {
GLOGENTRY();
GLOGI("Active InsertShareThread number is : %d", mInsertShareThreadNum);
sp<InsertShareInfoThread> insertThread;
{
RecursiveMutex::Autolock _l(mBluetoothOppManagerMutex);
if (mInsertShareThreadNum > ALLOWED_INSERT_SHARE_THREAD_NUMBER) {
LOGE("Too many shares user triggered concurrently!");
return;
/*
// Notice user
// TODO TODO TODO
// check due to different translation
// sp<Intent> in = new Intent(mContext, BluetoothOppBtErrorActivity.class);
sp<Intent> in = new Intent();
sp<ComponentName> component = new ComponentName(sp<String>(new String("BluetoothOppPbapService")), sp<String>(new String("BluetoothOppBtErrorActivity")));
in->setComponent(component);
in->setFlags(Intent::FLAG_ACTIVITY_NEW_TASK);
// TODO TODO TODO
// check due to different translation
// in->putExtra(new String("title"), mContext->getString(R.string.enabling_progress_title));
// in->putExtra(new String("content"), mContext->getString(R.string.ErrorTooManyRequests));
in->putExtra(new String("title"), mContext->getString(R::string::enabling_progress_title));
in->putExtra(new String("content"), mContext->getString(R::string::ErrorTooManyRequests));
mContext->startActivity(in);
return;
*/
}
insertThread = new InsertShareInfoThread(device, mMultipleFlag, mMimeTypeOfSendingFile,
mUriOfSendingFile, mMimeTypeOfSendingFiles, mUrisOfSendingFiles,
mIsHandoverInitiated, this);
if (mMultipleFlag) {
mfileNumInBatch = mUrisOfSendingFiles->size();
}
}
insertThread->run("Insert ShareInfo Thread");
}
BluetoothOppManager::InsertShareInfoThread::InsertShareInfoThread(const sp<BluetoothDevice>& device, bool multiple,
const sp<String>& typeOfSingleFile, const sp<String>& uri, const sp<String>& typeOfMultipleFiles,
const sp<GArrayList<Uri> >& uris, bool handoverInitiated, const wp<BluetoothOppManager>& bluetoothoppmanager)
: PREINIT_DYNAMIC()
, mRemoteDevice(device)
, mTypeOfSingleFile(typeOfSingleFile)
, mUri(uri)
, mTypeOfMultipleFiles(typeOfMultipleFiles)
, mUris(uris)
, mIsMultiple(multiple)
, mIsHandoverInitiated(handoverInitiated)
, condition(false)
, mwpbtom(bluetoothoppmanager) {
GLOGENTRY();
sp<BluetoothOppManager> mspbtom = mwpbtom.promote();
CHECK_NULL_POINTER_RETURN(mspbtom);
{
RecursiveMutex::Autolock _l(mspbtom->mBluetoothOppManagerMutex);
mspbtom->mInsertShareThreadNum++;
}
GLOGV("Thread id is: %d", this->getTid());
}
bool BluetoothOppManager::InsertShareInfoThread::threadLoop() {
GLOGENTRY();
sp<BluetoothOppManager> mspbtom = mwpbtom.promote();
CHECK_NULL_POINTER_RETURN_FALSE(mspbtom);
Process::setThreadPriority(Process::THREAD_PRIORITY_BACKGROUND);
Looper::prepare();
if (mRemoteDevice == NULL) {
LOGE("Target bt device is null!");
return false;
}
if (mIsMultiple) {
insertMultipleShare();
} else {
insertSingleShare();
}
{
RecursiveMutex::Autolock _l(mspbtom->mBluetoothOppManagerMutex);
mspbtom->mInsertShareThreadNum--;
}
mConLock.lock();
condition = true;
mThreadStartCondition.broadcast();
mConLock.unlock();
Looper::loop();
return false;
}
void BluetoothOppManager::InsertShareInfoThread::insertSingleShare() {
GLOGENTRY();
sp<BluetoothOppManager> mspbtom = mwpbtom.promote();
CHECK_NULL_POINTER_RETURN(mspbtom);
sp<ContentValues> values = new ContentValues();
values->put(BluetoothShare::URI(), mUri);
values->put(BluetoothShare::MIMETYPE(), mTypeOfSingleFile);
values->put(BluetoothShare::DESTINATION(), mRemoteDevice->getAddress());
if (mIsHandoverInitiated) {
values->put(BluetoothShare::USER_CONFIRMATION(), BluetoothShare::USER_CONFIRMATION_HANDOVER_CONFIRMED);
}
sp<Uri> contentUri = mspbtom->mContext->getContentResolver()->insert(BluetoothShare::CONTENT_URI(), values);
GLOGI("Insert contentUri: %s to device: %s", SP_TOSTRING_STR(contentUri), SP_STRING_STR(mspbtom->getDeviceName(mRemoteDevice)));
}
对insert的处理有以下几个比较重要的操作:
1)创建一个可读/可写的database
2)启动了BluetoothOppService
3)通知database的改变,调用对应的onChange函数
sp<Uri> BluetoothOppProvider::insert(const sp<Uri>& uri, const sp<ContentValues>& values) {
GLOGENTRY();
GLOGI("BluetoothOppProvider insert");
//创建一个可读可写的数据
sp<SQLiteDatabase> db = mOpenHelper->getWritableDatabase();
sp<UriMatcher> urimatcher = sURIMatcher();
CHECK_NULL_POINTER_RETURN_NULL(urimatcher);
GLOGI("BluetoothOppProvider::insert 1");
int32_t match = urimatcher->match(uri);
GLOGI("BluetoothOppProvider::insert 2");
if (match != SHARES) {
GLOGD("calling insert on an unknown/invalid URI: %s" , SP_TOSTRING_STR(uri));
}
sp<ContentValues> filteredValues = new ContentValues();
//得到对应values中的信息
copyString(BluetoothShare::URI(), values, filteredValues);
copyString(BluetoothShare::FILENAME_HINT(), values, filteredValues);
copyString(BluetoothShare::MIMETYPE(), values, filteredValues);
copyString(BluetoothShare::DESTINATION(), values, filteredValues);
copyInteger(BluetoothShare::VISIBILITY(), values, filteredValues);
copyInteger(BluetoothShare::TOTAL_BYTES(), values, filteredValues);
// if (values->getAsInteger(BluetoothShare::VISIBILITY()) == NULL) {
filteredValues->put(BluetoothShare::VISIBILITY(), BluetoothShare::VISIBILITY_VISIBLE);
// }
int32_t dir = values->getAsInteger(BluetoothShare::DIRECTION());
int32_t con = values->getAsInteger(BluetoothShare::USER_CONFIRMATION());
sp<String> address = values->getAsString(BluetoothShare::DESTINATION());
if (values->getAsInteger(BluetoothShare::DIRECTION()) == 0) {
dir = BluetoothShare::DIRECTION_OUTBOUND;
}
if (dir == BluetoothShare::DIRECTION_OUTBOUND && con == 0) {
con = BluetoothShare::USER_CONFIRMATION_AUTO_CONFIRMED;
}
if (dir == BluetoothShare::DIRECTION_INBOUND && con == 0) {
con = BluetoothShare::USER_CONFIRMATION_PENDING;
}
filteredValues->put(BluetoothShare::USER_CONFIRMATION(), con);
filteredValues->put(BluetoothShare::DIRECTION(), dir);
filteredValues->put(BluetoothShare::STATUS(), BluetoothShare::STATUS_PENDING);
filteredValues->put(Constants::MEDIA_SCANNED(), 0);
int64_t ts = values->getAsLong(BluetoothShare::TIMESTAMP());
if (ts == 0) {
ts = System::currentTimeMillis();
}
filteredValues->put(BluetoothShare::TIMESTAMP(), ts);
GLOGI("start BluetoothOppService");
sp<Context> context = getContext();
sp<Intent> intent = new Intent();
sp<ComponentName> component = new ComponentName(sp<String>(new String("BluetoothOppPbapService")), sp<String>(new String("BluetoothOppService")));
intent->setComponent(component);
//启动BluetoothOppService这个服务
context->startService(intent);
// context->startService(new Intent(context, Class::forName(new String("BluetoothOppService"))));
int64_t rowID = db->insert(DB_TABLE(), NULL, filteredValues);
sp<Uri> ret = NULL;
if (rowID != -1) {
GLOGI("rowID is not -1");
//再次启动这个服务
context->startService(intent);
// context->startService(new Intent(context, Class::forName(new String("BluetoothOppService"))));
ret = Uri::parse(BluetoothShare::CONTENT_URI()->toString() + String("/") + String(rowID));
//通知数据库的变化
context->getContentResolver()->notifyChange(uri, NULL);
} else {
GLOGD("couldn't insert into btopp database");
}
return ret;
}
监听数据库变化的:
mObserver = new BluetoothShareContentObserver();
getContentResolver().registerContentObserver(BluetoothShare.CONTENT_URI, true, mObserver);
注:将文件加入数据库后,在BluetoothOppService的内部类BluetoothShareContentObserver会收到数据改变的事件,调用onChange()-----updateFromProvider()---updatethread;
updatethread里调用insertShare,这函数里面用到BluetoothOppTransfer,然后启动了BluetoothOppTransfer(mTransfer.start();)。
void BluetoothOppService::BluetoothShareContentObserver::onChange(bool selfChange) {
GLOGENTRY();
sp<BluetoothOppService> mspbtoppser = mBtOppService.promote();
GLOGD("BluetoothOppService:: ContentObserver received notification");
mspbtoppser->updateFromProvider();
}
void BluetoothOppService::updateFromProvider() {
GLOGENTRY();
GLOGI("updateFromProvider");
RecursiveMutex::Autolock _l(mBluetoothOppServiceMutex);
mPendingUpdate = true;
if (mUpdateThread == NULL) {
GLOGD("BluetoothOppService:: UpdateThread count %d", getStrongCount());
mUpdateThread = new UpdateThread(this);
GLOGD("BluetoothOppService:: UpdateThread count %d", getStrongCount());
mUpdateThread->run("Bluetooth Share Service");
}
}
void BluetoothOppService::insertShare(const sp<Cursor>& cursor, int32_t arrayPos) {
GLOGENTRY();
GLOGI("insertShare");
sp<BluetoothOppShareInfo> info = new BluetoothOppShareInfo(
cursor->getInt(cursor->getColumnIndexOrThrow(BluetoothShare::_ID)),
cursor->getString(cursor->getColumnIndexOrThrow(BluetoothShare::URI())),
cursor->getString(cursor->getColumnIndexOrThrow(BluetoothShare::FILENAME_HINT())),
cursor->getString(cursor->getColumnIndexOrThrow(BluetoothShare::_DATA())),
cursor->getString(cursor->getColumnIndexOrThrow(BluetoothShare::MIMETYPE())),
cursor->getInt(cursor->getColumnIndexOrThrow(BluetoothShare::DIRECTION())),
cursor->getString(cursor->getColumnIndexOrThrow(BluetoothShare::DESTINATION())),
cursor->getInt(cursor->getColumnIndexOrThrow(BluetoothShare::VISIBILITY())),
cursor->getInt(cursor->getColumnIndexOrThrow(BluetoothShare::USER_CONFIRMATION())),
cursor->getInt(cursor->getColumnIndexOrThrow(BluetoothShare::STATUS())),
cursor->getInt(cursor->getColumnIndexOrThrow(BluetoothShare::TOTAL_BYTES())),
cursor->getInt(cursor->getColumnIndexOrThrow(BluetoothShare::CURRENT_BYTES())),
cursor->getInt(cursor->getColumnIndexOrThrow(BluetoothShare::TIMESTAMP())),
cursor->getInt(cursor->getColumnIndexOrThrow(Constants::MEDIA_SCANNED())) != Constants::MEDIA_SCANNED_NOT_SCANNED);
GLOGI("Service adding new entry");
GLOGV("ID : %d", info->mId);
// Log.v(TAG, "URI : " + ((info.mUri != null) ? "yes" : "no"));
GLOGV("URI : %s", SP_STRING_STR(info->mUri));
GLOGI("HINT : %s", SP_STRING_STR(info->mHint));
GLOGI("FILENAME: %s", SP_STRING_STR(info->mFilename));
GLOGV("MIMETYPE: %s", SP_STRING_STR(info->mMimetype));
GLOGV("DIRECTION: %d", info->mDirection);
GLOGV("DESTINAT: %s", SP_STRING_STR(info->mDestination));
GLOGV("VISIBILI: %d", info->mVisibility);
GLOGI("CONFIRM : %d", info->mConfirm);
GLOGI("STATUS : %d", info->mStatus);
GLOGV("TOTAL : %d", info->mTotalBytes);
GLOGV("CURRENT : %d", info->mCurrentBytes);
GLOGV("TIMESTAMP : %lld", info->mTimestamp);
GLOGV("SCANNED : %d", info->mMediaScanned);
mShares->add(arrayPos, info);
/* Mark the info as failed if it's in invalid status */
if (info->isObsolete()) {
Constants::updateShareStatus(this, info->mId, BluetoothShare::STATUS_UNKNOWN_ERROR);
GLOGD("BluetoothOppService:: Constants::updateShareStatus count %d", getStrongCount());
}
/*
* Add info into a batch. The logic is
* 1) Only add valid and readyToStart info
* 2) If there is no batch, create a batch and insert this transfer into batch,
* then run the batch
* 3) If there is existing batch and timestamp match, insert transfer into batch
* 4) If there is existing batch and timestamp does not match, create a new batch and
* put in queue
*/
if (info->isReadyToStart()) {
if (info->mDirection == BluetoothShare::DIRECTION_OUTBOUND) {
/* check if the file exists */
sp<InputStream> i;
#if 0
try {
i = getContentResolver()->openInputStream(Uri::parse(info->mUri));
} catch(FileNotFoundException e) {
Log.e(TAG, "Can't open file for OUTBOUND info " + info.mId);
Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_BAD_REQUEST);
return;
} catch(SecurityException e) {
Log.e(TAG, "Exception:" + e.toString() + " for OUTBOUND info " + info.mId);
Constants.updateShareStatus(this, info.mId, BluetoothShare.STATUS_BAD_REQUEST);
return;
}
#endif // mark
// TODO TODO TODO
// check due to different translation
i = getContentResolver()->openInputStream(Uri::parse(info->mUri));
if (i == NULL) {
LOGE("Can't open file for OUTBOUND info %d", info->mId);
Constants::updateShareStatus(this, info->mId, BluetoothShare::STATUS_BAD_REQUEST);
GLOGD("BluetoothOppService:: Constants::updateShareStatus count %d", getStrongCount());
return;
}
// try {
i->close();
// } catch(IOException ex) {
// LOGE("IO error when close file for OUTBOUND info %d", info->mId);
// return;
// }
}
if (mBatchs->size() == 0) {
sp<BluetoothOppBatch> newBatch = new BluetoothOppBatch(this, info);
newBatch->mId = mBatchId;
mBatchId++;
mBatchs->add(newBatch);
if (info->mDirection == BluetoothShare::DIRECTION_OUTBOUND) {
GLOGI("Service create new Batch %d for OUTBOUND info %d", newBatch->mId, info->mId);
mTransfer = new BluetoothOppTransfer(this, mPowerManager, newBatch);
GLOGD("BluetoothOppService:: BluetoothOppTransfer count %d", getStrongCount());
} else if (info->mDirection == BluetoothShare::DIRECTION_INBOUND) {
GLOGI("Service create new Batch %d for INBOUND info %d", newBatch->mId, info->mId);
mServerTransfer = new BluetoothOppTransfer(this, mPowerManager, newBatch, mServerSession);
GLOGD("BluetoothOppService:: BluetoothOppTransfer count %d", getStrongCount());
}
if (info->mDirection == BluetoothShare::DIRECTION_OUTBOUND && mTransfer != NULL) {
GLOGI("Service start transfer new Batch %d for info %d", newBatch->mId, info->mId);
mTransfer->start();
} else if (info->mDirection == BluetoothShare::DIRECTION_INBOUND && mServerTransfer != NULL) {
GLOGI("Service start server transfer new Batch %d for info %d", newBatch->mId, info->mId);
mServerTransfer->start();
}
} else {
int32_t i = findBatchWithTimeStamp(info->mTimestamp);
if (i != -1) {
GLOGI("Service add info %d to existing batch %d", info->mId, mBatchs->get(i)->mId);
mBatchs->get(i)->addShare(info);
} else {
// There is ongoing batch
sp<BluetoothOppBatch> newBatch = new BluetoothOppBatch(this, info);
GLOGD("BluetoothOppService:: BluetoothOppBatch count %d", getStrongCount());
newBatch->mId = mBatchId;
mBatchId++;
mBatchs->add(newBatch);
GLOGI("Service add new Batch %d for info %d", newBatch->mId, info->mId);
if (Constants::USE_TCP_DEBUG && !Constants::USE_TCP_SIMPLE_SERVER) {
// only allow concurrent serverTransfer in debug mode
if (info->mDirection == BluetoothShare::DIRECTION_INBOUND) {
GLOGV("TCP_DEBUG start server transfer new Batch %d for info %d", newBatch->mId, info->mId);
mServerTransfer = new BluetoothOppTransfer(this, mPowerManager, newBatch, mServerSession);
GLOGD("BluetoothOppService:: BluetoothOppTransfer count %d", getStrongCount());
mServerTransfer->start();
}
}
}
}
}
}
void BluetoothOppTransfer::start() {
GLOGENTRY();
/* check Bluetooth enable status */
/*
* normally it's impossible to reach here if BT is disabled. Just check
* for safety
*/
if (!mAdapter->isEnabled()) {
LOGE("Can't start transfer when Bluetooth is disabled for %d", mBatch->mId);
markBatchFailed();
mBatch->mStatus = Constants::BATCH_STATUS_FAILED;
return;
}
if (mHandlerThread == NULL) {
GLOGI("Create handler thread for batch %d", mBatch->mId);
mHandlerThread = new HandlerThread(new String("BtOpp Transfer Handler"), Process::THREAD_PRIORITY_BACKGROUND);
mHandlerThread->run();
mSessionHandler = new EventHandler(mHandlerThread->getLooper(), this);
GLOGI("mBatch->mDirection = %lld", mBatch->mDirection);
if (mBatch->mDirection == BluetoothShare::DIRECTION_OUTBOUND) {
/* for outbound transfer, we do connect first */
startConnectSession();
} else if (mBatch->mDirection == BluetoothShare::DIRECTION_INBOUND) {
/*
* for inbound transfer, it's already connected, so we start
* OBEX session directly
*/
startObexSession();
}
}
}
void BluetoothOppTransfer::startConnectSession() {
GLOGENTRY();
sp<Context> mspContext = mContext.promote();
CHECK_NULL_POINTER_RETURN(mspContext);
if (Constants::USE_TCP_DEBUG) {
mConnectThread = new SocketConnectThread(new String("localhost"), Constants::TCP_DEBUG_PORT, 0, this);
mConnectThread->run();
} else {
int32_t channel = BluetoothOppPreference::getInstance(mspContext)->getChannel(mBatch->mDestination, OPUSH_UUID16);
if (channel != -1) {
GLOGI("Get OPUSH channel %d from cache for %s", channel, SP_TOSTRING_STR(mBatch->mDestination));
mTimestamp = System::currentTimeMillis();
mSessionHandler->obtainMessage(SDP_RESULT, channel, -1, mBatch->mDestination)->sendToTarget();
} else {
doOpushSdp();
}
}
}
void BluetoothOppTransfer::doOpushSdp() {
GLOGENTRY();
GLOGI("Do Opush SDP request for address %s", SP_TOSTRING_STR(mBatch->mDestination));
sp<Context> mspContext = mContext.promote();
CHECK_NULL_POINTER_RETURN(mspContext);
mTimestamp = System::currentTimeMillis();
int32_t channel;
channel = mBatch->mDestination->getServiceChannel(BluetoothUuid::ObexObjectPush());
if (channel != -1) {
GLOGD("Get OPUSH channel %d from SDP for %s", channel, SP_TOSTRING_STR(mBatch->mDestination));
mSessionHandler->obtainMessage(SDP_RESULT, channel, -1, mBatch->mDestination)->sendToTarget();
return;
} else {
GLOGI("Remote Service channel not in cache");
if (!mBatch->mDestination->fetchUuidsWithSdp()) {
LOGE("Start SDP query failed");
} else {
// we expect framework send us Intent ACTION_UUID. otherwise we will fail
GLOGV("Start new SDP, wait for result");
sp<IntentFilter> intentFilter = new IntentFilter(BluetoothDevice::ACTION_UUID());
mspContext->registerReceiver(mReceiver, intentFilter);
return;
}
}
sp<Message> msg = mSessionHandler->obtainMessage(SDP_RESULT, channel, -1, mBatch->mDestination);
mSessionHandler->sendMessageDelayed(msg, 2000);
}