package com.yeokm1.bleintro; import android.Manifest; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; public class MainActivity extends Activity implements BLEHandlerCallback{ public static final String TAG = "MainActivity"; private static final int REQUEST_CODE_ASK_PERMISSIONS = 123; private TextView statusView; private ListView bleScannedList; private ArrayAdapter devicesListAdapter; private ArrayList<String> devicesMacAddr; private BLEHandler bleHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bleHandler = new BLEHandler(getApplicationContext(), this); BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (mBluetoothAdapter == null) { Toast.makeText(this, "Your device does not have Bluetooth", Toast.LENGTH_SHORT).show(); finish(); return; } //Check if at least Android 4.3 if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){ Toast.makeText(this, "You need Android 4.3 and above to use BLE.", Toast.LENGTH_SHORT).show(); finish(); return; } //It's rare for devices that ship with Android 4.3 and above to not have BLE hardware // but we still follow Google's recommendation and check anyway if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, "BLE hardware not found", Toast.LENGTH_SHORT).show(); finish(); return; } //New in Android 6.0 Marshmallow, we now have runtime permissions. //BLE Scan requires location permissions and we have to ask the user to approve on runtime if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { int hasLocationsPermission = checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION); if (hasLocationsPermission != PackageManager.PERMISSION_GRANTED) { requestPermissions(new String[] {Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_CODE_ASK_PERMISSIONS); } } statusView = (TextView)findViewById(R.id.textview_status); devicesMacAddr = new ArrayList<String>(); devicesListAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, new ArrayList<String>()); bleScannedList = (ListView) findViewById(R.id.listview_scanned); bleScannedList.setAdapter(devicesListAdapter); bleScannedList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //Stop scan before attempting to connect bleHandler.bleScan(false); String macAddressOfDeviceToConnect = devicesMacAddr.get(position); bleHandler.connectToDevice(macAddressOfDeviceToConnect); } }); } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { switch (requestCode) { case REQUEST_CODE_ASK_PERMISSIONS: if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { Toast.makeText(MainActivity.this, "Location Permission granted, you can now scan for Bluetooth devices", Toast.LENGTH_LONG).show(); } else { // Permission Denied Toast.makeText(MainActivity.this, "Location Permission denied, so Bluetooth will not work. Closing app...", Toast.LENGTH_LONG).show(); finish(); } break; default: super.onRequestPermissionsResult(requestCode, permissions, grantResults); } } public void startScanButtonPressed(View view){ if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivity(enableBtIntent); return; } showStatusToScreen("Scanning for BLE peripherals..."); devicesMacAddr.clear(); devicesListAdapter.clear(); devicesListAdapter.notifyDataSetChanged(); bleHandler.bleScan(true); } public void stopScanButtonPressed(View view){ showStatusToScreen("Scan stopped"); bleHandler.bleScan(false); } public void disconnectButtonPressed(View view){ bleHandler.disconnectCurrentlyConnectedDevice(); } public void toggleBlueButtonPressed(View view){ bleHandler.sendToggleBlueCommand(); } public void toggleYellowButtonPressed(View view){ bleHandler.sendToggleYellowCommand(); } public void showDeviceStatusToScreen(String frontMessage, String localName, String macAddress){ String message = String.format("%s: %s (%s)", frontMessage, macAddress, localName); showStatusToScreen(message); } public void showStatusToScreen(final String message){ //Run in UI thread as sometimes this method may be called from other threads runOnUiThread(new Runnable() { @Override public void run() { statusView.setText(message); } }); } //BLEHandler callbacks @Override public void newDeviceScanned(final String localName, final String macAddress, final int rssi, byte[] scanRecord) { runOnUiThread(new Runnable() { @Override public void run() { String displayMessage = String.format("%s (%s), rssi: %d", macAddress, localName, rssi); devicesMacAddr.add(macAddress); devicesListAdapter.add(displayMessage); devicesListAdapter.notifyDataSetChanged(); } }); } @Override public void connectionState(String localName, String macAddress, boolean state){ if(state){ showDeviceStatusToScreen("Connected to", localName, macAddress); } else { showDeviceStatusToScreen("Disconnected from", localName, macAddress); } } @Override public void servicesDiscoveredState(String localName, String macAddress, boolean state){ if(state){ showDeviceStatusToScreen("Services discovered for", localName, macAddress); } else { showDeviceStatusToScreen("Service Discovery failed for", localName, macAddress); } } @Override public void receivedStringValue(String localName, String macAddress, final String strValue){ showDeviceStatusToScreen("Received \"" + strValue + "\" from ", localName, macAddress); } }