2016-07-01 157 views
4

AndroidのBluetoothデバイスに接続しようとしています。私はonClientConnectionStateハンドラにステータス133を受け取りました。私はいつもこのエラーが出るとは限りません。私は問題を引き起こすものに指を置くことができませんでした。私はデバイスと私のreproアプリケーションを再起動した直後にもそれを持っていた。Android Bluetoothエラー133

、私はいくつかの質問を認識だと(herehere、およびhereから)を含め、この問題に対する解決策を提案した:

  • すべてのBTのAPI
  • ためのUIスレッドが閉じるようにしてください使用GATTが完了したら

しかし、私はそれをすべてやっています。さらに、私のデバイスはNexus 5(Lollipopを走らせている)であり、UIスレッド上にBTのやり取りをする必要がないものもあります。

私は可能な限り簡単なレプロをまとめました。これは、C#でのですが、Javaと同等のは明白でなければなりません:

[Activity(Label = "BluetoothGatt133ErrorRepro", MainLauncher = true, Icon = "@drawable/icon")] 
public class MainActivity : Activity 
{ 
    protected override void OnCreate(Android.OS.Bundle bundle) 
    { 
     base.OnCreate(bundle); 

     SetContentView(Resource.Layout.Main); 
     var button = FindViewById<Button>(Resource.Id.button); 
     button.Click += this.OnClick; 
    } 

    private async void OnClick(object sender, EventArgs e) 
    { 
     Action<string> log = message => Console.WriteLine($"***** #{Environment.CurrentManagedThreadId} {message}"); 

     log("Beginning"); 

     var bluetoothManager = (BluetoothManager)Application.Context.GetSystemService(Context.BluetoothService); 
     var adapter = bluetoothManager.Adapter; 
     var scanner = adapter.BluetoothLeScanner; 
     var callback = new Callback(); 
     var filters = new List<ScanFilter>(); 
     var settings = new ScanSettings.Builder() 
      .SetScanMode(global::Android.Bluetooth.LE.ScanMode.LowLatency) 
      .Build(); 

     log("Starting scan"); 
     scanner.StartScan(filters, settings, callback); 

     var result = await callback.Result; 
     log($"Got device: {result.Device.Name}"); 

     var remoteDevice = adapter.GetRemoteDevice(result.Device.Address); 
     var gattCallback = new GattCallback(log); 

     log("Connecting GATT"); 

     var gatt = remoteDevice.ConnectGatt(Application.Context, true, gattCallback); 
     gatt.Connect(); 

     await gattCallback.Result; 

     log("Disconnecting GATT"); 

     gatt.Close(); 
     gatt.Dispose(); 
    } 

    private sealed class Callback : ScanCallback 
    { 
     private readonly TaskCompletionSource<ScanResult> result; 

     public Callback() 
     { 
      this.result = new TaskCompletionSource<ScanResult>(); 
     } 

     public Task<ScanResult> Result => this.result.Task; 

     public override void OnBatchScanResults(IList<ScanResult> results) 
     { 
      foreach (var result in results) 
      { 
       this.HandleResult(result); 
      } 
     } 

     public override void OnScanResult(ScanCallbackType callbackType, ScanResult result) 
     { 
      this.HandleResult(result); 
     } 

     public override void OnScanFailed(ScanFailure errorCode) 
     { 
      this.result.TrySetException(new InvalidOperationException($"Failed with error code {errorCode}.")); 
     } 

     private void HandleResult(ScanResult result) 
     { 
      if (result.Device.Name.Contains("elided")) 
      { 
       this.result.TrySetResult(result); 
      } 
     } 
    } 

    private sealed class GattCallback : BluetoothGattCallback 
    { 
     private readonly Action<string> log; 
     private readonly TaskCompletionSource<bool> result; 

     public GattCallback(Action<string> log) 
     { 
      this.log = log; 
      this.result = new TaskCompletionSource<bool>(); 
     } 

     public Task<bool> Result => this.result.Task; 

     public override void OnConnectionStateChange(BluetoothGatt gatt, GattStatus status, ProfileState newState) 
     { 
      this.log($"Connection state changed to {newState} with status {status}."); 

      this.result.TrySetResult(true); 
     } 
    } 
} 

そして、ここで(私もAndroidのBluetoothGattソースからの出力に残してきた)、これを実行しているからの出力です:あなたができるよう

***** #1 Beginning 
***** #1 Starting scan 
07-01 11:53:21.458 D/BluetoothLeScanner(10377): onClientRegistered() - status=0 clientIf=5 
***** #1 Got device: elided 
***** #1 Connecting GATT 
07-01 11:53:22.833 D/BluetoothGatt(10377): connect() - device: 00:00:DE:AD:BE:EF, auto: true 
07-01 11:53:22.833 D/BluetoothGatt(10377): registerApp() 
07-01 11:53:22.833 D/BluetoothGatt(10377): registerApp() - UUID=fa5bce8a-416d-47fe-9a8a-e44156f7e865 
07-01 11:53:22.834 D/BluetoothGatt(10377): onClientRegistered() - status=0 clientIf=6 
07-01 11:53:24.622 D/BluetoothGatt(10377): onClientConnectionState() - status=133 clientIf=6 device=00:00:DE:AD:BE:EF 
***** #4 Connection state changed to Disconnected with status 133. 
***** #1 Disconnecting GATT 
07-01 11:53:24.707 D/BluetoothGatt(10377): close() 
07-01 11:53:24.707 D/BluetoothGatt(10377): unregisterApp() - mClientIf=6 

Bluetoothスタックとの私のすべてのやりとりは、メインスレッド(#1)で発生しています。しかしそれにもかかわらず、onClientConnectionStateハンドラにステータス133が届いています。

私のマニフェストには、これらの権限を持っている:

<uses-permission android:name="android.permission.BLUETOOTH" /> 
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> 
    <uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED" /> 
    <uses-permission android:name="android.permission.INTERNET" /> 
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 

私は、最新のマシュマロツールでコンパイルしていて、4.0.3(APIレベル15)の最小目標とマシュマロをターゲットにしています。

これは何が原因でしょうか?

+1

マニフェストファイルにどのような権限があるか教えてください。また、接続を試みる前にスキャンを停止することもできますか? – Zomb

+0

^^ upvotedスキャンの提案を停止するために、そのことに気付かなかった – Submersed

+0

@ Zomb私の質問に詳細を追加しました。それは明らかに今朝私のためにうまくいきますが、次回このポップアップでスキャントリックを止めてみる必要があります。 –

答えて

2

(注:あなたはすでにこれをやっているかもしれないが、私はよくC#で精通していないよ)

私の経験で

、それは本当にあなただけのメインスレッド上BLEデバイスと対話することをされていません一度に多くのリクエストをデバイスにあふれさせないだけです。

AndroidでBLEを使用しているときにこの問題が発生していました(メインスレッドの使用に関する同様のコメントを読んでいます)、それはあまりにも多くのリクエスト(読み取り/書き込み、通知/表示登録など) Bluetooth GattCallbackオブジェクトの以前の操作のコールバックを受信する前に、リモートのGattデバイスに送信します。私は自分自身のマネージドgatt操作キュー(その操作のコールバックがGattCallbackで受信されるまでブロックするスレッド、または最初の読み取り/書き込み操作がfalseを返し、次にキューに入れられた操作を処理するか、バックオフ乗数で再試行する)私はこの問題にぶつからなかったからです。私が知ることから、Androidは "キューイング"操作をうまくやっていないので、 "isBusy"ブール値は知らないうちに噛み付いてしまいます(BlueoothGattCharacteristic writeメソッドを見てください)。また、コールバックオブジェクトで多くの作業を行うのではなく、別のスレッドにコールバックを委譲するか、結果をブロードキャストする(バインダースレッドをブロックしないようにする)ことに気付きました。通常は、バイトペイロードをコピーし、別のHandlerThreadに渡して解析します。

また、切断とクローズは確かに重要です。私は一般に、サービスのonDestroyが終了する前にBLEのやりとりを処理し、両方を呼び出すためにServiceを使用します。

+0

私は実際の実装で操作キューをすでに持っていますが、上記の私のテストアプリケーションで見ることができるように、私はそれほど遠慮していません。私は接続を確立する最初のハードルで失敗する(しばしば、しかし常にではない)。 –

+0

また、これは常にあなたが得た結果ですか、それともあなたは成功した接続を得ていますか? – Submersed

+0

申し訳ありませんが、私は秒を取った。面白い。どのようなファームウェアですか? – Submersed