首先,android原生的藍(lán)牙接收流程是,在有文件從其他設(shè)備傳過來時(shí),會彈出藍(lán)牙文件接收的缺人框且默認(rèn)是以notification的形式顯示在狀態(tài)欄,當(dāng)用戶點(diǎn)擊之后才會彈出一個dialog。那么當(dāng)狀態(tài)欄被禁用時(shí),如何實(shí)現(xiàn)文件接受全程不需用戶點(diǎn)擊而自動接收呢?
第一個問題:
如何不讓用戶點(diǎn)擊狀態(tài)欄直接彈確認(rèn)的dialog。
在BluetoothOppNotification.java的updateIncomingFileConfirmNotification()方法中會對接受到來的文件進(jìn)行一定的處理同時(shí)會構(gòu)造一個Notification,來顯示接受和拒絕的信息,那么解決的思路就在這里。
private void updateIncomingFileConfirmNotification() {
//省略若干…
Intent intent = new Intent(Constants.ACTION_INCOMING_FILE_CONFIRM);//這句比較關(guān)鍵,傳遞一個action到BluetoothOppReceiver
intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
intent.setDataAndNormalize(contentUri);
intent構(gòu)造了之后在這里并沒有發(fā)送廣播出去,而是在下面構(gòu)造notification之后,點(diǎn)擊時(shí)才將廣播發(fā)送出去,所以問題的解決點(diǎn)就在這里。如果不需要用戶點(diǎn)擊狀態(tài)欄直接顯示文件接收和拒絕的確認(rèn)界面可以直接在這里mContext.sendBroadcast(intent);將廣播發(fā)送出去
//省略若干…
{
//構(gòu)造notification
Notification n = new Notification();
n.icon = R.drawable.bt_incomming_file_notification;
n.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
n.flags |= Notification.FLAG_ONGOING_EVENT;
n.defaults = Notification.DEFAULT_SOUND;
n.tickerText = title;
n.when = timeStamp;
n.color = mContext.getResources().getColor(
com.android.internal.R.color.system_notification_accent_color);
n.setLatestEventInfo(mContext, title, caption, PendingIntent.getBroadcast(mContext, 0,
intent, 0));
intent = new Intent(Constants.ACTION_HIDE);
intent.setClassName(Constants.THIS_PACKAGE_NAME, BluetoothOppReceiver.class.getName());
intent.setDataAndNormalize(contentUri);
n.deleteIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);//用戶點(diǎn)擊之后將廣播發(fā)送出去
mNotificationMgr.notify(id, n);
}
}
}
第二個問題
用戶不點(diǎn)擊確認(rèn)文件接收的按鈕直接進(jìn)行文件接收。這個相對來說比較簡單
繼續(xù)上面說的,當(dāng)廣播發(fā)送之后在BluetoothOppReceiver.java直接啟動BluetoothOppIncomingFileConfirmActivity。在這個activity中作進(jìn)一步的處理。
可以看到的是在這個activity中主要是構(gòu)造上面所說的接收文件確認(rèn)和拒絕的dialog。
要想達(dá)到需要的效果,只需要將確認(rèn)接收按鈕事件的代碼外移即可??梢灾苯右苿拥膐ncreate中執(zhí)行,完了之后將dialog dismiss掉。主要就是如下幾句代碼
if (!mTimeout) {
// Update database
mUpdateValues = new ContentValues();
mUpdateValues.put(BluetoothShare.USER_CONFIRMATION,
BluetoothShare.USER_CONFIRMATION_CONFIRMED);
this.getContentResolver().update(mUri, mUpdateValues, null, null);
Toast.makeText(this, getString(R.string.bt_toast_1), Toast.LENGTH_SHORT).show();
}
第三個問題
如何顯示進(jìn)度條。
當(dāng)上面的文件開始接受之時(shí)就需要彈出進(jìn)度條進(jìn)行顯示進(jìn)度。所以在上面的代碼中還需要加入啟動進(jìn)度條界面的代碼。具體是
Intent in = new Intent(this, BluetoothOppTransferActivity.class);
in.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
in.setDataAndNormalize(mUri);
this.startActivity(in);
至此,單文件就開始傳輸并且已經(jīng)顯示進(jìn)度條。
第四個問題
文件傳輸完場之后,進(jìn)度條界面如何三秒之后自動消失。
進(jìn)入BluetoothOppTransferActivity這個activity,首先先定義一個消失的方法。如下
private void dismissNowDialog(){
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
dismiss();
}
}, 2000);
}
之后再setUpDialog()中mWhichDialog == DIALOG_RECEIVE_COMPLETE_SUCCESS和mWhichDialog == DIALOG_RECEIVE_COMPLETE_FAIL時(shí)調(diào)用這個方法即可。
寫到這里,單文件文件傳輸全程不需要用戶進(jìn)行任何點(diǎn)擊就可以自動接收完成。
但是不知道您有沒有想過一個問題,在接受完之后dismiss掉了界面,那么在多文件傳輸時(shí)后面的那些文件進(jìn)度條是否還會顯示呢?答案是不會的。
第五個問題
多文件時(shí)如何顯示所有文件傳輸?shù)倪M(jìn)度條。
思路就是,再多文件傳輸時(shí),單個文件傳輸完,狀態(tài)欄會進(jìn)行更新顯示其他文件的進(jìn)度信息,考慮到這里,繼續(xù)進(jìn)入BluetoothOppNotification.java這個類,在updateActiveNotification()方法中可以看到多文件在傳輸時(shí),它是通過Notification.Builder來進(jìn)行刷新顯示的,我們的需求并不是這樣,所以這些并不可取。繼續(xù)往下看可以看到重點(diǎn)是Intent intent = new Intent(Constants.ACTION_LIST);這個可以理解為處理多文件的。原生的代碼并沒有很好地辦法來區(qū)分多文件還是單文件,所以需要在這里想辦法進(jìn)行處理。筆者在做的時(shí)候看到這個很是興奮,一想這不很簡單嗎,和單文件傳輸如出一轍我只需要將廣播手動發(fā)送一遍即可。結(jié)果會讓你崩潰的,這里簡單說下,假如十個文件在傳輸時(shí)那么這個廣播他會發(fā)幾遍呢?最終的結(jié)果就是后面的界面不停的閃爍加重疊。所以這里要做的就是在文件傳輸時(shí)只將這個廣播發(fā)送一次,但是并沒有現(xiàn)成的方法或變量來標(biāo)示是否多文件傳輸。
第六個問題
如何在一個循環(huán)中只根據(jù)自己的需求將廣播發(fā)送一次出去呢?
筆者這里采用的思路是定義一個任意類型的變量,給定一個初始值,找一個在文件接收時(shí)肯定會調(diào)用的一個方法,在這個方法中改變變臉的值,完了之后在發(fā)送廣播時(shí)加上對這個變量的判斷,完了之后將變量的值回復(fù)默認(rèn)值。下次的話,他肯定就不會再發(fā)廣播出去,保證廣播只發(fā)送了一次,即可達(dá)到需求。
Private Int temp =0;
private void updateActiveNotification() {
……
if(temp==1){//通過這個判斷保證廣播只會發(fā)送一次
mContext.sendBroadcast(intent);
temp=temp+1;
}
……
}
rivate void updateIncomingFileConfirmNotification() {
//這個方法中加入如下代碼
if(temp==1){
temp=temp+1;
return;
}
……
temp=1;
}
至此,整個需求處理完畢。當(dāng)讓如果在接受完畢之后還想顯示多少文件傳輸完成,多少文件傳輸失敗的話可以通過在代碼中BluetoothOppTransferActivity.java中動態(tài)的改變dialog的顯示信息來進(jìn)行處理,需要注意的是在這個類里面是不知道有多少文件傳輸完成和失敗的,需要從BluetoothOppNotification.java 的updateCompletedNotification()方法中,將
int outboundSuccNumber = 0;
int outboundFailNumber = 0;
int outboundNum;
int inboundNum;
int inboundSuccNumber = 0;
int inboundFailNumber = 0;
參數(shù)選擇性的進(jìn)行傳輸或者保存,從而在上面說的界面顯示出來。
最后再來一個小知識點(diǎn)結(jié)束。不知有沒有想過,藍(lán)牙文件在傳輸時(shí)如何判斷文件是正在傳輸還是已經(jīng)傳輸完畢呢?原生的藍(lán)牙代碼之后提供藍(lán)牙的配對,連接等狀態(tài),并不會提供文件傳輸?shù)臓顟B(tài),那么就需要自己來實(shí)現(xiàn)。思路就是藍(lán)牙文件的傳輸是通過流來進(jìn)行的,那么我只需要知道它所對應(yīng)的劉是否關(guān)閉即可知道文件是否傳輸完成。
在framework\base\obex\javax\obex下面有個ServerSession類,在這個里面會通過判斷ObexTransport; InputStream OutputStream來判斷是否關(guān)閉,可以自己在這里加接口提供給外部,用來判斷藍(lán)牙文件是否傳輸完成,比較簡單。