package com.o3dr.android.client;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.o3dr.android.client.interfaces.TowerListener;
import com.o3dr.services.android.lib.drone.connection.ConnectionParameter;
import com.o3dr.services.android.lib.model.IDroidPlannerServices;
import com.o3dr.services.android.lib.model.IDroneApi;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Created by fhuya on 11/12/14.
*/
public class ControlTower {
private static final String TAG = ControlTower.class.getSimpleName();
private final IBinder.DeathRecipient binderDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
notifyTowerDisconnected();
}
};
private final ServiceConnection o3drServicesConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
isServiceConnecting.set(false);
o3drServices = IDroidPlannerServices.Stub.asInterface(service);
try {
o3drServices.asBinder().linkToDeath(binderDeathRecipient, 0);
notifyTowerConnected();
} catch (RemoteException e) {
notifyTowerDisconnected();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
isServiceConnecting.set(false);
notifyTowerDisconnected();
}
};
private final AtomicBoolean isServiceConnecting = new AtomicBoolean(false);
private final Context context;
private final DroneApiListener apiListener;
private TowerListener towerListener;
private IDroidPlannerServices o3drServices;
public ControlTower(Context context) {
this.context = context;
this.apiListener = new DroneApiListener(this.context);
}
public boolean isTowerConnected() {
return o3drServices != null && o3drServices.asBinder().pingBinder();
}
void notifyTowerConnected() {
if (towerListener == null)
return;
towerListener.onTowerConnected();
}
void notifyTowerDisconnected() {
if (towerListener == null)
return;
towerListener.onTowerDisconnected();
}
public Bundle[] getConnectedApps() {
Bundle[] connectedApps = new Bundle[0];
if (isTowerConnected()) {
try {
connectedApps = o3drServices.getConnectedApps(getApplicationId());
if (connectedApps != null) {
final ClassLoader classLoader = ConnectionParameter.class.getClassLoader();
for (Bundle appInfo : connectedApps) {
appInfo.setClassLoader(classLoader);
}
}
} catch (RemoteException e) {
Log.e(TAG, e.getMessage(), e);
}
}
return connectedApps;
}
public void registerDrone(Drone drone, Handler handler) {
if (drone == null)
return;
if (!isTowerConnected())
throw new IllegalStateException("Control Tower must be connected.");
drone.init(this, handler);
drone.start();
}
public void unregisterDrone(Drone drone) {
if (drone != null)
drone.destroy();
}
public void connect(TowerListener listener) {
if (towerListener != null && (isServiceConnecting.get() || isTowerConnected()))
return;
if (listener == null) {
throw new IllegalArgumentException("ServiceListener argument cannot be null.");
}
towerListener = listener;
if (!isTowerConnected() && !isServiceConnecting.get()) {
final Intent serviceIntent = ApiAvailability.getInstance().getAvailableServicesInstance(context);
isServiceConnecting.set(context.bindService(serviceIntent, o3drServicesConnection,
Context.BIND_AUTO_CREATE));
}
}
public void disconnect() {
if (o3drServices != null) {
o3drServices.asBinder().unlinkToDeath(binderDeathRecipient, 0);
o3drServices = null;
}
notifyTowerDisconnected();
towerListener = null;
try {
context.unbindService(o3drServicesConnection);
} catch (Exception e) {
Log.e(TAG, "Error occurred while unbinding from DroneKit-Android.");
}
}
IDroneApi registerDroneApi() throws RemoteException {
return o3drServices.registerDroneApi(this.apiListener, getApplicationId());
}
void releaseDroneApi(IDroneApi droneApi) throws RemoteException {
o3drServices.releaseDroneApi(droneApi);
}
private String getApplicationId() {
return context.getPackageName();
}
}