blob: 62a488a36a347c225e896bb5fefcc4e052f7e5b4 [file] [log] [blame]
/*
* Copyright (C) 2013 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.bluetooth.gatt;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.IInterface;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.UUID;
/**
* Helper class that keeps track of registered GATT applications.
* This class manages application callbacks and keeps track of GATT connections.
* @hide
*/
/*package*/ class ContextMap<T> {
private static final String TAG = GattServiceConfig.TAG_PREFIX + "ContextMap";
/**
* Connection class helps map connection IDs to device addresses.
*/
class Connection {
int connId;
String address;
int appId;
Connection(int connId, String address,int appId) {
this.connId = connId;
this.address = address;
this.appId = appId;
}
}
/**
* Application entry mapping UUIDs to appIDs and callbacks.
*/
class App {
/** The UUID of the application */
UUID uuid;
/** The id of the application */
int id;
/** Application callbacks */
T callback;
/** Death receipient */
private IBinder.DeathRecipient mDeathRecipient;
/**
* Creates a new app context.
*/
App(UUID uuid, T callback) {
this.uuid = uuid;
this.callback = callback;
}
/**
* Link death recipient
*/
void linkToDeath(IBinder.DeathRecipient deathRecipient) {
try {
IBinder binder = ((IInterface)callback).asBinder();
binder.linkToDeath(deathRecipient, 0);
mDeathRecipient = deathRecipient;
} catch (RemoteException e) {
Log.e(TAG, "Unable to link deathRecipient for app id " + id);
}
}
/**
* Unlink death recipient
*/
void unlinkToDeath() {
if (mDeathRecipient != null) {
try {
IBinder binder = ((IInterface)callback).asBinder();
binder.unlinkToDeath(mDeathRecipient,0);
} catch (NoSuchElementException e) {
Log.e(TAG, "Unable to unlink deathRecipient for app id " + id);
}
}
}
}
/** Our internal application list */
List<App> mApps = new ArrayList<App>();
/** Internal list of connected devices **/
Set<Connection> mConnections = new HashSet<Connection>();
/**
* Add an entry to the application context list.
*/
void add(UUID uuid, T callback) {
synchronized (mApps) {
mApps.add(new App(uuid, callback));
}
}
/**
* Remove the context for a given application ID.
*/
void remove(int id) {
synchronized (mApps) {
Iterator<App> i = mApps.iterator();
while(i.hasNext()) {
App entry = i.next();
if (entry.id == id) {
entry.unlinkToDeath();
i.remove();
break;
}
}
}
}
/**
* Add a new connection for a given application ID.
*/
void addConnection(int id, int connId, String address) {
synchronized (mConnections) {
App entry = getById(id);
if (entry != null){
mConnections.add(new Connection(connId, address, id));
}
}
}
/**
* Remove a connection with the given ID.
*/
void removeConnection(int id, int connId) {
synchronized (mConnections) {
Iterator<Connection> i = mConnections.iterator();
while(i.hasNext()) {
Connection connection = i.next();
if (connection.connId == connId) {
i.remove();
break;
}
}
}
}
/**
* Get an application context by ID.
*/
App getById(int id) {
Iterator<App> i = mApps.iterator();
while(i.hasNext()) {
App entry = i.next();
if (entry.id == id) return entry;
}
Log.e(TAG, "Context not found for ID " + id);
return null;
}
/**
* Get an application context by UUID.
*/
App getByUuid(UUID uuid) {
Iterator<App> i = mApps.iterator();
while(i.hasNext()) {
App entry = i.next();
if (entry.uuid.equals(uuid)) return entry;
}
Log.e(TAG, "Context not found for UUID " + uuid);
return null;
}
/**
* Get the device addresses for all connected devices
*/
Set<String> getConnectedDevices() {
Set<String> addresses = new HashSet<String>();
Iterator<Connection> i = mConnections.iterator();
while(i.hasNext()) {
Connection connection = i.next();
addresses.add(connection.address);
}
return addresses;
}
/**
* Get an application context by a connection ID.
*/
App getByConnId(int connId) {
Iterator<Connection> ii = mConnections.iterator();
while(ii.hasNext()) {
Connection connection = ii.next();
if (connection.connId == connId){
return getById(connection.appId);
}
}
return null;
}
/**
* Returns a connection ID for a given device address.
*/
Integer connIdByAddress(int id, String address) {
App entry = getById(id);
if (entry == null) return null;
Iterator<Connection> i = mConnections.iterator();
while(i.hasNext()) {
Connection connection = i.next();
if (connection.address.equals(address) && connection.appId == id)
return connection.connId;
}
return null;
}
/**
* Returns the device address for a given connection ID.
*/
String addressByConnId(int connId) {
Iterator<Connection> i = mConnections.iterator();
while(i.hasNext()) {
Connection connection = i.next();
if (connection.connId == connId) return connection.address;
}
return null;
}
List<Connection> getConnectionByApp(int appId) {
List<Connection> currentConnections = new ArrayList<Connection>();
Iterator<Connection> i = mConnections.iterator();
while(i.hasNext()) {
Connection connection = i.next();
if (connection.appId == appId)
currentConnections.add(connection);
}
return currentConnections;
}
/**
* Erases all application context entries.
*/
void clear() {
synchronized (mApps) {
Iterator<App> i = mApps.iterator();
while(i.hasNext()) {
App entry = i.next();
entry.unlinkToDeath();
i.remove();
}
}
synchronized (mConnections) {
mConnections.clear();
}
}
/**
* Logs debug information.
*/
void dump() {
StringBuilder b = new StringBuilder();
b.append( "-------------- GATT Context Map ----------------");
b.append("\nEntries: " + mApps.size());
Iterator<App> i = mApps.iterator();
while(i.hasNext()) {
App entry = i.next();
List<Connection> connections = getConnectionByApp(entry.id);
b.append("\n\nApplication Id: " + entry.id);
b.append("\nUUID: " + entry.uuid);
b.append("\nConnections: " + connections.size());
Iterator<Connection> ii = connections.iterator();
while(ii.hasNext()) {
Connection connection = ii.next();
b.append("\n " + connection.connId + ": " + connection.address);
}
}
b.append("\n------------------------------------------------");
Log.d(TAG, b.toString());
}
}