MAP MCE
am: 631768d814
Change-Id: I155fd0e8b44539bf79cec2c6ddb2a4d71b0c23d9
This commit is contained in:
@@ -117,9 +117,10 @@ LOCAL_SRC_FILES += \
|
|||||||
core/java/android/bluetooth/IBluetoothPan.aidl \
|
core/java/android/bluetooth/IBluetoothPan.aidl \
|
||||||
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/IBluetoothMap.aidl \
|
||||||
|
core/java/android/bluetooth/IBluetoothMapClient.aidl \
|
||||||
core/java/android/bluetooth/IBluetoothPbap.aidl \
|
core/java/android/bluetooth/IBluetoothPbap.aidl \
|
||||||
core/java/android/bluetooth/IBluetoothPbapClient.aidl \
|
core/java/android/bluetooth/IBluetoothPbapClient.aidl \
|
||||||
core/java/android/bluetooth/IBluetoothMap.aidl \
|
|
||||||
core/java/android/bluetooth/IBluetoothSap.aidl \
|
core/java/android/bluetooth/IBluetoothSap.aidl \
|
||||||
core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
|
core/java/android/bluetooth/IBluetoothStateChangeCallback.aidl \
|
||||||
core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \
|
core/java/android/bluetooth/IBluetoothHeadsetClient.aidl \
|
||||||
|
|||||||
@@ -1952,6 +1952,9 @@ public final class BluetoothAdapter {
|
|||||||
} else if (profile == BluetoothProfile.PBAP_CLIENT) {
|
} else if (profile == BluetoothProfile.PBAP_CLIENT) {
|
||||||
BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener);
|
BluetoothPbapClient pbapClient = new BluetoothPbapClient(context, listener);
|
||||||
return true;
|
return true;
|
||||||
|
} else if (profile == BluetoothProfile.MAP_CLIENT) {
|
||||||
|
BluetoothMapClient mapClient = new BluetoothMapClient(context, listener);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2024,6 +2027,10 @@ public final class BluetoothAdapter {
|
|||||||
BluetoothPbapClient pbapClient = (BluetoothPbapClient)proxy;
|
BluetoothPbapClient pbapClient = (BluetoothPbapClient)proxy;
|
||||||
pbapClient.close();
|
pbapClient.close();
|
||||||
break;
|
break;
|
||||||
|
case BluetoothProfile.MAP_CLIENT:
|
||||||
|
BluetoothMapClient mapClient = (BluetoothMapClient)proxy;
|
||||||
|
mapClient.close();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
415
core/java/android/bluetooth/BluetoothMapClient.java
Normal file
415
core/java/android/bluetooth/BluetoothMapClient.java
Normal file
@@ -0,0 +1,415 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.app.PendingIntent;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides the APIs to control the Bluetooth MAP MCE Profile.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public final class BluetoothMapClient implements BluetoothProfile {
|
||||||
|
|
||||||
|
private static final String TAG = "BluetoothMapClient";
|
||||||
|
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
|
||||||
|
private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);
|
||||||
|
|
||||||
|
public static final String ACTION_CONNECTION_STATE_CHANGED =
|
||||||
|
"android.bluetooth.mapmce.profile.action.CONNECTION_STATE_CHANGED";
|
||||||
|
public static final String ACTION_MESSAGE_RECEIVED =
|
||||||
|
"android.bluetooth.mapmce.profile.action.MESSAGE_RECEIVED";
|
||||||
|
/* Actions to be used for pending intents */
|
||||||
|
public static final String ACTION_MESSAGE_SENT_SUCCESSFULLY =
|
||||||
|
"android.bluetooth.mapmce.profile.action.MESSAGE_SENT_SUCCESSFULLY";
|
||||||
|
public static final String ACTION_MESSAGE_DELIVERED_SUCCESSFULLY =
|
||||||
|
"android.bluetooth.mapmce.profile.action.MESSAGE_DELIVERED_SUCCESSFULLY";
|
||||||
|
|
||||||
|
private IBluetoothMapClient 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;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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...");
|
||||||
|
doBind();
|
||||||
|
}
|
||||||
|
} catch (Exception re) {
|
||||||
|
Log.e(TAG, "", re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a BluetoothMapClient proxy object.
|
||||||
|
*/
|
||||||
|
/*package*/ BluetoothMapClient(Context context, ServiceListener l) {
|
||||||
|
if (DBG) Log.d(TAG, "Create BluetoothMapClient proxy object");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doBind();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean doBind() {
|
||||||
|
Intent intent = new Intent(IBluetoothMapClient.class.getName());
|
||||||
|
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
|
||||||
|
intent.setComponent(comp);
|
||||||
|
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
|
||||||
|
android.os.Process.myUserHandle())) {
|
||||||
|
Log.e(TAG, "Could not bind to Bluetooth MAP MCE Service with " + intent);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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);
|
||||||
|
} catch (Exception re) {
|
||||||
|
Log.e(TAG, "", re);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mServiceListener = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the specified Bluetooth device is connected.
|
||||||
|
* 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.d(TAG, "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.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate connection. Initiation of outgoing connections is not
|
||||||
|
* supported for MAP server.
|
||||||
|
*/
|
||||||
|
public boolean connect(BluetoothDevice device) {
|
||||||
|
if (DBG) Log.d(TAG, "connect(" + device + ")" + "for MAPS MCE");
|
||||||
|
if (mService != null) {
|
||||||
|
try {
|
||||||
|
return mService.connect(device);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, e.toString());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Proxy not attached to service");
|
||||||
|
if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiate disconnect.
|
||||||
|
*
|
||||||
|
* @param device Remote Bluetooth Device
|
||||||
|
* @return false on error, true otherwise
|
||||||
|
*/
|
||||||
|
public boolean disconnect(BluetoothDevice device) {
|
||||||
|
if (DBG) Log.d(TAG, "disconnect(" + device + ")");
|
||||||
|
if (mService != null && isEnabled() &&
|
||||||
|
isValidDevice(device)) {
|
||||||
|
try {
|
||||||
|
return mService.disconnect(device);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of connected devices. Currently at most one.
|
||||||
|
*
|
||||||
|
* @return list of connected devices
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<BluetoothDevice> getConnectedDevices() {
|
||||||
|
if (DBG) Log.d(TAG, "getConnectedDevices()");
|
||||||
|
if (mService != null && isEnabled()) {
|
||||||
|
try {
|
||||||
|
return mService.getConnectedDevices();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the list of devices matching specified states. Currently at most one.
|
||||||
|
*
|
||||||
|
* @return list of matching devices
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
|
||||||
|
if (DBG) Log.d(TAG, "getDevicesMatchingStates()");
|
||||||
|
if (mService != null && isEnabled()) {
|
||||||
|
try {
|
||||||
|
return mService.getDevicesMatchingConnectionStates(states);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get connection state of device
|
||||||
|
*
|
||||||
|
* @return device connection state
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getConnectionState(BluetoothDevice device) {
|
||||||
|
if (DBG) Log.d(TAG, "getConnectionState(" + device + ")");
|
||||||
|
if (mService != null && isEnabled() &&
|
||||||
|
isValidDevice(device)) {
|
||||||
|
try {
|
||||||
|
return mService.getConnectionState(device);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
return BluetoothProfile.STATE_DISCONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||||
|
return BluetoothProfile.STATE_DISCONNECTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set priority of the profile
|
||||||
|
*
|
||||||
|
* <p> The device should already be paired. Priority can be one of {@link #PRIORITY_ON} or
|
||||||
|
* {@link #PRIORITY_OFF},
|
||||||
|
*
|
||||||
|
* @param device Paired bluetooth device
|
||||||
|
* @return true if priority is set, false on error
|
||||||
|
*/
|
||||||
|
public boolean setPriority(BluetoothDevice device, int priority) {
|
||||||
|
if (DBG) Log.d(TAG, "setPriority(" + device + ", " + priority + ")");
|
||||||
|
if (mService != null && isEnabled() &&
|
||||||
|
isValidDevice(device)) {
|
||||||
|
if (priority != BluetoothProfile.PRIORITY_OFF &&
|
||||||
|
priority != BluetoothProfile.PRIORITY_ON) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return mService.setPriority(device, priority);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the priority of the profile.
|
||||||
|
*
|
||||||
|
* <p> The priority can be any of:
|
||||||
|
* {@link #PRIORITY_AUTO_CONNECT}, {@link #PRIORITY_OFF},
|
||||||
|
* {@link #PRIORITY_ON}, {@link #PRIORITY_UNDEFINED}
|
||||||
|
*
|
||||||
|
* @param device Bluetooth device
|
||||||
|
* @return priority of the device
|
||||||
|
*/
|
||||||
|
public int getPriority(BluetoothDevice device) {
|
||||||
|
if (VDBG) Log.d(TAG, "getPriority(" + device + ")");
|
||||||
|
if (mService != null && isEnabled() &&
|
||||||
|
isValidDevice(device)) {
|
||||||
|
try {
|
||||||
|
return mService.getPriority(device);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
return PRIORITY_OFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mService == null) Log.w(TAG, "Proxy not attached to service");
|
||||||
|
return PRIORITY_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message.
|
||||||
|
*
|
||||||
|
* Send an SMS message to either the contacts primary number or the telephone number specified.
|
||||||
|
*
|
||||||
|
* @param device Bluetooth device
|
||||||
|
* @param contacts Uri[] of the contacts
|
||||||
|
* @param message Message to be sent
|
||||||
|
* @param sentIntent intent issued when message is sent
|
||||||
|
* @param deliveredIntent intent issued when message is delivered
|
||||||
|
* @return true if the message is enqueued, false on error
|
||||||
|
*/
|
||||||
|
public boolean sendMessage(BluetoothDevice device, Uri[] contacts, String message,
|
||||||
|
PendingIntent sentIntent, PendingIntent deliveredIntent) {
|
||||||
|
if (DBG) Log.d(TAG, "sendMessage(" + device + ", " + contacts + ", " + message);
|
||||||
|
if (mService != null && isEnabled() && isValidDevice(device)) {
|
||||||
|
try {
|
||||||
|
return mService.sendMessage(device, contacts, message, sentIntent, deliveredIntent);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unread messages. Unread messages will be published via {@LINK #ACTION_MESSAGE_RECEIVED}.
|
||||||
|
*
|
||||||
|
* @param device Bluetooth device
|
||||||
|
* @return true if the message is enqueued, false on error
|
||||||
|
*/
|
||||||
|
public boolean getUnreadMessages(BluetoothDevice device) {
|
||||||
|
if (DBG) Log.d(TAG, "getUnreadMessages(" + device + ")");
|
||||||
|
if (mService != null && isEnabled() && isValidDevice(device)) {
|
||||||
|
try {
|
||||||
|
return mService.getUnreadMessages(device);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, Log.getStackTraceString(new Throwable()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||||
|
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||||
|
if (DBG) Log.d(TAG, "Proxy object connected");
|
||||||
|
mService = IBluetoothMapClient.Stub.asInterface(service);
|
||||||
|
if (mServiceListener != null) {
|
||||||
|
mServiceListener.onServiceConnected(BluetoothProfile.MAP_CLIENT,
|
||||||
|
BluetoothMapClient.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(ComponentName className) {
|
||||||
|
if (DBG) Log.d(TAG, "Proxy object disconnected");
|
||||||
|
mService = null;
|
||||||
|
if (mServiceListener != null) {
|
||||||
|
mServiceListener.onServiceDisconnected(BluetoothProfile.MAP_CLIENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private boolean isEnabled() {
|
||||||
|
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||||
|
if (adapter != null && adapter.getState() == BluetoothAdapter.STATE_ON) return true;
|
||||||
|
if (DBG) Log.d(TAG, "Bluetooth is Not enabled");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidDevice(BluetoothDevice device) {
|
||||||
|
if (device == null) return false;
|
||||||
|
|
||||||
|
if (BluetoothAdapter.checkBluetoothAddress(device.getAddress())) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2010-2014 The Android Open Source Project
|
* Copyright (C) 2010-2016 The Android Open Source Project
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -136,6 +136,12 @@ public interface BluetoothProfile {
|
|||||||
*/
|
*/
|
||||||
public static final int PBAP_CLIENT = 17;
|
public static final int PBAP_CLIENT = 17;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MAP Messaging Client Equipment (MCE)
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final int MAP_CLIENT = 18;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Max profile ID. This value should be updated whenever a new profile is added to match
|
* Max profile ID. This value should be updated whenever a new profile is added to match
|
||||||
* the largest value assigned to a profile.
|
* the largest value assigned to a profile.
|
||||||
|
|||||||
40
core/java/android/bluetooth/IBluetoothMapClient.aidl
Normal file
40
core/java/android/bluetooth/IBluetoothMapClient.aidl
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.app.PendingIntent;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System private API for Bluetooth MAP MCE service
|
||||||
|
*
|
||||||
|
* {@hide}
|
||||||
|
*/
|
||||||
|
interface IBluetoothMapClient {
|
||||||
|
boolean connect(in BluetoothDevice device);
|
||||||
|
boolean disconnect(in BluetoothDevice device);
|
||||||
|
boolean isConnected(in BluetoothDevice device);
|
||||||
|
List<BluetoothDevice> getConnectedDevices();
|
||||||
|
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
|
||||||
|
int getConnectionState(in BluetoothDevice device);
|
||||||
|
boolean setPriority(in BluetoothDevice device,in int priority);
|
||||||
|
int getPriority(in BluetoothDevice device);
|
||||||
|
boolean sendMessage(in BluetoothDevice device, in Uri[] contacts, in String message,
|
||||||
|
in PendingIntent sentIntent, in PendingIntent deliveryIntent);
|
||||||
|
boolean getUnreadMessages(in BluetoothDevice device);
|
||||||
|
}
|
||||||
@@ -8165,6 +8165,9 @@ public final class Settings {
|
|||||||
public static final String
|
public static final String
|
||||||
BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
|
BLUETOOTH_MAP_PRIORITY_PREFIX = "bluetooth_map_priority_";
|
||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
|
public static final String
|
||||||
|
BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX = "bluetooth_map_client_priority_";
|
||||||
|
/** {@hide} */
|
||||||
public static final String
|
public static final String
|
||||||
BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX = "bluetooth_pbap_client_priority_";
|
BLUETOOTH_PBAP_CLIENT_PRIORITY_PREFIX = "bluetooth_pbap_client_priority_";
|
||||||
/** {@hide} */
|
/** {@hide} */
|
||||||
@@ -8365,6 +8368,14 @@ public final class Settings {
|
|||||||
return BLUETOOTH_MAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
|
return BLUETOOTH_MAP_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the key that retrieves a bluetooth map client priority.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final String getBluetoothMapClientPriorityKey(String address) {
|
||||||
|
return BLUETOOTH_MAP_CLIENT_PRIORITY_PREFIX + address.toUpperCase(Locale.ROOT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the key that retrieves a bluetooth pbap client priority.
|
* Get the key that retrieves a bluetooth pbap client priority.
|
||||||
* @hide
|
* @hide
|
||||||
@@ -8374,7 +8385,7 @@ public final class Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the key that retrieves a bluetooth map priority.
|
* Get the key that retrieves a bluetooth sap priority.
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public static final String getBluetoothSapPriorityKey(String address) {
|
public static final String getBluetoothSapPriorityKey(String address) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.bluetooth.BluetoothDevice;
|
|||||||
import android.bluetooth.BluetoothHeadset;
|
import android.bluetooth.BluetoothHeadset;
|
||||||
import android.bluetooth.BluetoothHeadsetClient;
|
import android.bluetooth.BluetoothHeadsetClient;
|
||||||
import android.bluetooth.BluetoothMap;
|
import android.bluetooth.BluetoothMap;
|
||||||
|
import android.bluetooth.BluetoothMapClient;
|
||||||
import android.bluetooth.BluetoothInputDevice;
|
import android.bluetooth.BluetoothInputDevice;
|
||||||
import android.bluetooth.BluetoothPan;
|
import android.bluetooth.BluetoothPan;
|
||||||
import android.bluetooth.BluetoothPbapClient;
|
import android.bluetooth.BluetoothPbapClient;
|
||||||
@@ -81,12 +82,14 @@ public final class LocalBluetoothProfileManager {
|
|||||||
private HeadsetProfile mHeadsetProfile;
|
private HeadsetProfile mHeadsetProfile;
|
||||||
private HfpClientProfile mHfpClientProfile;
|
private HfpClientProfile mHfpClientProfile;
|
||||||
private MapProfile mMapProfile;
|
private MapProfile mMapProfile;
|
||||||
|
private MapClientProfile mMapClientProfile;
|
||||||
private final HidProfile mHidProfile;
|
private final HidProfile mHidProfile;
|
||||||
private OppProfile mOppProfile;
|
private OppProfile mOppProfile;
|
||||||
private final PanProfile mPanProfile;
|
private final PanProfile mPanProfile;
|
||||||
private PbapClientProfile mPbapClientProfile;
|
private PbapClientProfile mPbapClientProfile;
|
||||||
private final PbapServerProfile mPbapProfile;
|
private final PbapServerProfile mPbapProfile;
|
||||||
private final boolean mUsePbapPce;
|
private final boolean mUsePbapPce;
|
||||||
|
private final boolean mUseMapClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mapping from profile name, e.g. "HEADSET" to profile object.
|
* Mapping from profile name, e.g. "HEADSET" to profile object.
|
||||||
@@ -104,6 +107,8 @@ public final class LocalBluetoothProfileManager {
|
|||||||
mDeviceManager = deviceManager;
|
mDeviceManager = deviceManager;
|
||||||
mEventManager = eventManager;
|
mEventManager = eventManager;
|
||||||
mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
|
mUsePbapPce = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
|
||||||
|
// MAP Client is typically used in the same situations as PBAP Client
|
||||||
|
mUseMapClient = mContext.getResources().getBoolean(R.bool.enable_pbap_pce_profile);
|
||||||
// pass this reference to adapter and event manager (circular dependency)
|
// pass this reference to adapter and event manager (circular dependency)
|
||||||
mLocalAdapter.setProfileManager(this);
|
mLocalAdapter.setProfileManager(this);
|
||||||
mEventManager.setProfileManager(this);
|
mEventManager.setProfileManager(this);
|
||||||
@@ -125,10 +130,15 @@ public final class LocalBluetoothProfileManager {
|
|||||||
BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
|
BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
|
||||||
|
|
||||||
if(DEBUG) Log.d(TAG, "Adding local MAP profile");
|
if(DEBUG) Log.d(TAG, "Adding local MAP profile");
|
||||||
mMapProfile = new MapProfile(mContext, mLocalAdapter,
|
if (mUseMapClient) {
|
||||||
mDeviceManager, this);
|
mMapClientProfile = new MapClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
|
||||||
addProfile(mMapProfile, MapProfile.NAME,
|
addProfile(mMapClientProfile, MapClientProfile.NAME,
|
||||||
BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
|
BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
|
||||||
|
} else {
|
||||||
|
mMapProfile = new MapProfile(mContext, mLocalAdapter, mDeviceManager, this);
|
||||||
|
addProfile(mMapProfile, MapProfile.NAME,
|
||||||
|
BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
//Create PBAP server profile, but do not add it to list of profiles
|
//Create PBAP server profile, but do not add it to list of profiles
|
||||||
// as we do not need to monitor the profile as part of profile list
|
// as we do not need to monitor the profile as part of profile list
|
||||||
@@ -199,6 +209,22 @@ public final class LocalBluetoothProfileManager {
|
|||||||
Log.d(TAG, "Handsfree Uuid not found.");
|
Log.d(TAG, "Handsfree Uuid not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Message Access Profile Client
|
||||||
|
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.MNS)) {
|
||||||
|
if (mMapClientProfile == null) {
|
||||||
|
if(DEBUG) Log.d(TAG, "Adding local Map Client profile");
|
||||||
|
mMapClientProfile =
|
||||||
|
new MapClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
|
||||||
|
addProfile(mMapClientProfile, MapClientProfile.NAME,
|
||||||
|
BluetoothMapClient.ACTION_CONNECTION_STATE_CHANGED);
|
||||||
|
}
|
||||||
|
} else if (mMapClientProfile != null) {
|
||||||
|
Log.w(TAG,
|
||||||
|
"Warning: MAP Client profile was previously added but the UUID is now missing.");
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "MAP Client Uuid not found.");
|
||||||
|
}
|
||||||
|
|
||||||
// OPP
|
// OPP
|
||||||
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
|
if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
|
||||||
if (mOppProfile == null) {
|
if (mOppProfile == null) {
|
||||||
@@ -383,6 +409,10 @@ public final class LocalBluetoothProfileManager {
|
|||||||
return mMapProfile;
|
return mMapProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MapClientProfile getMapClientProfile() {
|
||||||
|
return mMapClientProfile;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill in a list of LocalBluetoothProfile objects that are supported by
|
* Fill in a list of LocalBluetoothProfile objects that are supported by
|
||||||
* the local device and the remote device.
|
* the local device and the remote device.
|
||||||
@@ -465,6 +495,11 @@ public final class LocalBluetoothProfileManager {
|
|||||||
mMapProfile.setPreferred(device, true);
|
mMapProfile.setPreferred(device, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mMapClientProfile != null) {
|
||||||
|
profiles.add(mMapClientProfile);
|
||||||
|
removedProfiles.remove(mMapClientProfile);
|
||||||
|
}
|
||||||
|
|
||||||
if (mUsePbapPce) {
|
if (mUsePbapPce) {
|
||||||
profiles.add(mPbapClientProfile);
|
profiles.add(mPbapClientProfile);
|
||||||
removedProfiles.remove(mPbapClientProfile);
|
removedProfiles.remove(mPbapClientProfile);
|
||||||
|
|||||||
@@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012 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.android.settingslib.bluetooth;
|
||||||
|
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothClass;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothMapClient;
|
||||||
|
import android.bluetooth.BluetoothProfile;
|
||||||
|
import android.bluetooth.BluetoothUuid;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.ParcelUuid;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.settingslib.R;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MapClientProfile handles Bluetooth MAP profile.
|
||||||
|
*/
|
||||||
|
public final class MapClientProfile implements LocalBluetoothProfile {
|
||||||
|
private static final String TAG = "MapClientProfile";
|
||||||
|
private static boolean V = false;
|
||||||
|
|
||||||
|
private BluetoothMapClient mService;
|
||||||
|
private boolean mIsProfileReady;
|
||||||
|
|
||||||
|
private final LocalBluetoothAdapter mLocalAdapter;
|
||||||
|
private final CachedBluetoothDeviceManager mDeviceManager;
|
||||||
|
private final LocalBluetoothProfileManager mProfileManager;
|
||||||
|
|
||||||
|
static final ParcelUuid[] UUIDS = {
|
||||||
|
BluetoothUuid.MAP,
|
||||||
|
BluetoothUuid.MNS,
|
||||||
|
BluetoothUuid.MAS,
|
||||||
|
};
|
||||||
|
|
||||||
|
static final String NAME = "MAP Client";
|
||||||
|
|
||||||
|
// Order of this profile in device profiles list
|
||||||
|
private static final int ORDINAL = 0;
|
||||||
|
|
||||||
|
// These callbacks run on the main thread.
|
||||||
|
private final class MapClientServiceListener
|
||||||
|
implements BluetoothProfile.ServiceListener {
|
||||||
|
|
||||||
|
public void onServiceConnected(int profile, BluetoothProfile proxy) {
|
||||||
|
if (V) Log.d(TAG,"Bluetooth service connected");
|
||||||
|
mService = (BluetoothMapClient) proxy;
|
||||||
|
// We just bound to the service, so refresh the UI for any connected MAP devices.
|
||||||
|
List<BluetoothDevice> deviceList = mService.getConnectedDevices();
|
||||||
|
while (!deviceList.isEmpty()) {
|
||||||
|
BluetoothDevice nextDevice = deviceList.remove(0);
|
||||||
|
CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
|
||||||
|
// we may add a new device here, but generally this should not happen
|
||||||
|
if (device == null) {
|
||||||
|
Log.w(TAG, "MapProfile found new device: " + nextDevice);
|
||||||
|
device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
|
||||||
|
}
|
||||||
|
device.onProfileStateChanged(MapClientProfile.this,
|
||||||
|
BluetoothProfile.STATE_CONNECTED);
|
||||||
|
device.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
mProfileManager.callServiceConnectedListeners();
|
||||||
|
mIsProfileReady=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceDisconnected(int profile) {
|
||||||
|
if (V) Log.d(TAG,"Bluetooth service disconnected");
|
||||||
|
mProfileManager.callServiceDisconnectedListeners();
|
||||||
|
mIsProfileReady=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProfileReady() {
|
||||||
|
if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady);
|
||||||
|
return mIsProfileReady;
|
||||||
|
}
|
||||||
|
|
||||||
|
MapClientProfile(Context context, LocalBluetoothAdapter adapter,
|
||||||
|
CachedBluetoothDeviceManager deviceManager,
|
||||||
|
LocalBluetoothProfileManager profileManager) {
|
||||||
|
mLocalAdapter = adapter;
|
||||||
|
mDeviceManager = deviceManager;
|
||||||
|
mProfileManager = profileManager;
|
||||||
|
mLocalAdapter.getProfileProxy(context, new MapClientServiceListener(),
|
||||||
|
BluetoothProfile.MAP_CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isConnectable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAutoConnectable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean connect(BluetoothDevice device) {
|
||||||
|
if (mService == null) return false;
|
||||||
|
List<BluetoothDevice> connectedDevices = getConnectedDevices();
|
||||||
|
if (connectedDevices != null) {
|
||||||
|
for (BluetoothDevice connectedDevice : connectedDevices) {
|
||||||
|
mService.disconnect(connectedDevice);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mService.connect(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean disconnect(BluetoothDevice device) {
|
||||||
|
if (mService == null) return false;
|
||||||
|
// Downgrade priority as user is disconnecting.
|
||||||
|
if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
|
||||||
|
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||||
|
}
|
||||||
|
return mService.disconnect(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getConnectionStatus(BluetoothDevice device) {
|
||||||
|
if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
|
||||||
|
|
||||||
|
return mService.getConnectionState(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPreferred(BluetoothDevice device) {
|
||||||
|
if (mService == null) return false;
|
||||||
|
return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPreferred(BluetoothDevice device) {
|
||||||
|
if (mService == null) return BluetoothProfile.PRIORITY_OFF;
|
||||||
|
return mService.getPriority(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPreferred(BluetoothDevice device, boolean preferred) {
|
||||||
|
if (mService == null) return;
|
||||||
|
if (preferred) {
|
||||||
|
if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
|
||||||
|
mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<BluetoothDevice> getConnectedDevices() {
|
||||||
|
if (mService == null) return new ArrayList<BluetoothDevice>(0);
|
||||||
|
return mService.getDevicesMatchingConnectionStates(
|
||||||
|
new int[] {BluetoothProfile.STATE_CONNECTED,
|
||||||
|
BluetoothProfile.STATE_CONNECTING,
|
||||||
|
BluetoothProfile.STATE_DISCONNECTING});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getOrdinal() {
|
||||||
|
return ORDINAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNameResource(BluetoothDevice device) {
|
||||||
|
return R.string.bluetooth_profile_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSummaryResourceForDevice(BluetoothDevice device) {
|
||||||
|
int state = getConnectionStatus(device);
|
||||||
|
switch (state) {
|
||||||
|
case BluetoothProfile.STATE_DISCONNECTED:
|
||||||
|
return R.string.bluetooth_map_profile_summary_use_for;
|
||||||
|
|
||||||
|
case BluetoothProfile.STATE_CONNECTED:
|
||||||
|
return R.string.bluetooth_map_profile_summary_connected;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return Utils.getConnectionStateSummary(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDrawableResource(BluetoothClass btClass) {
|
||||||
|
return R.drawable.ic_bt_cellphone;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void finalize() {
|
||||||
|
if (V) Log.d(TAG, "finalize()");
|
||||||
|
if (mService != null) {
|
||||||
|
try {
|
||||||
|
BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP_CLIENT,
|
||||||
|
mService);
|
||||||
|
mService = null;
|
||||||
|
}catch (Throwable t) {
|
||||||
|
Log.w(TAG, "Error cleaning up MAP Client proxy", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user