我目前正在做一个项目,该项目需要Android手机应用程序对特定的SensorTag进行后台扫描并触发通知以提醒用户清理他们的手。
我已设法创建应用,并可在应用运行时收到通知消息。我的应用程序可以扫描ble设备并使用listadapter显示它们,并且可以间隔10秒扫描。
但是,当手机正在睡觉或我正在使用其他应用时,我无法收到任何通知消息,这会破坏我的项目目的。
如果有人能够启发我,我将不胜感激。
由于
Chrysline
* P.S。我只在广播模式和蓝牙智能模式下使用SensorTag。我的目标只是API 18手机。
public class MainActivity extends ListActivity{
//Bluetooth Management
private BluetoothAdapter btAdapter;
private LeDeviceListAdapter mLeDeviceListAdapter;
private boolean mScanning;
// Set the enable bluetooth code
private final static int REQUEST_ENABLE_BT = 0;
//Handler
private Handler myHandler;
private static final int SCAN_INTERVAL_MS_1 = 10000;
// Notification
private static final int NOTIFY_1 = 0x1001;
private static int mNotificationCount = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myHandler = new Handler();
//Check whether BLE is supported on the device(can selectively disable BLE-related features)
if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
Toast.makeText(this, "ble_not_supported", Toast.LENGTH_SHORT).show();
finish();
}
final BluetoothManager btManager =
(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
//Check if Bluetooth Adapter is present in the device
if(btAdapter == null)
{
Toast.makeText(this, "Error : Bluetooth not supported", Toast.LENGTH_SHORT).show();
Log.i("DEBUG_TAG", "No bluetooth available");
finish();
return;
}
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onResume() {
super.onResume();
// check for Bluetooth enabled on each resume
if (btAdapter != null && !btAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
}
//Initialise list view adapter
mLeDeviceListAdapter = new LeDeviceListAdapter();
setListAdapter(mLeDeviceListAdapter);
scanLeDevice(true);
}
@Override
public void onPause() {
super.onPause();
mLeDeviceListAdapter.clear();
scanLeDevice(true);
Log.i("DEBUG_TOAST", "Scanning in onPause method!!!");
}
@Override
public void onStop() {
super.onStop();
scanLeDevice(false);
mLeDeviceListAdapter.clear();
}
@Override
public void onRestart() {
super.onRestart();
scanLeDevice(true);
}
@Override
public void onDestroy() {
super.onDestroy();
btAdapter = null;
}
@Override
protected void onActivityResult(int request_enable_bt, int result_enable_bt, Intent data) {
if (result_enable_bt == RESULT_OK) {
//Display "Turn On" message
Toast.makeText(this, "Turned On", Toast.LENGTH_SHORT).show();
Log.i("DEBUG_TOAST", "Turn On Toast Success!");
// Display device name and MAC Address
BluetoothManager btManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
String address = btAdapter.getAddress();
String name = btAdapter.getName();
String toastText = name + " : " + address;
Toast.makeText(this, toastText, Toast.LENGTH_LONG).show();
Log.i("DEBUG_TOAST", "Device Name and Address Toast Success!");
} else if (result_enable_bt == RESULT_CANCELED) {
Toast.makeText(this, "Didn't Turn On", Toast.LENGTH_SHORT).show();
Log.i("DEBUG_TOAST", "Turn Off Toast Success!");
finish();
}
super.onActivityResult(request_enable_bt, result_enable_bt, data);
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
getMenuInflater().inflate(R.menu.main_menu, menu);
if(!mScanning){
menu.findItem(R.id.scan).setVisible(true);
menu.findItem(R.id.stop).setVisible(false);
menu.findItem(R.id.exit).setVisible(true);
menu.findItem(R.id.info).setVisible(true);
menu.findItem(R.id.refresh).setActionView(null);
Log.i("DEBUG_TOAST", "Menu_mScanning = 0");
}
else{
menu.findItem(R.id.scan).setVisible(false);
menu.findItem(R.id.stop).setVisible(true);
menu.findItem(R.id.exit).setVisible(true);
menu.findItem(R.id.info).setVisible(true);
menu.findItem(R.id.refresh).setActionView(
R.layout.actionbar_indeterminate_progress);
Log.i("DEBUG_TOAST", "Menu_mScanning = 1");
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
switch (item.getItemId()){
case R.id.scan:
if(mLeDeviceListAdapter.getCount() >0)
mLeDeviceListAdapter.clear();
scanLeDevice(true);
Log.i("DEBUG_TOAST", "Scan button pressed!");
break;
case R.id.stop:
scanLeDevice(false);
break;
case R.id.info:
Intent information_Intent = new Intent(MainActivity.this, Information.class);
startActivity(information_Intent);
break;
case R.id.reminder:
Intent reminder_Intent = new Intent(MainActivity.this, Reminder.class);
startActivity(reminder_Intent);
break;
case R.id.exit:
finish();
break;
}
return true;
}
protected void onListItemClick(ListView l, View v, int position, long id) {
final BluetoothDevice device = mLeDeviceListAdapter.getDevice(position);
if (device == null) return;
final Intent intent = new Intent(this, DeviceControlActivity.class);
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName());
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress());
if (mScanning) {
btAdapter.stopLeScan(leScanCallback);
mScanning = false;
}
startActivity(intent);
}
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, final int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device, rssi);
Log.i("DEBUG-ScanCallBack", "add device");
mLeDeviceListAdapter.notifyDataSetChanged();
Log.i("DEBUG-ScanCallBack", "notify data set changed");
}
});
}
};
private void scanLeDevice(final boolean enable) {
if (enable) {
Log.i("DEBUG_TOAST", "Scanning enabled!");
// Stops scanning after a pre-defined scan period.
myHandler.postDelayed(new Runnable() {
@Override
public void run() {
mScanning = false;
Log.i("DEBUG_TOAST", "scanLeEnable_mScanning = 0");
btAdapter.stopLeScan(leScanCallback);
invalidateOptionsMenu();
}
}, SCAN_INTERVAL_MS_1);
mScanning = true;
Log.i("DEBUG_TOAST", "scanLeEnable_mScanning = 1");
btAdapter.startLeScan(leScanCallback);
new CountDownTimer(5000, 1000) {
public void onFinish() {
// When timer is finished
// Execute your code here
myHandler.postDelayed(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.clear();
Log.i("DEBUG_TOAST", "List Adapter cleared scan handler");
mScanning = true;
Log.i("DEBUG_TOAST", "scanLeEnable_mScanning = 1 (Timer)");
btAdapter.startLeScan(leScanCallback);
invalidateOptionsMenu();
scanLeDevice(true);
}
}, SCAN_INTERVAL_MS_1); }
public void onTick(long millisUntilFinished) {
// millisUntilFinished The amount of time until finished.
}
}.start();
} else {
mScanning = false;
Log.i("DEBUG_TOAST", "scanLeNotEnable_mScanning = 0");
btAdapter.stopLeScan(leScanCallback);
}
invalidateOptionsMenu();
}
//Adapter for holding devices found through scanning
private class LeDeviceListAdapter extends BaseAdapter {
private ArrayList<BluetoothDevice> mLeDevices;
private LayoutInflater mInflator;
private final HashMap<BluetoothDevice, Integer> rssiMap = new HashMap<BluetoothDevice, Integer>();
public LeDeviceListAdapter() {
super();
mLeDevices = new ArrayList<BluetoothDevice>();
Log.i("LISTVIEW_1", "z" );
mInflator = MainActivity.this.getLayoutInflater();
Log.i("LISTVIEW_1", "a" );
}
public void addDevice(BluetoothDevice device, int rssi) {
if (!mLeDevices.contains(device)) {
mLeDevices.add(device);
Log.i("LISTVIEW_1", "b");
rssiMap.put(device, rssi);
Log.i("LISTVIEW_1", "b1");
}
else {
rssiMap.put(device, rssi);
Log.i("LISTVIEW_1", "b2");
}
}
public BluetoothDevice getDevice(int position) {
Log.i("LISTVIEW_1", "c");
return mLeDevices.get(position);
}
public void clear() {
Log.i("LISTVIEW_1", "d" );
mLeDevices.clear();
}
@Override
public int getCount() {
Log.i("LISTVIEW_1", "e" + mLeDevices.size());
return mLeDevices.size();
}
@Override
public Object getItem(int i) {
Log.i("LISTVIEW_1", "f" );
return mLeDevices.get(i);
}
@Override
public long getItemId(int i) {
Log.i("LISTVIEW_1", "g" );
return i;
}
public View getView(int position, View convertView, ViewGroup parent){
ViewHolder viewHolder;
if (convertView == null){
mInflator =
(LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
convertView = mInflator.inflate(R.layout.listitem_device, null);
Log.i("LISTVIEW_1", "0" );
viewHolder = new ViewHolder();
viewHolder.deviceAddress = (TextView) convertView.findViewById(R.id.device_address);
Log.i("LISTVIEW_1", "1" );
viewHolder.deviceName = (TextView) convertView.findViewById(R.id.device_name);
Log.i("LISTVIEW_1", "2" );
viewHolder.deviceRssi = (TextView) convertView.findViewById(R.id.device_rssi);
Log.i("LISTVIEW_1", "2.5" );
convertView.setTag(viewHolder);
Log.i("LISTVIEW_1", "3");
}
else{
viewHolder = (ViewHolder) convertView.getTag();
Log.i("LISTVIEW_1", "4" );
}
BluetoothDevice device = mLeDevices.get(position);
Log.i("LISTVIEW_1", "5" );
final String deviceName = device.getName();
Log.i("LISTVIEW_1", "6");
final int deviceRSSI = rssiMap.get(device);
Log.i("LISTVIEW_1", "6.1");
if(deviceName != null && deviceName.length() > 0 ) {
if (deviceRSSI >= -50 && deviceName.equals("CC2650 SensorTag") ||
deviceName.equals("SimpleBLEBroadcaster")) {
viewHolder.deviceName.setText(deviceName);
NotificationManager notifier = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder notifyBuilder = new
NotificationCompat.Builder(getApplicationContext());
notifyBuilder.setSmallIcon(R.drawable.hand_sanitise_image);
notifyBuilder.setTicker("Attention!");
notifyBuilder.setWhen(System.currentTimeMillis());
Intent toLaunch = new Intent(MainActivity.this,
Reminder.class);
notifyBuilder.setContentIntent(PendingIntent.getActivity(
MainActivity.this, 0, toLaunch, 0));
notifyBuilder.setContentTitle("Take a look!");
notifyBuilder.setContentText("Will benefit everyone!!! (" + mNotificationCount++
+ ")");
notifyBuilder.setAutoCancel(true);
notifyBuilder.setVibrate(new long[]{0, 200, 200, 600, 600});
notifier.notify(NOTIFY_1, notifyBuilder.build());
Log.i("LISTVIEW_1", "Notification Vibrate Success");
mScanning = false;
Log.i("DEBUG_TOAST", "scanLeEnable_mScanning = 0 (Notification)");
btAdapter.stopLeScan(leScanCallback);
invalidateOptionsMenu();
new CountDownTimer(10000, 1000) {
public void onFinish() {
// When timer is finished
// Execute your code here
mLeDeviceListAdapter.clear();
Log.i("LISTVIEW_1", "List Adapter cleared due to notification");
scanLeDevice(true);
Log.i("LISTVIEW_1", "CountDownTimer Success!");
}
public void onTick(long millisUntilFinished) {
// millisUntilFinished The amount of time until finished.
}
}.start();
}
viewHolder.deviceName.setText(deviceName);
Log.i("LISTVIEW_1", "8.1");
viewHolder.deviceAddress.setText(device.getAddress());
Log.i("LISTVIEW_1", "9.1");
viewHolder.deviceRssi.setText("" + rssiMap.get(device) + " dBm");
Log.i("LISTVIEW_1", "10.1");
}
else
viewHolder.deviceName.setText(R.string.unknown_device);
Log.i("LISTVIEW_1", "8");
viewHolder.deviceAddress.setText(device.getAddress());
Log.i("LISTVIEW_1", "9");
viewHolder.deviceRssi.setText(""+rssiMap.get(device)+" dBm");
Log.i("LISTVIEW_1", "10");
return convertView;
}
}
static class ViewHolder {
TextView deviceRssi, deviceAddress, deviceName;
}
}