org.thaliproject.p2p.btconnectorlib.internal.AbstractBluetoothConnectivityAgent.java Source code

Java tutorial

Introduction

Here is the source code for org.thaliproject.p2p.btconnectorlib.internal.AbstractBluetoothConnectivityAgent.java

Source

/* Copyright (c) 2015-2016 Microsoft Corporation. This software is licensed under the MIT License.
 * See the license file delivered with this project for further information.
 */
package org.thaliproject.p2p.btconnectorlib.internal;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.Nullable;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import org.thaliproject.p2p.btconnectorlib.DiscoveryManagerSettings;
import org.thaliproject.p2p.btconnectorlib.PeerProperties;
import org.thaliproject.p2p.btconnectorlib.internal.bluetooth.BluetoothManager;
import org.thaliproject.p2p.btconnectorlib.internal.bluetooth.BluetoothUtils;
import org.thaliproject.p2p.btconnectorlib.utils.CommonUtils;

/**
 * An abstract base class for classes utilizing Bluetooth connectivity that need to validate the
 * identity string. For internal use only.
 */
public abstract class AbstractBluetoothConnectivityAgent implements BluetoothManager.BluetoothManagerListener {
    protected static String TAG = AbstractBluetoothConnectivityAgent.class.getName();
    protected static final String JSON_ID_PEER_NAME = "name";
    protected static final String JSON_ID_PEER_BLUETOOTH_MAC_ADDRESS = "address";
    protected final Context mContext;
    protected final BluetoothManager mBluetoothManager;
    protected String mMyPeerName = PeerProperties.NO_PEER_NAME_STRING;
    protected String mMyIdentityString = "";
    protected boolean mEmulateMarshmallow = false;

    /**
     * Constructor.
     *
     * @param context The application context.
     */
    public AbstractBluetoothConnectivityAgent(Context context) {
        this(context, BluetoothManager.getInstance(context));
    }

    /**
     * Constructor.
     *
     * @param context The application context.
     * @param bluetoothManager The bluetooth manager.
     */
    public AbstractBluetoothConnectivityAgent(Context context, BluetoothManager bluetoothManager) {
        if (context == null) {
            throw new NullPointerException("Context is null");
        }

        mContext = context;
        mBluetoothManager = bluetoothManager;
    }

    /**
     * @return The Bluetooth manager instance. Guaranteed not to be null.
     */
    public BluetoothManager getBluetoothManager() {
        return mBluetoothManager;
    }

    /**
     * Sets the peer name. Not mandatory - the functionality is 100 % even when not set.
     * The name is used in the identity string.
     *
     * @param myPeerName Our peer name.
     */
    public void setPeerName(String myPeerName) {
        if (myPeerName == null) {
            throw new NullPointerException("Peer name is null");
        }
        if (!mMyPeerName.equals(myPeerName)) {
            Log.i(TAG, "setPeerName: " + myPeerName);
            mMyPeerName = myPeerName;

            // Recreate the identity string
            mMyIdentityString = null;
            verifyIdentityString();
        }
    }

    /**
     * Releases resources.
     *
     * Should be called when getting rid of the instance. Note that after calling this method you
     * should not use the instance anymore. Instead, if needed again, you must reconstruct the
     * instance.
     */
    public void dispose() {
        // No default implementation
    }

    /**
     * Used for testing purposes.
     *
     * Turns Marshmallow emulation on/off. Basically what this does is that if enabled, will not be
     * able to resolve the Bluetooth MAC address of the device from the Bluetooth adapter.
     *
     * @param emulate If true, will turn on Marshmallow emulation.
     */
    public void setEmulateMarshmallow(boolean emulate) {
        if (mEmulateMarshmallow != emulate) {
            mEmulateMarshmallow = emulate;
            Log.i(TAG, "setEmulateMarshmallow: " + mEmulateMarshmallow);
        }
    }

    /**
     * @return The Bluetooth MAC address or null, if not available.
     */
    public String getBluetoothMacAddress() {
        DiscoveryManagerSettings settings = DiscoveryManagerSettings.getInstance(mContext);

        return verifyBluetoothMacAddress(settings);
    }

    /**
     * @param preferences The shared preferences.
     * @return The Bluetooth MAC address or null, if not available.
     */
    public String getBluetoothMacAddress(SharedPreferences preferences) {

        DiscoveryManagerSettings settings = DiscoveryManagerSettings.getInstance(mContext, preferences);

        return verifyBluetoothMacAddress(settings);
    }

    @Nullable
    private String verifyBluetoothMacAddress(DiscoveryManagerSettings settings) {
        String bluetoothMacAddress = mEmulateMarshmallow ? null : mBluetoothManager.getBluetoothMacAddress();
        if (settings != null) {
            if (bluetoothMacAddress == null) {
                bluetoothMacAddress = settings.getBluetoothMacAddress();
            } else {
                // Store the address just to be on the safe side
                settings.setBluetoothMacAddress(bluetoothMacAddress);
            }
        } else {
            Log.e(TAG, "getBluetoothMacAddress: Failed to get the discovery manager settings instance");
        }

        if (!BluetoothUtils.isValidBluetoothMacAddress(bluetoothMacAddress)) {
            bluetoothMacAddress = null;
        }
        return bluetoothMacAddress;
    }

    /**
     * Clears the identity string. This method is considered to be used for testing purposes.
     */
    public void clearIdentityString() {
        Log.i(TAG, "clearIdentityString");
        mMyIdentityString = null;
    }

    @Override
    abstract public void onBluetoothAdapterScanModeChanged(int mode);

    /**
     * Resolves the peer properties from the given identity string.
     *
     * @param identityString The identity string.
     * @param peerProperties The peer properties to contain the resolved values.
     * @return True, if all the properties contain data (not validated though). False otherwise.
     * @throws JSONException
     */
    public static boolean getPropertiesFromIdentityString(String identityString, PeerProperties peerProperties)
            throws JSONException {

        JSONObject jsonObject = new JSONObject(identityString);
        peerProperties.setName(jsonObject.getString(JSON_ID_PEER_NAME));
        peerProperties.setBluetoothMacAddress(jsonObject.getString(JSON_ID_PEER_BLUETOOTH_MAC_ADDRESS));

        return peerProperties.isValid();
    }

    /**
     * Verifies the validity of our identity string. If not yet created, will try to create it.
     * If the identity string already exists, it won't be recreated.
     *
     * @return True, if the identity string is OK (i.e. not empty). False otherwise.
     */
    protected boolean verifyIdentityString() {
        String bluetoothMacAddress = getBluetoothMacAddress();

        return verifyIdentityStringImp(bluetoothMacAddress);
    }

    /**
     * Verifies the validity of our identity string. If not yet created, will try to create it.
     * If the identity string already exists, it won't be recreated.
     *
     * @param preferences The shared preferences.
     * @return True, if the identity string is OK (i.e. not empty). False otherwise.
     */
    protected boolean verifyIdentityString(SharedPreferences preferences) {
        String bluetoothMacAddress = getBluetoothMacAddress(preferences);

        return verifyIdentityStringImp(bluetoothMacAddress);
    }

    private boolean verifyIdentityStringImp(String bluetoothMacAddress) {
        if (!CommonUtils.isNonEmptyString(mMyIdentityString)) {
            if (CommonUtils.isNonEmptyString(mMyPeerName) && !mMyPeerName.equals(PeerProperties.NO_PEER_NAME_STRING)
                    && BluetoothUtils.isValidBluetoothMacAddress(bluetoothMacAddress)) {
                try {
                    mMyIdentityString = createIdentityString(mMyPeerName, bluetoothMacAddress);
                    Log.i(TAG, "verifyIdentityString: Identity string created: " + mMyIdentityString);
                } catch (JSONException e) {
                    Log.e(TAG, "verifyIdentityString: Failed create an identity string: " + e.getMessage(), e);
                }
            } else {
                Log.d(TAG,
                        "verifyIdentityString: One or more of the following values are invalid: " + "Peer name: \""
                                + mMyPeerName + "\", Bluetooth MAC address: \"" + bluetoothMacAddress + "\"");
            }
        }

        return (mMyIdentityString != null && mMyIdentityString.length() > 0);
    }

    /**
     * Creates an identity string based on the given arguments.
     *
     * @param peerName The peer name.
     * @param bluetoothMacAddress The Bluetooth MAC address of the peer.
     * @return An identity string or null in case of a failure.
     * @throws JSONException
     */
    private String createIdentityString(String peerName, String bluetoothMacAddress) throws JSONException {

        String identityString = null;
        JSONObject jsonObject = new JSONObject();

        try {
            jsonObject.put(JSON_ID_PEER_NAME, peerName);
            jsonObject.put(JSON_ID_PEER_BLUETOOTH_MAC_ADDRESS, bluetoothMacAddress);
            identityString = jsonObject.toString();
        } catch (JSONException e) {
            Log.e(TAG, "createIdentityString: Failed to construct a JSON object (from data " + peerName + " "
                    + bluetoothMacAddress + "): " + e.getMessage(), e);
            throw e;
        }

        return identityString;
    }

    /**
     * Creates an identity string based on the given properties.
     *
     * @param peerProperties The peer properties.
     * @return An identity string or null in case of a failure.
     * @throws JSONException
     */
    public String createIdentityString(PeerProperties peerProperties) throws JSONException {
        return createIdentityString(peerProperties.getName(), peerProperties.getBluetoothMacAddress());
    }
}