2016-04-04 1 views
0

私は、BluetoothのArduinoデバイスに自動的に接続し、アプリと通信するAndroidアプリで主なアクティビティを持っています。私は、アプリケーションがBluetooth接続を失ったときにそれを検出し、ユーザに警告することができるようにしたい。これは、完全にフォアグラウンドスレッドで実行されているが、完全に正常に動作しますが、私は、アプリケーションを終了し、接続が失われた場合でもユーザーに通知することができるようにしたい。しかし、私はこれを達成するための最良の方法が不明です。バックグラウンドでBluetoothアクティビティを続行するにはどうすればよいですか?

// Main BTLE device callback where much of the logic occurs. 
public BluetoothGattCallback callback = new BluetoothGattCallback() { 
    // Called whenever the device connection state changes, i.e. from disconnected to connected. 
    @Override 
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
     super.onConnectionStateChange(gatt, status, newState); 
     if (newState == BluetoothGatt.STATE_CONNECTED) { 
      writeLine("Connected!"); 
      // Discover services. 
      if (!gatt.discoverServices()) { 
       writeLine("Failed to start discovering services!"); 
      } 
     } else if (newState == BluetoothGatt.STATE_DISCONNECTED) { 
      writeLine("Disconnected!"); 
      // This is where the user is notified! 
      pushNotification(); 

     } else { 
      writeLine("Connection state changed. New state: " + newState); 
     } 
    } 

    // Called when services have been discovered on the remote device. 
    // It seems to be necessary to wait for this discovery to occur before 
    // manipulating any services or characteristics. 
    @Override 
    public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
     super.onServicesDiscovered(gatt, status); 
     if (status == BluetoothGatt.GATT_SUCCESS) { 
      writeLine("Service discovery completed!"); 
     } else { 
      writeLine("Service discovery failed with status: " + status); 
     } 
     // Save reference to each characteristic. 
     tx = gatt.getService(UART_UUID).getCharacteristic(TX_UUID); 
     rx = gatt.getService(UART_UUID).getCharacteristic(RX_UUID); 
     // Setup notifications on RX characteristic changes (i.e. data received). 
     // First call setCharacteristicNotification to enable notification. 
     if (!gatt.setCharacteristicNotification(rx, true)) { 
      writeLine("Couldn't set notifications for RX characteristic!"); 
     } 
     // Next update the RX characteristic's client descriptor to enable notifications. 
     if (rx.getDescriptor(CLIENT_UUID) != null) { 
      BluetoothGattDescriptor desc = rx.getDescriptor(CLIENT_UUID); 
      desc.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 
      if (!gatt.writeDescriptor(desc)) { 
       writeLine("Couldn't write RX client descriptor value!"); 
      } 
     } else { 
      writeLine("Couldn't get RX client descriptor!"); 
     } 
    } 

    // Called when a remote characteristic changes (like the RX characteristic). 
    @Override 
    public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { 
     super.onCharacteristicChanged(gatt, characteristic); 
     // THIS LINE WRITES TO THE UI FROM THE ARDUINO 
     writeLine(characteristic.getStringValue(0)); 
    } 
}; 

// BTLE device scanning callback. 
private LeScanCallback scanCallback = new LeScanCallback() { 
    // Called when a device is found. 
    @Override 
    public void onLeScan(BluetoothDevice bluetoothDevice, int i, byte[] bytes) { 
     writeLine("Found device: " + bluetoothDevice.getAddress()); 
     // Check if the device has the UART service. 
     if (parseUUIDs(bytes).contains(UART_UUID)) { 
      // Found a device, stop the scan. 
      adapter.stopLeScan(scanCallback); 
      writeLine("Found UART service!"); 
      // Connect to the device. 
      // Control flow will now go to the callback functions when BTLE events occur. 
      gatt = bluetoothDevice.connectGatt(getApplicationContext(), false, callback); 
     } 
    } 
}; 

// OnCreate, called once to initialize the activity. 
@Override 
protected void onCreate(Bundle savedInstanceState) { 

    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 

    // Checks if Bluetooth is enabled 
    BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 
    if (mBluetoothAdapter == null) { 
     bluetoothPopup("Your device does not support Bluetooth!"); 
    } else { 
     if (!mBluetoothAdapter.isEnabled()) { 
      Intent turnOn = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
      startActivityForResult(turnOn, 0);; 
     } 
    } 

    // Grab references to UI elements. 
    messages = (TextView) findViewById(R.id.messages); 

    //adapter = BluetoothAdapter.getDefaultAdapter(); 
    adapter = mBluetoothAdapter; 
} 

// OnResume, called right before UI is displayed. Start the BTLE connection. 
@Override 
protected void onResume() { 
    super.onResume(); 
    // Scan for all BTLE devices. 
    // The first one with the UART service will be chosen--see the code in the scanCallback. 
    writeLine("Scanning for devices..."); 
    adapter.startLeScan(scanCallback); 
} 

// OnStop, called right before the activity loses foreground focus. Close the BTLE connection. 
@Override 
protected void onStop() { 
    super.onStop(); 
    if (gatt != null) { 
     // For better reliability be careful to disconnect and close the connection. 
     gatt.disconnect(); 
     gatt.close(); 
     gatt = null; 
     tx = null; 
     rx = null; 
    } 
} 

// Write some text to the messages text view. 
// Care is taken to do this on the main UI thread so writeLine can be called 
// from any thread (like the BTLE callback). 
private void writeLine(final CharSequence text) { 
    runOnUiThread(new Runnable() { 
     @Override 
     public void run() { 
      messages.append(text); 
      messages.append("\n"); 
     } 
    }); 
} 

// This is a workaround function from the SO thread to manually parse advertisement data. 
private List<UUID> parseUUIDs(final byte[] advertisedData) { 
    List<UUID> uuids = new ArrayList<UUID>(); 

    int offset = 0; 
    while (offset < (advertisedData.length - 2)) { 
     int len = advertisedData[offset++]; 
     if (len == 0) 
      break; 

     int type = advertisedData[offset++]; 
     switch (type) { 
      case 0x02: // Partial list of 16-bit UUIDs 
      case 0x03: // Complete list of 16-bit UUIDs 
       while (len > 1) { 
        int uuid16 = advertisedData[offset++]; 
        uuid16 += (advertisedData[offset++] << 8); 
        len -= 2; 
        uuids.add(UUID.fromString(String.format("%08x-0000-1000-8000-00805f9b34fb", uuid16))); 
       } 
       break; 
      case 0x06:// Partial list of 128-bit UUIDs 
      case 0x07:// Complete list of 128-bit UUIDs 
       // Loop through the advertised 128-bit UUID's. 
       while (len >= 16) { 
        try { 
         // Wrap the advertised bits and order them. 
         ByteBuffer buffer = ByteBuffer.wrap(advertisedData, offset++, 16).order(ByteOrder.LITTLE_ENDIAN); 
         long mostSignificantBit = buffer.getLong(); 
         long leastSignificantBit = buffer.getLong(); 
         uuids.add(new UUID(leastSignificantBit, 
           mostSignificantBit)); 
        } catch (IndexOutOfBoundsException e) { 
         // Defensive programming. 
         //Log.e(LOG_TAG, e.toString()); 
         continue; 
        } finally { 
         // Move the offset to read the next uuid. 
         offset += 15; 
         len -= 16; 
        } 
       } 
       break; 
      default: 
       offset += (len - 1); 
       break; 
     } 
    } 
    return uuids; 
} 

// Method called to start the service 
public void startService(View view) { 
    startService(new Intent(getBaseContext(), AppService.class)); 
} 

// Method called to stop the service 
public void stopService(View view) { 
    stopService(new Intent(getBaseContext(), AppService.class));} 

サービス開始前に既に接続が確立されていますが、サービスの開始時に接続が維持されるようにするにはどうすればよいですか? BluetoothGattCallbackコールバックオブジェクトをサービスに渡すだけでよいのですか?これを実行する最も良い方法は何ですか?

--UPDATE- 私はこれを行う最良の方法はサービスを介していると考えましたが、どのように "コールバック"オブジェクトのような複雑なパラメータを渡すのでしょうか? Parcelableインターフェイスを使用してこれをどうすればできますか?

+1

サービスを使用して、それに活動をバインド –

答えて

0

Serviceを作成する必要があります。
あなたのアプリが通知として実行中であることを示すために、必要に応じて、良いアイデアかもしれません。この方法では、自動的に殺されることはありませんが、あなたは常にそれが動作していることを認識しています。それがあなたが望むものならば、ForegroundServiceがほしいと思う。

ここに完全チュートリアル: http://www.vogella.com/tutorials/AndroidServices/article.html

0

Activitiesは、可視部分に結合している。彼らが目に見えない場合、彼らは破壊される可能性があります。バックグラウンドタスクの場合、ヘッドレスコンポーネントが必要です。通常、Serviceをそのまま使用します。

関連する問題