我是android开发的新手,正在开发一个通过Uart服务将数据传输/接收到BLE模块的应用程序。
使用智能手机android 5.x.x,该应用程序可以正常运行,它可以与硬件连接并接收/传输数据。
使用智能手机android 7.x.x,该应用无法连接。 在下面,您可以看到MainActivity.java的代码段:
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "HW_CONNECT_MSG");
DisconnectButton.setEnabled(true);
DeviceInfo.setText("Device Information:");
DeviceName.setText(mDevice.getName() + " - Connected");
mState = UART_PROFILE_CONNECTED;
isConnected = true;
if(isConnected) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x43; // 'C';
Connectcmd[3] = (byte) 0x54; // 'T'
Connectcmd[4] = (byte) ETX;
try {
//send data to UART service
SendData(Connectcmd);
sleep(500); // wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
else
{
isConnected = false;
}
}
});
}
似乎在发送数据时,GATT操作尚未完成。由于action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART)
,智能手机显示消息“设备不支持通过BLE的UART。正在断开连接...”。
如果我删除if(isConnected)... else ...语句,则具有Android 7.x.x的智能手机也将连接。 我的问题是怎么回事,该如何解决?
我的目标是通过BLE向硬件发送命令,以便在连接MCU时,蜂鸣器发出声音。
感谢您的帮助。
编辑
下面您可以找到整个MainActivity:
public class MainActivity extends Activity implements RadioGroup.OnCheckedChangeListener {
public static final String TAG = "DEBUG ";
public static final String DEV_NAME_FILTER = "";
private static final int REQUEST_SELECT_DEVICE = 1;
private static final int REQUEST_ENABLE_BT = 2;
private static final int UART_PROFILE_READY = 10;
private static final int UART_PROFILE_CONNECTED = 20;
public static final int UART_PROFILE_DISCONNECTED = 21;
private static final int STATE_OFF = 10;
private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
TextView mRemoteRssiVal;
RadioGroup mRg;
private int mState = UART_PROFILE_DISCONNECTED;
private static UartService mService = null;
private static BluetoothDevice mDevice = null;
private BluetoothAdapter mBtAdapter = null;
private ListView messageListView;
private ArrayAdapter<String> listAdapter;
private Button SelectButton, DisconnectButton;
private EditText edtMessage;
private static Context context;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
private GoogleApiClient client;
private static TextView DeviceInfo;
private static TextView DeviceName;
private static TextView Manufacturer;
public static boolean isConnected;
public static boolean isSetting;
public static boolean isReading;
public static boolean isManual;
public static boolean isFunctional;
public static boolean isBootloader;
public static byte[] SettingValues;
public static byte[] ReadingValues;
public static byte[] ManualValues;
public static byte[] FunctionalValues;
private static byte[] Connectcmd = new byte[5];
public static int STX = 0x3E; // '>'
public static int ETX = 0x23; // '#'
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DeviceInfo = (TextView) findViewById(R.id.deviceInfo);
DeviceName = (TextView) findViewById(R.id.deviceName);
Manufacturer= (TextView) findViewById(R.id.manufacturer);
isConnected = false;
isSetting = false;
isReading = false;
isManual = false;
isFunctional = false;
isBootloader = false;
context = this;
//Enable location
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Android M Permission check
if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("This app needs location access");
builder.setMessage("Please grant location access so this app can detect beacons.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
@TargetApi(Build.VERSION_CODES.M)
public void onDismiss(DialogInterface dialog) {
requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, PERMISSION_REQUEST_COARSE_LOCATION);
}
});
builder.show();
}
}
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBtAdapter == null) {
Toast.makeText(this, "Bluetooth is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
SelectButton = (Button) findViewById(R.id.button);
DisconnectButton = (Button) findViewById(R.id.disconnect);
DisconnectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x44; // 'D';
Connectcmd[3] = (byte) 0x43; // 'C'
Connectcmd[4] = (byte) ETX;
try {
//send data to Banner service
SendData(Connectcmd);
sleep(500); // Wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
MainActivity.disconnected();
setContentView(R.layout.activity_main);
finish();
} catch (Exception e) {
Log.e(TAG, "Disconnect error");
}
}
});
// Handle Select device button
SelectButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onClick - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
} else {
if (SelectButton.getText().equals("SELECT CELU")) {
//Connect button pressed, open DeviceListActivity class, with popup windows that scan for devices
Log.i(TAG, "Push button CONNECT");
Intent newIntent = new Intent(context, DeviceListActivity.class);
((Activity) context).startActivityForResult(newIntent, MainActivity.REQUEST_SELECT_DEVICE);
} else {
//Disconnect button pressed
disconnected();
}
}
}
});
// Set initial UI state
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
//UART service connected/disconnected
private ServiceConnection mServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder rawBinder) {
mService = ((UartService.LocalBinder) rawBinder).getService();
Log.d(TAG, "onServiceConnected mService= " + mService);
if (!mService.initialize()) {
Log.e(TAG, "Unable to initialize Bluetooth");
finish();
}
}
public void onServiceDisconnected(ComponentName classname) {
//// mService.disconnect(mDevice);
mService = null;
}
};
private Handler mHandler = new Handler() {
@Override
//Handler events that received from UART service
public void handleMessage(Message msg) {
}
};
private final BroadcastReceiver UARTStatusChangeReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final Intent mIntent = intent;
//*********************//
if (action.equals(UartService.ACTION_GATT_CONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
String currentDateTimeString = DateFormat.getTimeInstance().format(new Date());
Log.d(TAG, "CELU_CONNECT_MSG");
//btnConnectDisconnect.setText("Disconnect");
//edtMessage.setEnabled(true);
DisconnectButton.setEnabled(true);
DeviceInfo.setText("Device Information:");
DeviceName.setText(mDevice.getName() + " - Connected");
mState = UART_PROFILE_CONNECTED;
isConnected = true;
//IF COMMENTED THE APP CONNECTS!!!!!!!!!!!!!!!!!!
//ELSE IF NOT COMMENTED THE APP NEVER CONNECTS
/*if(isConnected) {
//Serial protocol to send command on MCU
Connectcmd[0] = (byte) STX;
Connectcmd[1] = (byte) 0x02;
Connectcmd[2] = (byte) 0x43; // 'C';
Connectcmd[3] = (byte) 0x54; // 'T'
Connectcmd[4] = (byte) ETX;
try {
//send data to UART service
SendData(Connectcmd);
sleep(500); // Wait 500ms to send data
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
else
{
isConnected = false;
}*/
new Handler().postDelayed(mUpdateTimeTask, 2000);
}
});
}
//*********************//
if (action.equals(UartService.ACTION_GATT_DISCONNECTED)) {
runOnUiThread(new Runnable() {
public void run() {
Log.d(TAG, "HW_DISCONNECT_MSG");
DisconnectButton.setEnabled(false);
DeviceName.setText("Not Connected");
mState = UART_PROFILE_DISCONNECTED;
mService.close();
//setUiState();
}
});
}
//Enable notifivcation on UART service//
if (action.equals(UartService.ACTION_GATT_SERVICES_DISCOVERED)) {
mService.enableTXNotification();
}
//*********************//
if (action.equals(UartService.ACTION_DATA_AVAILABLE)) {
final byte[] txValue = intent.getByteArrayExtra(UartService.EXTRA_DATA);
try {
ParsingPacket(txValue);
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
//*********************//
if (action.equals(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART)) {
showMessage("Device doesn't support UART over BLE Celu . Disconnecting");
mService.disconnect();
}
}
};
private static void ParsingPacket(byte[] packet) throws Exception {
if (packet.length == 0) {
// received empty packet
isConnected = false;
isSetting = false;
isReading = false;
isManual = false;
isFunctional = false;
isBootloader = false;
}
if(isSetting){
isSetting = false;
SettingValues = packet.clone();
String text = new String(SettingValues, "UTF-8");
Log.d(TAG, text);
}
if(isReading){
ReadingValues= packet;
ReadActivity.updateMeasure(ReadingValues);
//ReadActivity.addData(packet);
//String text = new String(ReadingValues, "UTF-8");
Log.d("Length ", String.format("%02d", (int) ReadingValues.length));
for(int i=0; i<ReadingValues.length; i++) {
String text = String.format("%02x", (int) ReadingValues[i]);
Log.d(TAG, text);
}
}
if(isManual){
isManual = false;
ManualValues = packet.clone();
String text = new String(ManualValues, "UTF-8");
Log.d(TAG, text);
}
if(isFunctional){
isFunctional = false;
FunctionalValues = packet.clone();
String text = new String(FunctionalValues, "UTF-8");
Log.d(TAG, text);
}
if(isBootloader){
isBootloader = false;
// do samething
}
}
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
if(DeviceName.getText()!="Not Connected") {
Intent connectedIntent = new Intent(getApplicationContext(), MenuActivity.class); //new Intent("com.antertech.mybleapplication.MenuActivity");
startActivity(connectedIntent);
}
}
};
private void service_init() {
Intent bindIntent = new Intent(this, UartService.class);
bindService(bindIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
LocalBroadcastManager.getInstance(this).registerReceiver(UARTStatusChangeReceiver, makeGattUpdateIntentFilter());
}
private static IntentFilter makeGattUpdateIntentFilter() {
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(UartService.ACTION_GATT_CONNECTED);
intentFilter.addAction(UartService.ACTION_GATT_DISCONNECTED);
intentFilter.addAction(UartService.ACTION_GATT_SERVICES_DISCOVERED);
intentFilter.addAction(UartService.ACTION_DATA_AVAILABLE);
intentFilter.addAction(UartService.DEVICE_DOES_NOT_SUPPORT_BLE_UART);
return intentFilter;
}
@Override
public void onStart() {
super.onStart();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.connect();
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.start(client, getIndexApiAction());
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
try {
LocalBroadcastManager.getInstance(this).unregisterReceiver(UARTStatusChangeReceiver);
} catch (Exception ignore) {
Log.e(TAG, ignore.toString());
}
unbindService(mServiceConnection);
mService.stopSelf();
mService = null;
}
@Override
protected void onStop() {
Log.d(TAG, "onStop");
super.onStop();// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
AppIndex.AppIndexApi.end(client, getIndexApiAction());
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
client.disconnect();
}
@Override
protected void onPause() {
Log.d(TAG, "onPause");
super.onPause();
}
@Override
protected void onRestart() {
super.onRestart();
Log.d(TAG, "onRestart");
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume");
if (!mBtAdapter.isEnabled()) {
Log.i(TAG, "onResume - BT not enabled yet");
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_SELECT_DEVICE:
//When the DeviceListActivity return, with the selected device address
if (resultCode == Activity.RESULT_OK && data != null) {
String deviceAddress = data.getStringExtra(BluetoothDevice.EXTRA_DEVICE);
mDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(deviceAddress);
Log.d(TAG, "... onActivityResultdevice.address==" + mDevice + " mserviceValue " + mService);
mService.connect(deviceAddress);
//setContentView(R.layout.activity_setting);
((TextView) findViewById(R.id.deviceName)).setText(mDevice.getName() + " - Connecting...");
}
break;
case REQUEST_ENABLE_BT:
// When the request to enable Bluetooth returns
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, "Bluetooth has turned on ", Toast.LENGTH_SHORT).show();
} else {
// User did not enable Bluetooth or an error occurred
Log.d(TAG, "BT not enabled");
Toast.makeText(this, "Problem in BT Turning ON ", Toast.LENGTH_SHORT).show();
finish();
}
break;
default:
Log.e(TAG, "wrong request code");
break;
}
}
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
}
public static void SendData(byte[] text) {
mService.writeRXCharacteristic(text);
Log.i(TAG, "Message send to Target");
}
public static void disconnected() {
if (mDevice != null) {
mService.disconnect();
Log.i(TAG, "Push Button DISCONNECT");
}
}
private void showMessage(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
@Override
public void onBackPressed() {
if (mState == UART_PROFILE_CONNECTED) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain);
showMessage("CELU TPE running in background.\n Disconnect to exit");
} else {
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.popup_title)
.setMessage(R.string.popup_message)
.setPositiveButton(R.string.popup_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
})
.setNegativeButton(R.string.popup_no, null)
.show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[],
int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_COARSE_LOCATION: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "coarse location permission granted");
} else {
final AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Functionality limited");
builder.setMessage("Since location access has not been granted, this app will not be able to discover beacons when in the background.");
builder.setPositiveButton(android.R.string.ok, null);
builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
}
});
builder.show();
}
return;
}
}
}
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
public Action getIndexApiAction() {
Thing object = new Thing.Builder()
.setName("Main Page") // TODO: Define a title for the content shown.
// TODO: Make sure this auto-generated URL is correct.
.setUrl(Uri.parse("http://[ENTER-YOUR-URL-HERE]"))
.build();
return new Action.Builder(Action.TYPE_VIEW)
.setObject(object)
.setActionStatus(Action.STATUS_TYPE_COMPLETED)
.build();
}
}