Java tutorial
/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mikroe.hexiwear_android; import android.app.Activity; import android.app.ListActivity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.provider.Settings; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.SimpleExpandableListAdapter; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Activity for scanning and displaying available Bluetooth LE devices. */ public class DeviceScanActivity extends Activity { private static final String TAG = "DeviceScanActivity"; private BluetoothAdapter mBluetoothAdapter; private Handler mHandler; public static final String UUID_CHAR_ALERTIN = "00002031-0000-1000-8000-00805f9b34fb"; private BluetoothGattCharacteristic alertInCharacteristic; private static final int REQUEST_ENABLE_BT = 1; public static final String KWARP_ADDRESS = "00:39:40:0A:00:07"; public static final String KWARP_ADDRESS_TWO = "00:48:40:0B:00:2B"; private TextView mScanTitle; //both devices private ArrayList<String> mDeviceAddresses; private BluetoothGattCharacteristic mNotifyCharacteristic; private final String LIST_NAME = "NAME"; private final String LIST_UUID = "UUID"; private static BluetoothLeService mBluetoothLeService; private static ArrayList<ArrayList<ArrayList<BluetoothGattCharacteristic>>> mGattsCharacteristics = new ArrayList<>(); //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// public static ArrayList<ArrayList<ArrayList<BluetoothGattCharacteristic>>> getGattsCharacteristics() { return mGattsCharacteristics; } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// public static BluetoothLeService getBluetoothLeService() { return mBluetoothLeService; } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.listitem_device); mHandler = new Handler(); mDeviceAddresses = new ArrayList<String>(); mScanTitle = (TextView) findViewById(R.id.scanTitle); mDeviceAddresses.add(KWARP_ADDRESS); mDeviceAddresses.add(KWARP_ADDRESS_TWO); // Use this check to determine whether BLE is supported on the device. Then you can // selectively disable BLE-related features. if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); finish(); } // Initializes a Bluetooth adapter. For API level 18 and above, get a reference to // BluetoothAdapter through BluetoothManager. final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); // Checks if Bluetooth is supported on the device. if (mBluetoothAdapter == null) { Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); finish(); return; } // Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled, // fire an intent to display a dialog asking the user to grant permission to enable it. if (!mBluetoothAdapter.isEnabled()) { if (!mBluetoothAdapter.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } } //checkNotificationEnabled(); LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, new IntentFilter("Msg")); ComponentName name = startService(new Intent(DeviceScanActivity.this, NotificationService.class)); registerReceiver(mGattUpdateReceiver, makeGattUpdateIntentFilter()); scanLeDevice(true); Intent gattServiceIntent = new Intent(DeviceScanActivity.this, BluetoothLeService.class); bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// @Override protected void onDestroy() { super.onDestroy(); unregisterReceiver(mGattUpdateReceiver); mBluetoothLeService = null; stopService(new Intent(DeviceScanActivity.this, NotificationService.class)); mGattsCharacteristics.clear(); //other unbindService(mServiceConnection); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// @Override protected void onResume() { super.onResume(); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// @Override protected void onPause() { super.onPause(); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // Demonstrates how to iterate through the supported GATT Services/Characteristics. // In this sample, we populate the data structure that is bound to the ExpandableListView // on the UI. //TODO see if this works private void displayGattServices(List<List<BluetoothGattService>> devicesGattServices) { if (devicesGattServices == null) return; String uuid = null; ArrayList<HashMap<String, String>> gattServiceData = new ArrayList<HashMap<String, String>>(); ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = new ArrayList<ArrayList<HashMap<String, String>>>(); ArrayList<ArrayList<BluetoothGattCharacteristic>> tempGattCharacteristics = new ArrayList<>(); mGattsCharacteristics.clear(); for (List<BluetoothGattService> gattServices : devicesGattServices) { // Loops through available GATT Services. for (BluetoothGattService gattService : gattServices) { HashMap<String, String> currentServiceData = new HashMap<String, String>(); uuid = gattService.getUuid().toString(); currentServiceData.put(LIST_UUID, uuid); gattServiceData.add(currentServiceData); ArrayList<HashMap<String, String>> gattCharacteristicGroupData = new ArrayList<HashMap<String, String>>(); List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics(); ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>(); // Loops through available Characteristics. for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { charas.add(gattCharacteristic); HashMap<String, String> currentCharaData = new HashMap<String, String>(); uuid = gattCharacteristic.getUuid().toString(); if (uuid.equals(UUID_CHAR_ALERTIN)) { alertInCharacteristic = gattCharacteristic; byte[] value = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; alertInCharacteristic.setValue(value); } currentCharaData.put(LIST_UUID, uuid); gattCharacteristicGroupData.add(currentCharaData); } tempGattCharacteristics.add(charas); gattCharacteristicData.add(gattCharacteristicGroupData); } mGattsCharacteristics.add(tempGattCharacteristics); } mHandler.postDelayed(new Runnable() { @Override public void run() { Intent intent = new Intent(DeviceScanActivity.this, MainScreenActivity.class); startActivity(intent); } }, 1500); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// private static IntentFilter makeGattUpdateIntentFilter() { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(BluetoothLeService.ACTION_GATT_CONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_DISCONNECTED); intentFilter.addAction(BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED); intentFilter.addAction(BluetoothLeService.ACTION_DATA_AVAILABLE); intentFilter.addAction(BluetoothLeService.ACTION_WRITE_RESPONSE_OK); intentFilter.addAction(BluetoothLeService.ACTION_WRITE_RESPONSE_ERROR); return intentFilter; } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// private BroadcastReceiver onNotice = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // String pack = intent.getStringExtra("package"); String title = intent.getStringExtra("title"); String text = intent.getStringExtra("text"); if ((alertInCharacteristic != null) && (mBluetoothLeService != null)) { int charaProp = alertInCharacteristic.getProperties(); if ((charaProp & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0) { byte[] bytes = Arrays.copyOf(text.getBytes(), 20); alertInCharacteristic.setValue(bytes); while (mBluetoothLeService.writeNoResponseCharacteristic(alertInCharacteristic) == false) { try { Thread.sleep(50); } catch (InterruptedException e) { Log.e(TAG, "InterruptedException"); } } } } } }; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // Handles various events fired by the Service. // ACTION_GATT_CONNECTED: connected to a GATT server. // ACTION_GATT_DISCONNECTED: disconnected from a GATT server. // ACTION_GATT_SERVICES_DISCOVERED: discovered GATT services. // ACTION_DATA_AVAILABLE: received data from the device. This can be a result of read // or notification operations. private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) { //// TODO: 9/9/2016 wait till both devices are connected mScanTitle.setText("connected"); invalidateOptionsMenu(); } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) { invalidateOptionsMenu(); } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) { // Show all the supported services and characteristics on the user interface. displayGattServices(mBluetoothLeService.getSupportedGattServices()); } else if (BluetoothLeService.ACTION_DATA_AVAILABLE.equals(action)) { ; } else if ((BluetoothLeService.ACTION_WRITE_RESPONSE_OK.equals(action)) || (BluetoothLeService.ACTION_WRITE_RESPONSE_ERROR.equals(action))) { ; } } }; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { // User chose not to enable Bluetooth. if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { finish(); return; } super.onActivityResult(requestCode, resultCode, data); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// private void scanLeDevice(final boolean enable) { if (enable) { mBluetoothAdapter.startLeScan(mLeScanCallback); } else { mBluetoothAdapter.stopLeScan(mLeScanCallback); } invalidateOptionsMenu(); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // Device scan callback. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { //if the device is registered in the list of devices if (mDeviceAddresses.contains(device.getAddress())) { // giving me null ref on ble service, so i added this condition to make sure it is initialized //TODO fix this try { if (mBluetoothLeService.initialize()) { mBluetoothLeService.connect(mDeviceAddresses); //keep looping till both devices are connected if (mBluetoothLeService.getDevicesConnected() == 2) scanLeDevice(false); } } catch (Exception e) { e.printStackTrace(); } } } }; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // check notification access setting is enabled or not public boolean checkNotificationEnabled() { try { if (Settings.Secure.getString(this.getContentResolver(), "enabled_notification_listeners") .contains(getApplicationContext().getPackageName())) { return true; } else { //service is not enabled try to enabled by calling... Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); return false; } } catch (Exception e) { e.printStackTrace(); } return false; } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// // Code to manage Service lifecycle. private final ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder service) { mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService(); if ((!mBluetoothLeService.initialize())) { finish(); } // Automatically connects to the device upon successful start-up initialization. mBluetoothLeService.connect(mDeviceAddresses); } @Override public void onServiceDisconnected(ComponentName componentName) { mBluetoothLeService = null; } }; //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// }