Java tutorial
/* * MIT License * <p> * Copyright (c) 2017 Donato Rimenti * <p> * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * <p> * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * <p> * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package co.aurasphere.bluepair.bluetooth; import android.Manifest; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.pm.PackageManager; import android.support.v4.app.ActivityCompat; import android.support.v4.content.ContextCompat; import android.util.Log; import android.widget.Toast; import java.io.Closeable; /** * Class for handling Bluetooth connection. * * @author Donato Rimenti */ public class BluetoothController implements Closeable { /** * Tag string used for logging. */ private static final String TAG = "BluetoothManager"; /** * Interface for Bluetooth OS services. */ private final BluetoothAdapter bluetooth; /** * Class used to handle communication with OS about Bluetooth system events. */ private final BroadcastReceiverDelegator broadcastReceiverDelegator; /** * The activity which is using this controller. */ private final Activity context; /** * Used as a simple way of synchronization between turning on the Bluetooth and starting a * device discovery. */ private boolean bluetoothDiscoveryScheduled; /** * Used as a temporary field for the currently bounding device. This field makes this whole * class not Thread Safe. */ private BluetoothDevice boundingDevice; /** * Instantiates a new BluetoothController. * * @param context the activity which is using this controller. * @param listener a callback for handling Bluetooth events. */ public BluetoothController(Activity context, BluetoothAdapter adapter, BluetoothDiscoveryDeviceListener listener) { this.context = context; this.bluetooth = adapter; this.broadcastReceiverDelegator = new BroadcastReceiverDelegator(context, listener, this); } /** * Checks if the Bluetooth is already enabled on this device. * * @return true if the Bluetooth is on, false otherwise. */ public boolean isBluetoothEnabled() { return bluetooth.isEnabled(); } /** * Starts the discovery of new Bluetooth devices nearby. */ public void startDiscovery() { broadcastReceiverDelegator.onDeviceDiscoveryStarted(); // This line of code is very important. In Android >= 6.0 you have to ask for the runtime // permission as well in order for the discovery to get the devices ids. If you don't do // this, the discovery won't find any device. if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(context, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION }, 1); } // If another discovery is in progress, cancels it before starting the new one. if (bluetooth.isDiscovering()) { bluetooth.cancelDiscovery(); } // Tries to start the discovery. If the discovery returns false, this means that the // bluetooth has not started yet. Log.d(TAG, "Bluetooth starting discovery."); if (!bluetooth.startDiscovery()) { Toast.makeText(context, "Error while starting device discovery!", Toast.LENGTH_SHORT).show(); Log.d(TAG, "StartDiscovery returned false. Maybe Bluetooth isn't on?"); // Ends the discovery. broadcastReceiverDelegator.onDeviceDiscoveryEnd(); } } /** * Turns on the Bluetooth. */ public void turnOnBluetooth() { Log.d(TAG, "Enabling Bluetooth."); broadcastReceiverDelegator.onBluetoothTurningOn(); bluetooth.enable(); } /** * Performs the device pairing. * * @param device the device to pair with. * @return true if the pairing was successful, false otherwise. */ public boolean pair(BluetoothDevice device) { // Stops the discovery and then creates the pairing. if (bluetooth.isDiscovering()) { Log.d(TAG, "Bluetooth cancelling discovery."); bluetooth.cancelDiscovery(); } Log.d(TAG, "Bluetooth bonding with device: " + deviceToString(device)); boolean outcome = device.createBond(); Log.d(TAG, "Bounding outcome : " + outcome); // If the outcome is true, we are bounding with this device. if (outcome == true) { this.boundingDevice = device; } return outcome; } /** * Checks if a device is already paired. * * @param device the device to check. * @return true if it is already paired, false otherwise. */ public boolean isAlreadyPaired(BluetoothDevice device) { return bluetooth.getBondedDevices().contains(device); } /** * Converts a BluetoothDevice to its String representation. * * @param device the device to convert to String. * @return a String representation of the device. */ public static String deviceToString(BluetoothDevice device) { return "[Address: " + device.getAddress() + ", Name: " + device.getName() + "]"; } /** * {@inheritDoc} */ @Override public void close() { this.broadcastReceiverDelegator.close(); } /** * Checks if a deviceDiscovery is currently running. * * @return true if a deviceDiscovery is currently running, false otherwise. */ public boolean isDiscovering() { return bluetooth.isDiscovering(); } /** * Cancels a device discovery. */ public void cancelDiscovery() { if (bluetooth != null) { bluetooth.cancelDiscovery(); broadcastReceiverDelegator.onDeviceDiscoveryEnd(); } } /** * Turns on the Bluetooth and executes a device discovery when the Bluetooth has turned on. */ public void turnOnBluetoothAndScheduleDiscovery() { this.bluetoothDiscoveryScheduled = true; turnOnBluetooth(); } /** * Called when the Bluetooth status changed. */ public void onBluetoothStatusChanged() { // Does anything only if a device discovery has been scheduled. if (bluetoothDiscoveryScheduled) { int bluetoothState = bluetooth.getState(); switch (bluetoothState) { case BluetoothAdapter.STATE_ON: // Bluetooth is ON. Log.d(TAG, "Bluetooth succesfully enabled, starting discovery"); startDiscovery(); // Resets the flag since this discovery has been performed. bluetoothDiscoveryScheduled = false; break; case BluetoothAdapter.STATE_OFF: // Bluetooth is OFF. Log.d(TAG, "Error while turning Bluetooth on."); Toast.makeText(context, "Error while turning Bluetooth on.", Toast.LENGTH_SHORT); // Resets the flag since this discovery has been performed. bluetoothDiscoveryScheduled = false; break; default: // Bluetooth is turning ON or OFF. Ignore. break; } } } /** * Returns the status of the current pairing and cleans up the state if the pairing is done. * * @return the current pairing status. * @see BluetoothDevice#getBondState() */ public int getPairingDeviceStatus() { if (this.boundingDevice == null) { throw new IllegalStateException("No device currently bounding"); } int bondState = this.boundingDevice.getBondState(); // If the new state is not BOND_BONDING, the pairing is finished, cleans up the state. if (bondState != BluetoothDevice.BOND_BONDING) { this.boundingDevice = null; } return bondState; } /** * Gets the name of the currently pairing device. * * @return the name of the currently pairing device. */ public String getPairingDeviceName() { return getDeviceName(this.boundingDevice); } /** * Gets the name of a device. If the device name is not available, returns the device address. * * @param device the device whose name to return. * @return the name of the device or its address if the name is not available. */ public static String getDeviceName(BluetoothDevice device) { String deviceName = device.getName(); if (deviceName == null) { deviceName = device.getAddress(); } return deviceName; } /** * Returns if there's a pairing currently being done through this app. * * @return true if a pairing is in progress through this app, false otherwise. */ public boolean isPairingInProgress() { return this.boundingDevice != null; } /** * Gets the currently bounding device. * * @return the {@link #boundingDevice}. */ public BluetoothDevice getBoundingDevice() { return boundingDevice; } }