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

Commit 97aaa8f0 authored by Zhihai Xu's avatar Zhihai Xu Committed by Android (Google) Code Review
Browse files

Merge "Bluetooth MAP profile - sms and mms support initial check-in" into klp-dev

parents f910d320 fe3807a5
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -95,6 +95,7 @@ LOCAL_SRC_FILES += \
	core/java/android/bluetooth/IBluetoothManager.aidl \
	core/java/android/bluetooth/IBluetoothManager.aidl \
	core/java/android/bluetooth/IBluetoothManagerCallback.aidl \
	core/java/android/bluetooth/IBluetoothManagerCallback.aidl \
	core/java/android/bluetooth/IBluetoothPbap.aidl \
	core/java/android/bluetooth/IBluetoothPbap.aidl \
	core/java/android/bluetooth/IBluetoothMap.aidl \
	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
	core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
	core/java/android/bluetooth/IBluetoothGatt.aidl \
	core/java/android/bluetooth/IBluetoothGatt.aidl \
	core/java/android/bluetooth/IBluetoothGattCallback.aidl \
	core/java/android/bluetooth/IBluetoothGattCallback.aidl \
+3 −0
Original line number Original line Diff line number Diff line
@@ -343,6 +343,9 @@ public final class BluetoothDevice implements Parcelable {
    /**@hide*/
    /**@hide*/
    public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;
    public static final int REQUEST_TYPE_PHONEBOOK_ACCESS = 2;


    /**@hide*/
    public static final int REQUEST_TYPE_MESSAGE_ACCESS = 3;

    /**
    /**
     * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
     * Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intents,
     * Contains package name to return reply intent to.
     * Contains package name to return reply intent to.
+300 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2008 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.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.ServiceManager;
import android.util.Log;

/**
 * This class provides the APIs to control the Bluetooth MAP
 * Profile.
 *@hide
 */
public class BluetoothMap {

    private static final String TAG = "BluetoothMap";
    private static final boolean DBG = true;
    private static final boolean VDBG = false;

    /** int extra for MAP_STATE_CHANGED_ACTION */
    public static final String MAP_STATE =
        "android.bluetooth.map.intent.MAP_STATE";
    /** int extra for MAP_STATE_CHANGED_ACTION */
    public static final String MAP_PREVIOUS_STATE =
        "android.bluetooth.map.intent.MAP_PREVIOUS_STATE";

    /** Indicates the state of a Map connection state has changed.
     *  This intent will always contain MAP_STATE, MAP_PREVIOUS_STATE and
     *  BluetoothIntent.ADDRESS extras.
     */
    public static final String MAP_STATE_CHANGED_ACTION =
        "android.bluetooth.map.intent.action.MAP_STATE_CHANGED";

    private IBluetoothMap mService;
    private final Context mContext;
    private ServiceListener mServiceListener;
    private BluetoothAdapter mAdapter;

    /** There was an error trying to obtain the state */
    public static final int STATE_ERROR        = -1;
    /** No client currently connected */
    public static final int STATE_DISCONNECTED = 0;
    /** Connection attempt in progress */
    public static final int STATE_CONNECTING   = 1;
    /** Client is currently connected */
    public static final int STATE_CONNECTED    = 2;

    public static final int RESULT_FAILURE = 0;
    public static final int RESULT_SUCCESS = 1;
    /** Connection canceled before completion. */
    public static final int RESULT_CANCELED = 2;

    /**
     * An interface for notifying Bluetooth PCE IPC clients when they have
     * been connected to the BluetoothMap service.
     */
    public interface ServiceListener {
        /**
         * Called to notify the client when this proxy object has been
         * connected to the BluetoothMap service. Clients must wait for
         * this callback before making IPC calls on the BluetoothMap
         * service.
         */
        public void onServiceConnected(BluetoothMap proxy);

        /**
         * Called to notify the client that this proxy object has been
         * disconnected from the BluetoothMap service. Clients must not
         * make IPC calls on the BluetoothMap service after this callback.
         * This callback will currently only occur if the application hosting
         * the BluetoothMap service, but may be called more often in future.
         */
        public void onServiceDisconnected();
    }

    final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
            new IBluetoothStateChangeCallback.Stub() {
                public void onBluetoothStateChange(boolean up) {
                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
                    if (!up) {
                        if (VDBG) Log.d(TAG,"Unbinding service...");
                        synchronized (mConnection) {
                            try {
                                mService = null;
                                mContext.unbindService(mConnection);
                            } catch (Exception re) {
                                Log.e(TAG,"",re);
                            }
                        }
                    } else {
                        synchronized (mConnection) {
                            try {
                                if (mService == null) {
                                    if (VDBG) Log.d(TAG,"Binding service...");
                                    if (!mContext.bindService(
                                                        new Intent(IBluetoothMap.class.getName()),
                                                        mConnection, 0)) {
                                        Log.e(TAG, "Could not bind to Bluetooth MAP Service");
                                    }
                                }
                            } catch (Exception re) {
                                Log.e(TAG,"",re);
                            }
                        }
                    }
                }
        };

    /**
     * Create a BluetoothMap proxy object.
     */
    public BluetoothMap(Context context, ServiceListener l) {
        mContext = context;
        mServiceListener = l;
        mAdapter = BluetoothAdapter.getDefaultAdapter();
        IBluetoothManager mgr = mAdapter.getBluetoothManager();
        if (mgr != null) {
            try {
                mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
            } catch (RemoteException e) {
                Log.e(TAG,"",e);
            }
        }
        if (!context.bindService(new Intent(IBluetoothMap.class.getName()), mConnection, 0)) {
            Log.e(TAG, "Could not bind to Bluetooth Map Service");
        }
    }

    protected void finalize() throws Throwable {
        try {
            close();
        } finally {
            super.finalize();
        }
    }

    /**
     * Close the connection to the backing service.
     * Other public functions of BluetoothMap will return default error
     * results once close() has been called. Multiple invocations of close()
     * are ok.
     */
    public synchronized void close() {
        IBluetoothManager mgr = mAdapter.getBluetoothManager();
        if (mgr != null) {
            try {
                mgr.unregisterStateChangeCallback(mBluetoothStateChangeCallback);
            } catch (Exception e) {
                Log.e(TAG,"",e);
            }
        }

        synchronized (mConnection) {
            if (mService != null) {
                try {
                    mService = null;
                    mContext.unbindService(mConnection);
                    mConnection = null;
                } catch (Exception re) {
                    Log.e(TAG,"",re);
                }
            }
        }
        mServiceListener = null;
    }

    /**
     * Get the current state of the BluetoothMap service.
     * @return One of the STATE_ return codes, or STATE_ERROR if this proxy
     *         object is currently not connected to the Map service.
     */
    public int getState() {
        if (VDBG) log("getState()");
        if (mService != null) {
            try {
                return mService.getState();
            } catch (RemoteException e) {Log.e(TAG, e.toString());}
        } else {
            Log.w(TAG, "Proxy not attached to service");
            if (DBG) log(Log.getStackTraceString(new Throwable()));
        }
        return BluetoothMap.STATE_ERROR;
    }

    /**
     * Get the currently connected remote Bluetooth device (PCE).
     * @return The remote Bluetooth device, or null if not in connected or
     *         connecting state, or if this proxy object is not connected to
     *         the Map service.
     */
    public BluetoothDevice getClient() {
        if (VDBG) log("getClient()");
        if (mService != null) {
            try {
                return mService.getClient();
            } catch (RemoteException e) {Log.e(TAG, e.toString());}
        } else {
            Log.w(TAG, "Proxy not attached to service");
            if (DBG) log(Log.getStackTraceString(new Throwable()));
        }
        return null;
    }

    /**
     * Returns true if the specified Bluetooth device is connected (does not
     * include connecting). Returns false if not connected, or if this proxy
     * object is not currently connected to the Map service.
     */
    public boolean isConnected(BluetoothDevice device) {
        if (VDBG) log("isConnected(" + device + ")");
        if (mService != null) {
            try {
                return mService.isConnected(device);
            } catch (RemoteException e) {Log.e(TAG, e.toString());}
        } else {
            Log.w(TAG, "Proxy not attached to service");
            if (DBG) log(Log.getStackTraceString(new Throwable()));
        }
        return false;
    }

    /**
     * Disconnects the current Map Client. Currently this call blocks,
     * it may soon be made asynchronous. Returns false if this proxy object is
     * not currently connected to the Map service.
     */
    public boolean disconnect() {
        if (DBG) log("disconnect()");
        if (mService != null) {
            try {
                mService.disconnect();
                return true;
            } catch (RemoteException e) {Log.e(TAG, e.toString());}
        } else {
            Log.w(TAG, "Proxy not attached to service");
            if (DBG) log(Log.getStackTraceString(new Throwable()));
        }
        return false;
    }

    /**
     * Check class bits for possible Map support.
     * This is a simple heuristic that tries to guess if a device with the
     * given class bits might support Map. It is not accurate for all
     * devices. It tries to err on the side of false positives.
     * @return True if this device might support Map.
     */
    public static boolean doesClassMatchSink(BluetoothClass btClass) {
        // TODO optimize the rule
        switch (btClass.getDeviceClass()) {
        case BluetoothClass.Device.COMPUTER_DESKTOP:
        case BluetoothClass.Device.COMPUTER_LAPTOP:
        case BluetoothClass.Device.COMPUTER_SERVER:
        case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
            return true;
        default:
            return false;
        }
    }

    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className, IBinder service) {
            if (DBG) log("Proxy object connected");
            mService = IBluetoothMap.Stub.asInterface(service);
            if (mServiceListener != null) {
                mServiceListener.onServiceConnected(BluetoothMap.this);
            }
        }
        public void onServiceDisconnected(ComponentName className) {
            if (DBG) log("Proxy object disconnected");
            mService = null;
            if (mServiceListener != null) {
                mServiceListener.onServiceDisconnected();
            }
        }
    };

    private static void log(String msg) {
        Log.d(TAG, msg);
    }
}
+6 −0
Original line number Original line Diff line number Diff line
@@ -97,6 +97,12 @@ public interface BluetoothProfile {
     */
     */
    static public final int GATT_SERVER = 8;
    static public final int GATT_SERVER = 8;


    /**
     * MAP Profile
     * @hide
     */
    public static final int MAP = 9;

    /**
    /**
     * Default priority for devices that we try to auto-connect to and
     * Default priority for devices that we try to auto-connect to and
     * and allow incoming connections for the profile
     * and allow incoming connections for the profile
+12 −1
Original line number Original line Diff line number Diff line
@@ -64,10 +64,14 @@ public final class BluetoothUuid {
            ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
            ParcelUuid.fromString("0000000f-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid PBAP_PSE =
    public static final ParcelUuid PBAP_PSE =
            ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
            ParcelUuid.fromString("0000112f-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid MAP =
            ParcelUuid.fromString("00001132-0000-1000-8000-00805F9B34FB");
    public static final ParcelUuid MNS =
            ParcelUuid.fromString("00001133-0000-1000-8000-00805F9B34FB");


    public static final ParcelUuid[] RESERVED_UUIDS = {
    public static final ParcelUuid[] RESERVED_UUIDS = {
        AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
        AudioSink, AudioSource, AdvAudioDist, HSP, Handsfree, AvrcpController, AvrcpTarget,
        ObexObjectPush, PANU, NAP};
        ObexObjectPush, PANU, NAP, MAP, MNS};


    public static boolean isAudioSource(ParcelUuid uuid) {
    public static boolean isAudioSource(ParcelUuid uuid) {
        return uuid.equals(AudioSource);
        return uuid.equals(AudioSource);
@@ -112,6 +116,13 @@ public final class BluetoothUuid {
    public static boolean isBnep(ParcelUuid uuid) {
    public static boolean isBnep(ParcelUuid uuid) {
        return uuid.equals(BNEP);
        return uuid.equals(BNEP);
    }
    }
    public static boolean isMap(ParcelUuid uuid) {
        return uuid.equals(MAP);
    }
    public static boolean isMns(ParcelUuid uuid) {
        return uuid.equals(MNS);
    }

    /**
    /**
     * Returns true if ParcelUuid is present in uuidArray
     * Returns true if ParcelUuid is present in uuidArray
     *
     *
Loading