2015-10-20 133 views
3

我想從GATT服務器讀取值並將其顯示在我的屏幕上。我已經通過各種教程,並試圖找到各種方法來解決這個問題,但我在某個地方磕磕絆絆!閱讀Android上的GATT屬性問題藍牙低功耗

一些幫助將不勝感激。

佈局XML:

<?xml version="1.0" encoding="utf-8"?> 

<TextView android:text="Key : " android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:id="@+id/textView2" /> 

<TextView 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:textAppearance="?android:attr/textAppearanceMedium" 
    android:text="Medium Text" 
    android:id="@+id/pubkey" 
    android:layout_alignTop="@+id/textView2" 
    android:layout_toEndOf="@+id/textView2" 
    android:layout_marginStart="30dp" /> 
</RelativeLayout> 

MainActivity.java

public class MainActivity extends Activity implements BluetoothAdapter.LeScanCallback { 
private static final String TAG = "BluetoothGattActivity"; 
private static final String DEVICE_NAME = "PUNE\u0005\u0012\b"; 

/* 
SECURITY SERVICE 
*/ 
private static final UUID SECURITY_SERVICE = UUID.fromString("3E099914-293F-11E4-93BD-AFD0FE6D1DFD"); 
private static final UUID SECURITY_PUBLICKEY = UUID.fromString("3E099915-293F-11E4-93BD-AFD0FE6D1DFD"); 


private BluetoothAdapter mBluetoothAdapter; 
private SparseArray<BluetoothDevice> mDevices; 

private BluetoothGatt mConnectedGatt; 

private TextView publicKEY; 

private ProgressDialog mProgress; 


@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 
    setContentView(R.layout.activity_main); 
    setProgressBarIndeterminate(true); 

    publicKEY = (TextView) findViewById(R.id.pubkey); 


    BluetoothManager manager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); 
    mBluetoothAdapter = manager.getAdapter(); 

    mDevices = new SparseArray<BluetoothDevice>(); 

    mProgress = new ProgressDialog(this); 
    mProgress.setIndeterminate(true); 
    mProgress.setCancelable(false); 

} 

@Override 
protected void onResume() { 
    super.onResume(); 
    /* 
    * We need to enforce that Bluetooth is first enabled, and take the 
    * user to settings to enable it if they have not done so. 
    */ 
    if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { 
     //Bluetooth is disabled 
     Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); 
     startActivity(enableBtIntent); 
     finish(); 
     return; 
    } 

    /* 
    * Check for Bluetooth LE Support. In production, our manifest entry will keep this 
    * from installing on these devices, but this will allow test devices or other 
    * sideloads to report whether or not the feature exists. 
    */ 
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { 
     Toast.makeText(this, "No LE Support.", Toast.LENGTH_SHORT).show(); 
     finish(); 
     return; 
    } 

    clearDisplayValues(); 
} 


@Override 
protected void onPause() { 
    super.onPause(); 
    //Make sure dialog is hidden 
    mProgress.dismiss(); 
    //Cancel any scans in progress 
    mHandler.removeCallbacks(mStopRunnable); 
    mHandler.removeCallbacks(mStartRunnable); 
    mBluetoothAdapter.stopLeScan(this); 
} 

@Override 
protected void onStop() { 
    super.onStop(); 
    //Disconnect from any active tag connection 
    if (mConnectedGatt != null) { 
     mConnectedGatt.disconnect(); 
     mConnectedGatt = null; 
    } 
} 


@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    // Add the "scan" option to the menu 
    getMenuInflater().inflate(R.menu.main, menu); 
    //Add any device elements we've discovered to the overflow menu 
    for (int i=0; i < mDevices.size(); i++) { 
     BluetoothDevice device = mDevices.valueAt(i); 
     menu.add(0, mDevices.keyAt(i), 0, device.getName()); 
    } 

    return true; 
} 

@Override 
public boolean onOptionsItemSelected(MenuItem item) { 
    switch (item.getItemId()) { 
     case R.id.action_scan: 
      mDevices.clear(); 
      startScan(); 
      return true; 
     default: 
      //Obtain the discovered device to connect with 
      BluetoothDevice device = mDevices.get(item.getItemId()); 
      Log.i(TAG, "Connecting to "+device.getName()); 
      /* 
      * Make a connection with the device using the special LE-specific 
      * connectGatt() method, passing in a callback for GATT events 
      */ 
      mConnectedGatt = device.connectGatt(this, false, mGattCallback); 
      //Display progress UI 
      mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Connecting to "+device.getName()+"...")); 
      return super.onOptionsItemSelected(item); 
    } 
} 

private void clearDisplayValues() { 
    publicKEY.setText("---"); 

} 

private Runnable mStopRunnable = new Runnable() { 
    @Override 
    public void run() { 
     stopScan(); 
    } 
}; 
private Runnable mStartRunnable = new Runnable() { 
    @Override 
    public void run() { 
     startScan(); 
    } 
}; 

private void startScan() { 
    mBluetoothAdapter.startLeScan(this); 
    setProgressBarIndeterminateVisibility(true); 

    mHandler.postDelayed(mStopRunnable, 2500); 
} 

private void stopScan() { 
    mBluetoothAdapter.stopLeScan(this); 
    setProgressBarIndeterminateVisibility(false); 
} 

,我所有的回調在這裏

/* BluetoothAdapter.LeScanCallback */ 


@Override 
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { 
    Log.i(TAG, "New LE Device: " + device.getName() + " @ " + rssi); 
    /* 
    * We are looking for SensorTag devices only, so validate the name 
    * that each device reports before adding it to our collection 
    */ 
    if (DEVICE_NAME.equals(device.getName())) { 
     mDevices.put(device.hashCode(), device); 
     //Update the overflow menu 
     invalidateOptionsMenu(); 
    } 

} 

private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { 


    private int mState = 0; 

    private void reset() 
    { 
    mState= 0; 
    } 

    private void advance() 
    { 
     mState++; 
    } 

    private void enabled(BluetoothGatt gatt) { 
     BluetoothGattCharacteristic characteristic; 

     switch(mState) { 
      case 0: 
       Log.d(TAG, "Enable Public Key"); 
       characteristic = gatt.getService(SECURITY_SERVICE).getCharacteristic(SECURITY_PUBLICKEY); 

       break; 

      default: 
       mHandler.sendEmptyMessage(MSG_DISMISS); 
       Log.i(TAG, "All Sensors Enabled"); 
       return; 
     } 


    } 

    private void readData(BluetoothGatt gatt) 
    { 

     BluetoothGattCharacteristic characteristic; 

     switch (mState) { 
      case 0: 
       Log.d(TAG, "Reading Public Key"); 
       characteristic = gatt.getService(SECURITY_SERVICE).getCharacteristic(SECURITY_PUBLICKEY); 
       break; 

      default: 
       mHandler.sendEmptyMessage(MSG_DISMISS); 
       Log.i(TAG, "All Sensors Enabled"); 
       return; 
     } 
     gatt.readCharacteristic(characteristic); 


    } 

    private void enableNotif(BluetoothGatt gatt) { 
     BluetoothGattCharacteristic characteristic; 
     switch (mState) { 
      case 0: 
       Log.d(TAG, "Setting Notification Public Key"); 
       characteristic = gatt.getService(SECURITY_SERVICE).getCharacteristic(SECURITY_PUBLICKEY); 
       break; 

      default: 
       mHandler.sendEmptyMessage(MSG_DISMISS); 
       Log.i(TAG, "All Sensors Enabled"); 
       return; 
     } 

     gatt.setCharacteristicNotification(characteristic, true); 

    } 

    @Override 
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
     Log.d(TAG, "Connection State Change: " + status + " -> " + connectionState(newState)); 
     if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) { 
      /* 
      * Once successfully connected, we must next discover all the services on the 
      * device before we can read and write their characteristics. 
      */ 
      gatt.discoverServices(); 
      mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Discovering Services...")); 
     } else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) { 
      /* 
      * If at any point we disconnect, send a message to clear the weather values 
      * out of the UI 
      */ 
      mHandler.sendEmptyMessage(MSG_CLEAR); 
     } else if (status != BluetoothGatt.GATT_SUCCESS) { 
      /* 
      * If there is a failure at any stage, simply disconnect 
      */ 
      gatt.disconnect(); 
     } 
    } 

    @Override 
    public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
     Log.d(TAG, "Services Discovered: " + status); 
     mHandler.sendMessage(Message.obtain(null, MSG_PROGRESS, "Enabling Public Key...")); 

     reset(); 
     enabled(gatt); 

    } 

    @Override 
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,int status) { 
     if(SECURITY_PUBLICKEY.equals(characteristic.getUuid())) { 
      mHandler.sendMessage(Message.obtain(null,MSG_PUBLICKEY,characteristic)); 
     } 
     enableNotif(gatt); 
     readData(gatt); 

    } 


    @Override 
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { 
     //After writing the enable flag, next we read the initial value 
     readData(gatt); 
    } 

    @Override 
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { 
     Log.d(TAG, "Remote RSSI: " + rssi); 
    } 

    private String connectionState(int status) { 
     switch (status) { 
      case BluetoothProfile.STATE_CONNECTED: 
       return "Connected"; 
      case BluetoothProfile.STATE_DISCONNECTED: 
       return "Disconnected"; 
      case BluetoothProfile.STATE_CONNECTING: 
       return "Connecting"; 
      case BluetoothProfile.STATE_DISCONNECTING: 
       return "Disconnecting"; 
      default: 
       return String.valueOf(status); 
     } 
    } 

}; 



private static final int MSG_PROGRESS = 201; 
private static final int MSG_DISMISS = 202; 
private static final int MSG_CLEAR = 301; 
private static final int MSG_PUBLICKEY = 101; 

private Handler mHandler = new Handler() { 
    @Override 
    public void handleMessage(Message msg) { 
     BluetoothGattCharacteristic characteristic; 
     switch (msg.what) { 
      case MSG_PUBLICKEY: 
       characteristic = (BluetoothGattCharacteristic) msg.obj; 
       if (characteristic.getValue() == null) { 
        Log.w(TAG, "Error obtaining humidity value"); 
        return; 
       } 
       updatePubKey(characteristic); 
       break; 

      case MSG_PROGRESS: 
       mProgress.setMessage((String) msg.obj); 
       if (!mProgress.isShowing()) { 
        mProgress.show(); 
       } 
       break; 
      case MSG_DISMISS: 
       mProgress.hide(); 
       break; 
      case MSG_CLEAR: 
       clearDisplayValues(); 
       break; 
     } 
    } 
}; 

private void updatePubKey(BluetoothGattCharacteristic characteristic) { 

    byte[] data = characteristic.getValue(); 
    final StringBuilder stringBuilder = new StringBuilder(data.length); 
    for(byte byteChar : data) 
     stringBuilder.append(String.format("%02X ", byteChar)); 
    publicKEY.setText(new String(data)+" "+stringBuilder.toString()); 

} 


} 

這裏的日誌

Timeline: Timeline: Activity_idle id: [email protected]   time:10882957 
BluetoothAdapter: startLeScan(): null 
BluetoothAdapter: onClientRegistered() - status=0 clientIf=5 
BluetoothGattActivity: New LE Device: null @ -83 
BluetoothAdapter: stopLeScan() 
BluetoothAdapter: startLeScan(): null 
BluetoothAdapter: onClientRegistered() - status=0 clientIf=5 
BluetoothGattActivity: New LE Device: PUNE @ -38 
BluetoothAdapter: stopLeScan() 
BluetoothGattActivity: Connecting to PUNE 
BluetoothGatt: connect() - device: B0:B4:48:BA:40:84, auto: false 
BluetoothGatt: registerApp() 
BluetoothGatt: registerApp() - UUID=0bdf35a7-d4d0-4048-be15-a6cb030626f5 
BluetoothGatt: onClientRegistered() - status=0 clientIf=5 
BluetoothGatt: onClientConnectionState() - status=0 clientIf=5    device=B0:B4:48:BA:40:84 
BluetoothGattActivity: Connection State Change: 0 -> Connected 
BluetoothGatt: discoverServices() - device: B0:B4:48:BA:40:84 

我正在尋找的服務是在這裏找到..

onGetCharacteristic() - Device=B0:B4:48:BA:40:84 UUID=3e099919-293f-11e4-93bd-afd0fe6d1dfd 
onGetCharacteristic() - Device=B0:B4:48:BA:40:84 UUID=3e099915-293f-11e4-93bd-afd0fe6d1dfd 
onGetCharacteristic() - Device=B0:B4:48:BA:40:84 UUID=3e099916-293f-11e4-93bd-afd0fe6d1dfd 
onGetCharacteristic() - Device=B0:B4:48:BA:40:84 UUID=3e099917-293f-11e4-93bd-afd0fe6d1dfd 

這裏是哪裏出了問題就出現了。

D/BluetoothGattActivity: Services Discovered: 0 
D/BluetoothGattActivity: Enable Public Key 
W/BluetoothGatt: Unhandled exception in callback 
W/BluetoothGatt: java.lang.NullPointerException 
W/BluetoothGatt:  at gune.blegune.MainActivity$3.enabled(MainActivity.java:232) 
W/BluetoothGatt:  at gune.blegune.MainActivity$3.onServicesDiscovered(MainActivity.java:314) 
W/BluetoothGatt:  at android.bluetooth.BluetoothGatt$1.onSearchComplete(BluetoothGatt.java:295) 
W/BluetoothGatt:  at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:215) 
W/BluetoothGatt:  at android.os.Binder.execTransact(Binder.java:404) 
W/BluetoothGatt:  at dalvik.system.NativeStart.run(Native Method) 
D/BluetoothGatt: onClientConnectionState() - status=0 clientIf=5 device=B0:B4:48:BA:40:84 
D/BluetoothGattActivity: Connection State Change: 0 -> Disconnected 
D/BluetoothAdapter: stopLeScan() 

請。一些幫助將不勝感激。非常感謝!

+0

您發現的服務列表是什麼樣的?您所顯示的日誌表明特徵UUID有效,但沒有任何信息表明您的服務UUID是正確的。 – Devunwired

回答

0

我想這是被投擲NPE的行:

特性= gatt.getService(SECURITY_SERVICE).getCharacteristic(SECURITY_PUBLICKEY);

因此,無論

GATT爲空或

gatt.getService(SECURITY_SERVICE)

被返回null。

你可以添加一些日誌記錄來找出它是哪一個?

我的猜測是這是第二種情況,我建議你在BluetoothGatt對象上調用getServices(),並在結果列表中記錄每個BluetoothGattService對象的UUID,以仔細檢查你是否擁有你認爲應該擁有的服務UUID。

getService的規範說「如果支持,則爲」BluetoothGattService;如果請求的服務不是由遠程設備提供,則爲null「。