Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5623b074 authored by Jaikumar Ganesh's avatar Jaikumar Ganesh Committed by Android (Google) Code Review
Browse files

Merge "Bluetooth Health APIs"

parents f25a8ce4 fb658c72
Loading
Loading
Loading
Loading
+43 −32
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package android.bluetooth;

import android.annotation.SdkConstant;
import android.content.Context;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
@@ -67,9 +66,6 @@ public final class BluetoothHealth implements BluetoothProfile {
     */
    public static final int CHANNEL_TYPE_ANY = 12;

    private final ArrayList<BluetoothHealthAppConfiguration> mAppConfigs =
        new ArrayList<BluetoothHealthAppConfiguration>();

    /**
     * Register an application configuration that acts as a Health SINK.
     * This is the configuration that will be used to communicate with health devices
@@ -86,7 +82,7 @@ public final class BluetoothHealth implements BluetoothProfile {
     * @return If true, callback will be called.
     */
    public boolean registerSinkAppConfiguration(String name, int dataType,
            IBluetoothHealthCallback callback) {
            BluetoothHealthCallback callback) {
        if (!isEnabled() || name == null) return false;

        if (DBG) log("registerSinkApplication(" + name + ":" + dataType + ")");
@@ -111,18 +107,18 @@ public final class BluetoothHealth implements BluetoothProfile {
     * @hide
     */
    public boolean registerAppConfiguration(String name, int dataType, int role,
            int channelType, IBluetoothHealthCallback callback) {
            int channelType, BluetoothHealthCallback callback) {
        boolean result = false;
        if (!isEnabled() || !checkAppParam(name, role, channelType, callback)) return result;

        if (DBG) log("registerApplication(" + name + ":" + dataType + ")");
        BluetoothHealthCallbackWrapper wrapper = new BluetoothHealthCallbackWrapper(callback);
        BluetoothHealthAppConfiguration config =
                new BluetoothHealthAppConfiguration(name, dataType, role, channelType,
                callback);
                new BluetoothHealthAppConfiguration(name, dataType, role, channelType);

        if (mService != null) {
            try {
                result = mService.registerAppConfiguration(config);
                result = mService.registerAppConfiguration(config, wrapper);
            } catch (RemoteException e) {
                Log.e(TAG, e.toString());
            }
@@ -130,8 +126,6 @@ public final class BluetoothHealth implements BluetoothProfile {
            Log.w(TAG, "Proxy not attached to service");
            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
        }

        if (result) mAppConfigs.add(config);
        return result;
    }

@@ -147,7 +141,7 @@ public final class BluetoothHealth implements BluetoothProfile {
     */
    public boolean unregisterAppConfiguration(BluetoothHealthAppConfiguration config) {
        boolean result = false;
        if (mService != null && isEnabled() && isValidAppConfig(config)) {
        if (mService != null && isEnabled() && config != null) {
            try {
                result = mService.unregisterAppConfiguration(config);
            } catch (RemoteException e) {
@@ -157,26 +151,26 @@ public final class BluetoothHealth implements BluetoothProfile {
            Log.w(TAG, "Proxy not attached to service");
            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
        }
        if (result) mAppConfigs.remove(config);

        return result;
    }

    /**
     * Connect to a health device which has the {@link #SOURCE_ROLE}.
     * This is an asynchrnous call. If this function returns true, the callback
     * This is an asynchronous call. If this function returns true, the callback
     * associated with the application configuration will be called.
     *
     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
     *
     * @param device The remote Bluetooth device.
     * @param config The application configuration which has been registed using
     *        {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
     * @param config The application configuration which has been registered using
     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
     * @return If true, the callback associated with the application config will be called.
     */
    public boolean connectChannelToSource(BluetoothDevice device,
            BluetoothHealthAppConfiguration config) {
        if (mService != null && isEnabled() && isValidDevice(device) &&
                isValidAppConfig(config)) {
                config != null) {
            try {
                return mService.connectChannelToSource(device, config);
            } catch (RemoteException e) {
@@ -197,15 +191,15 @@ public final class BluetoothHealth implements BluetoothProfile {
     *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
     *
     * @param device The remote Bluetooth device.
     * @param config The application configuration which has been registed using
     *        {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
     * @param config The application configuration which has been registered using
     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
     * @return If true, the callback associated with the application config will be called.
     * @hide
     */
    public boolean connectChannelToSink(BluetoothDevice device,
            BluetoothHealthAppConfiguration config, int channelType) {
        if (mService != null && isEnabled() && isValidDevice(device) &&
                isValidAppConfig(config)) {
                config != null) {
            try {
                return mService.connectChannelToSink(device, config, channelType);
            } catch (RemoteException e) {
@@ -226,8 +220,8 @@ public final class BluetoothHealth implements BluetoothProfile {
     *<p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
     *
     * @param device The remote Bluetooth device.
     * @param config The application configuration which has been registed using
     *        {@link #registerSinkAppConfiguration(String, int, IBluetoothHealthCallback) }
     * @param config The application configuration which has been registered using
     *        {@link #registerSinkAppConfiguration(String, int, BluetoothHealthCallback) }
     * @param fd The file descriptor that was associated with the channel.
     * @return If true, the callback associated with the application config will be called.
     * @hide
@@ -235,7 +229,7 @@ public final class BluetoothHealth implements BluetoothProfile {
    public boolean disconnectChannel(BluetoothDevice device,
            BluetoothHealthAppConfiguration config, ParcelFileDescriptor fd) {
        if (mService != null && isEnabled() && isValidDevice(device) &&
                isValidAppConfig(config)) {
                config != null) {
            try {
                return mService.disconnectChannel(device, config, fd);
            } catch (RemoteException e) {
@@ -262,7 +256,7 @@ public final class BluetoothHealth implements BluetoothProfile {
    public ParcelFileDescriptor getMainChannelFd(BluetoothDevice device,
            BluetoothHealthAppConfiguration config) {
        if (mService != null && isEnabled() && isValidDevice(device) &&
                isValidAppConfig(config)) {
                config != null) {
            try {
                return mService.getMainChannelFd(device, config);
            } catch (RemoteException e) {
@@ -290,6 +284,7 @@ public final class BluetoothHealth implements BluetoothProfile {
     *               {@link #STATE_CONNECTED}, {@link #STATE_CONNECTING},
     *               {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING}
     */
    @Override
    public int getConnectionState(BluetoothDevice device) {
        if (mService != null && isEnabled() && isValidDevice(device)) {
            try {
@@ -317,6 +312,7 @@ public final class BluetoothHealth implements BluetoothProfile {
     * local adapter.
     * @return List of devices. The list will be empty on error.
     */
    @Override
    public List<BluetoothDevice> getConnectedDevices() {
        if (mService != null && isEnabled()) {
            try {
@@ -348,6 +344,7 @@ public final class BluetoothHealth implements BluetoothProfile {
     *              {@link #STATE_DISCONNECTED}, {@link #STATE_DISCONNECTING},
     * @return List of devices. The list will be empty on error.
     */
    @Override
    public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
        if (mService != null && isEnabled()) {
            try {
@@ -361,6 +358,27 @@ public final class BluetoothHealth implements BluetoothProfile {
        return new ArrayList<BluetoothDevice>();
    }

    private static class BluetoothHealthCallbackWrapper extends IBluetoothHealthCallback.Stub {
        private BluetoothHealthCallback mCallback;

        public BluetoothHealthCallbackWrapper(BluetoothHealthCallback callback) {
            mCallback = callback;
        }

        @Override
        public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
                                                         int status) {
            mCallback.onHealthAppConfigurationStatusChange(config, status);
        }

        @Override
        public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
                                       BluetoothDevice device, int prevState, int newState,
                                       ParcelFileDescriptor fd) {
            mCallback.onHealthChannelStateChange(config, device, prevState, newState, fd);
        }
    }

     /** Health Channel Connection State - Disconnected */
    public static final int STATE_CHANNEL_DISCONNECTED  = 0;
    /** Health Channel Connection State - Connecting */
@@ -379,7 +397,6 @@ public final class BluetoothHealth implements BluetoothProfile {
    /** Health App Configuration un-registration failure */
    public static final int APPLICATION_UNREGISTRATION_FAILURE = 3;

    private Context mContext;
    private ServiceListener mServiceListener;
    private IBluetooth mService;
    BluetoothAdapter mAdapter;
@@ -420,14 +437,8 @@ public final class BluetoothHealth implements BluetoothProfile {
        return false;
    }

    private boolean isValidAppConfig(BluetoothHealthAppConfiguration config) {
        if (!mAppConfigs.isEmpty() && mAppConfigs.contains(config)) return true;
        log("Not a valid config: " + config);
        return false;
    }

    private boolean checkAppParam(String name, int role, int channelType,
            IBluetoothHealthCallback callback) {
            BluetoothHealthCallback callback) {
        if (name == null || (role != SOURCE_ROLE && role != SINK_ROLE) ||
                (channelType != CHANNEL_TYPE_RELIABLE &&
                channelType != CHANNEL_TYPE_STREAMING &&
+16 −29
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@

package android.bluetooth;

import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;

@@ -34,21 +33,18 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
    private final int mDataType;
    private final int mRole;
    private final int mChannelType;
    private final IBluetoothHealthCallback mCallback;

    /**
     * Constructor to register the SINK role
     *
     * @param name Friendly name associated with the application configuration
     * @param dataType Data Type of the remote Bluetooth Health device
     * @param callback Callback associated with the application configuration.
     */
    BluetoothHealthAppConfiguration(String name, int dataType, IBluetoothHealthCallback callback) {
    BluetoothHealthAppConfiguration(String name, int dataType) {
        mName = name;
        mDataType = dataType;
        mRole = BluetoothHealth.SINK_ROLE;
        mChannelType = BluetoothHealth.CHANNEL_TYPE_ANY;
        mCallback = callback;
    }

    /**
@@ -56,17 +52,15 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
     *
     * @param name Friendly name associated with the application configuration
     * @param dataType Data Type of the remote Bluetooth Health device
     * @param role {@link BluetoothHealth.SOURCE_ROLE} or
     *                     {@link BluetoothHealth.SINK_ROLE}
     * @param callback Callback associated with the application configuration.
     * @param role {@link BluetoothHealth#SOURCE_ROLE} or
     *                     {@link BluetoothHealth#SINK_ROLE}
     */
    BluetoothHealthAppConfiguration(String name, int dataType, int role, int channelType,
            IBluetoothHealthCallback callback) {
    BluetoothHealthAppConfiguration(String name, int dataType, int role, int
        channelType) {
        mName = name;
        mDataType = dataType;
        mRole = role;
        mChannelType = channelType;
        mCallback = callback;
    }

    @Override
@@ -77,8 +71,7 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
            return mName.equals(config.getName()) &&
                    mDataType == config.getDataType() &&
                    mRole == config.getRole() &&
                    mChannelType == config.getChannelType() &&
                    mCallback.equals(config.getCallback());
                    mChannelType == config.getChannelType();
        }
        return false;
    }
@@ -90,7 +83,6 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
        result = 31 * result + mDataType;
        result = 31 * result + mRole;
        result = 31 * result + mChannelType;
        result = 31 * result + (mCallback != null ? mCallback.hashCode() : 0);
        return result;
    }

@@ -98,9 +90,10 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
    public String toString() {
        return "BluetoothHealthAppConfiguration [mName = " + mName +
            ",mDataType = " + mDataType + ", mRole = " + mRole + ",mChannelType = " +
            mChannelType +  ",callback=" + mCallback +"]";
            mChannelType + "]";
    }

    @Override
    public int describeContents() {
        return 0;
    }
@@ -144,37 +137,31 @@ public final class BluetoothHealthAppConfiguration implements Parcelable {
        return mChannelType;
    }

    /**
     * Return the callback associated with this application configuration.
     *
     * @return IBluetoothHealthCallback
     */
    public IBluetoothHealthCallback getCallback() {
        return mCallback;
    }

    public static final Parcelable.Creator<BluetoothHealthAppConfiguration> CREATOR =
        new Parcelable.Creator<BluetoothHealthAppConfiguration>() {
        @Override
        public BluetoothHealthAppConfiguration createFromParcel(Parcel in) {
            String name = in.readString();
            int type = in.readInt();
            int role = in.readInt();
            int channelType = in.readInt();
            IBluetoothHealthCallback callback =
                IBluetoothHealthCallback.Stub.asInterface(in.readStrongBinder());
            return new BluetoothHealthAppConfiguration(name, type, role, channelType,
                    callback);
            return new BluetoothHealthAppConfiguration(name, type, role,
                channelType);
        }

        @Override
        public BluetoothHealthAppConfiguration[] newArray(int size) {
            return new BluetoothHealthAppConfiguration[size];
        }
    };

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeString(mName);
        out.writeInt(mDataType);
        out.writeInt(mRole);
        out.writeInt(mChannelType);
        out.writeStrongInterface(mCallback);
    }


}
+42 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 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 android.bluetooth;

import android.os.ParcelFileDescriptor;
import android.util.Log;

/**
 * This class is used for all the {@link BluetoothHealth} callbacks.
 * @hide
 */
public abstract class BluetoothHealthCallback {

    private static final String TAG = "BluetoothHealthCallback";

    public void onHealthAppConfigurationStatusChange(BluetoothHealthAppConfiguration config,
                                                int status) {
        Log.d(TAG, "onHealthAppConfigurationStatusChange: " + config + " Status:" + status);
    }

    public void onHealthChannelStateChange(BluetoothHealthAppConfiguration config,
                                    BluetoothDevice device, int prevState, int newState,
                                    ParcelFileDescriptor fd) {
        Log.d(TAG, "onHealthChannelStateChange: " + config + " Device:" + device +
            "PrevState:" + prevState + "NewState:" + newState + "FileDescriptor:" + fd);
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.bluetooth;

import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothHealthCallback;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHealthAppConfiguration;
import android.os.ParcelUuid;
@@ -102,7 +103,8 @@ interface IBluetooth
    boolean disconnectPanDevice(in BluetoothDevice device);

    // HDP profile APIs
    boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config);
    boolean registerAppConfiguration(in BluetoothHealthAppConfiguration config,
        in IBluetoothHealthCallback callback);
    boolean unregisterAppConfiguration(in BluetoothHealthAppConfiguration config);
    boolean connectChannelToSource(in BluetoothDevice device, in BluetoothHealthAppConfiguration config);
    boolean connectChannelToSink(in BluetoothDevice device, in BluetoothHealthAppConfiguration config,
+25 −24
Original line number Diff line number Diff line
@@ -20,15 +20,12 @@ import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothHealth;
import android.bluetooth.BluetoothHealthAppConfiguration;
import android.bluetooth.BluetoothHealth;
import android.bluetooth.BluetoothInputDevice;
import android.bluetooth.IBluetoothHealthCallback;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Log;

import java.util.ArrayList;
@@ -36,10 +33,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * This handles all the operations on the Bluetooth Health profile.
 * All functions are called by BluetoothService, as Bluetooth Service
@@ -58,6 +51,7 @@ final class BluetoothHealthProfileHandler {
    private ArrayList<HealthChannel> mHealthChannels;
    private HashMap <BluetoothHealthAppConfiguration, String> mHealthAppConfigs;
    private HashMap <BluetoothDevice, Integer> mHealthDevices;
    private HashMap <BluetoothHealthAppConfiguration, IBluetoothHealthCallback> mCallbacks;

    private static final int MESSAGE_REGISTER_APPLICATION = 0;
    private static final int MESSAGE_UNREGISTER_APPLICATION = 1;
@@ -103,6 +97,7 @@ final class BluetoothHealthProfileHandler {
                }

                if (path == null) {
                    mCallbacks.remove(registerApp);
                    callHealthApplicationStatusCallback(registerApp,
                            BluetoothHealth.APPLICATION_REGISTRATION_FAILURE);
                } else {
@@ -118,6 +113,7 @@ final class BluetoothHealthProfileHandler {
                boolean result = mBluetoothService.unregisterHealthApplicationNative(
                        mHealthAppConfigs.get(unregisterApp));
                if (result) {
                    mCallbacks.remove(unregisterApp);
                    callHealthApplicationStatusCallback(unregisterApp,
                            BluetoothHealth.APPLICATION_UNREGISTRATION_SUCCESS);
                } else {
@@ -149,6 +145,7 @@ final class BluetoothHealthProfileHandler {
        mHealthAppConfigs = new HashMap<BluetoothHealthAppConfiguration, String>();
        mHealthChannels = new ArrayList<HealthChannel>();
        mHealthDevices = new HashMap<BluetoothDevice, Integer>();
        mCallbacks = new HashMap<BluetoothHealthAppConfiguration, IBluetoothHealthCallback>();
    }

    static synchronized BluetoothHealthProfileHandler getInstance(Context context,
@@ -157,10 +154,12 @@ final class BluetoothHealthProfileHandler {
        return sInstance;
    }

    boolean registerAppConfiguration(BluetoothHealthAppConfiguration config) {
    boolean registerAppConfiguration(BluetoothHealthAppConfiguration config,
                                     IBluetoothHealthCallback callback) {
        Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_APPLICATION);
        msg.obj = config;
        mHandler.sendMessage(msg);
        mCallbacks.put(config, callback);
        return true;
    }

@@ -442,11 +441,11 @@ final class BluetoothHealthProfileHandler {

        debugLog("Health Device Callback: " + device + " State Change: "
                + prevState + "->" + state);
        IBluetoothHealthCallback callback = mCallbacks.get(config);
        if (callback != null) {
            try {
            config.getCallback().onHealthChannelStateChange(config, device, prevState,
                    state, fd);
        } catch (RemoteException e) {
            errorLog("Error while making health channel state change callback: " + e);
                callback.onHealthChannelStateChange(config, device, prevState, state, fd);
            } catch (RemoteException e) {}
        }
    }

@@ -454,10 +453,11 @@ final class BluetoothHealthProfileHandler {
            BluetoothHealthAppConfiguration config, int status) {
        debugLog("Health Device Application: " + config + " State Change: status:"
                + status);
        IBluetoothHealthCallback callback = mCallbacks.get(config);
        if (callback != null) {
            try {
            config.getCallback().onHealthAppConfigurationStatusChange(config, status);
        } catch (RemoteException e) {
            errorLog("Error while making health app registration state change callback: " + e);
                callback.onHealthAppConfigurationStatusChange(config, status);
            } catch (RemoteException e) {}
        }
    }

@@ -526,19 +526,19 @@ final class BluetoothHealthProfileHandler {
            List<HealthChannel> chan;
            switch (currDeviceState) {
                case BluetoothHealth.STATE_DISCONNECTED:
                    updateAndsendIntent(device, currDeviceState, newDeviceState);
                    updateAndSendIntent(device, currDeviceState, newDeviceState);
                    break;
                case BluetoothHealth.STATE_CONNECTING:
                    // Channel got connected.
                    if (newDeviceState == BluetoothHealth.STATE_CONNECTED) {
                        updateAndsendIntent(device, currDeviceState, newDeviceState);
                        updateAndSendIntent(device, currDeviceState, newDeviceState);
                    } else {
                        // Channel got disconnected
                        chan = findChannelByStates(device, new int [] {
                                    BluetoothHealth.STATE_CHANNEL_CONNECTING,
                                    BluetoothHealth.STATE_CHANNEL_DISCONNECTING});
                        if (chan.isEmpty()) {
                            updateAndsendIntent(device, currDeviceState, newDeviceState);
                            updateAndSendIntent(device, currDeviceState, newDeviceState);
                        }
                    }
                    break;
@@ -548,22 +548,23 @@ final class BluetoothHealthProfileHandler {
                                BluetoothHealth.STATE_CHANNEL_CONNECTING,
                                BluetoothHealth.STATE_CHANNEL_CONNECTED});
                    if (chan.isEmpty()) {
                        updateAndsendIntent(device, currDeviceState, newDeviceState);
                        updateAndSendIntent(device, currDeviceState, newDeviceState);
                    }
                    break;
                case BluetoothHealth.STATE_DISCONNECTING:
                    // Channel got disconnected.
                    chan = findChannelByStates(device, new int [] {
                                BluetoothHealth.STATE_CHANNEL_CONNECTING,
                                BluetoothHealth.STATE_CHANNEL_DISCONNECTING});
                    if (chan.isEmpty()) {
                        updateAndsendIntent(device, currDeviceState, newDeviceState);
                        updateAndSendIntent(device, currDeviceState, newDeviceState);
                    }
                    break;
            }
        }
    }

    private void updateAndsendIntent(BluetoothDevice device, int prevDeviceState,
    private void updateAndSendIntent(BluetoothDevice device, int prevDeviceState,
            int newDeviceState) {
        mHealthDevices.put(device, newDeviceState);
        mBluetoothService.sendConnectionStateChange(device, prevDeviceState, newDeviceState);
Loading