package eu.hgross.blaubot.android.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Looper;
import android.os.Vibrator;
import android.text.Html;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Collection;
import eu.hgross.blaubot.android.R;
import eu.hgross.blaubot.core.Blaubot;
import eu.hgross.blaubot.core.IBlaubotConnection;
import eu.hgross.blaubot.core.ServerConnectionManager;
import eu.hgross.blaubot.core.acceptor.IBlaubotConnectionManagerListener;
import eu.hgross.blaubot.ui.IBlaubotDebugView;
import eu.hgross.blaubot.util.Log;
/**
* A view to visualize a list of IBlaubotConnections beautifully ;-)
* Implements IBlaubotDebugView but can also be used manually via addConnection, removeConnection and clearConnections.
*
* @author Henning Gross {@literal (mail.to@henning-gross.de)}
*/
public class ConnectionView extends LinearLayout implements IBlaubotConnectionManagerListener, IBlaubotDebugView {
private static final String LOG_TAG = "ConnectionView";
private static final String NO_CONNECTED_DEVICES_TEXT = "No connections.";
private Blaubot mBlaubot;
private ArrayList<IBlaubotConnection> mConnections;
private Handler mUiHandler;
private Object mMonitor = new Object();
private boolean mShowId = true;
private Vibrator mVibrator;
/**
* If the user disconnects a visualized connection via tap, we vibrate for this amount of time.
*/
private long DISCONNECT_VIBRATION_TIME = 100;
public ConnectionView(Context context, AttributeSet attrs) {
super(context, attrs);
if (attrs != null) {
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.ConnectionView,
0, 0);
try {
mShowId = a.getBoolean(R.styleable.ConnectionView_showId, mShowId);
} finally {
a.recycle();
}
}
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mUiHandler = new Handler(Looper.getMainLooper());
mConnections = new ArrayList<>();
}
public void registerBlaubotInstance(Blaubot blaubot) {
if (this.mBlaubot != null) {
unregisterBlaubotInstance();
}
this.mBlaubot = blaubot;
this.mBlaubot.getConnectionManager().addConnectionListener(this);
updateList();
}
@Override
public void unregisterBlaubotInstance() {
if (this.mBlaubot != null) {
this.mBlaubot.getConnectionManager().removeConnectionListener(this);
this.mBlaubot = null;
}
clearConnections();
}
@Override
public void onConnectionEstablished(final IBlaubotConnection connection) {
if (Log.logDebugMessages()) {
Log.d(LOG_TAG, "Got connection established event - " + connection);
}
addConnection(connection);
if (Log.logDebugMessages()) {
Log.d(LOG_TAG, "Connections: " + mConnections);
}
updateList();
}
@Override
public void onConnectionClosed(final IBlaubotConnection connection) {
if (Log.logDebugMessages()) {
Log.d(LOG_TAG, "Got connection closed event - " + connection);
}
removeConnection(connection);
if (Log.logDebugMessages()) {
Log.d(LOG_TAG, "Connections: " + mConnections);
}
updateList();
}
/**
* Adds a list of mConnections, then updates the view.
*
* @param connectionList the list of connections to be added
*/
public void addConnections(Collection<IBlaubotConnection> connectionList) {
for (IBlaubotConnection connection : connectionList) {
synchronized (mMonitor) {
mConnections.add(connection);
}
}
updateList();
}
/**
* Adds a connection and refreshes the view
*
* @param connection the connection to be added
*/
public void addConnection(IBlaubotConnection connection) {
synchronized (mMonitor) {
mConnections.add(connection);
}
updateList();
}
/**
* Removes a connection and refreshes the view
*
* @param connection the connection to be added
*/
public void removeConnection(IBlaubotConnection connection) {
synchronized (mMonitor) {
mConnections.remove(connection);
}
updateList();
}
/**
* Removes all mConnections and refreshes the view
*/
public void clearConnections() {
synchronized (mMonitor) {
mConnections.clear();
}
updateList();
}
private void updateList() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
removeAllViews();
ArrayList<IBlaubotConnection> cp = new ArrayList<>(mConnections);
for (final IBlaubotConnection connection : cp) {
View view = inflate(getContext(), R.layout.blaubot_device_list_item, null);
TextView id = (TextView) view.findViewById(R.id.blaubot_device_list_item_id);
TextView name = (TextView) view.findViewById(R.id.blaubot_device_list_item_name);
TextView connectionClass = (TextView) view.findViewById(R.id.blaubot_device_list_connection_class);
id.setVisibility(mShowId ? VISIBLE : GONE);
id.setText(connection.getRemoteDevice().getUniqueDeviceID());
name.setText(connection.getRemoteDevice().getReadableName());
if (!(connection instanceof ServerConnectionManager.BlaubotServerRelayConnection)) {
connectionClass.setText(connection.getClass().getSimpleName() + "");
connectionClass.setMaxLines(1);
connectionClass.setSingleLine(true);
connectionClass.setEllipsize(TextUtils.TruncateAt.MIDDLE);
} else {
ServerConnectionManager.BlaubotServerRelayConnection relayConnection = (ServerConnectionManager.BlaubotServerRelayConnection) connection;
StringBuilder sb = new StringBuilder("<html>");
sb.append(connection.getClass().getSimpleName());
sb.append("<br>via mediator device<br>");
sb.append(relayConnection.getMediatorUniqueDeviceId());
sb.append("</html>");
connectionClass.setEllipsize(null);
connectionClass.setSingleLine(false);
connectionClass.setMaxLines(3);
connectionClass.setText(Html.fromHtml(sb.toString()));
}
view.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mUiHandler.post(new Runnable() {
@Override
public void run() {
if (mVibrator != null) {
mVibrator.vibrate(DISCONNECT_VIBRATION_TIME);
}
Toast.makeText(getContext(), "Closing connection ...", Toast.LENGTH_SHORT).show();
}
});
// disconnect, but don't lock up the ui.
new Thread(new Runnable() {
@Override
public void run() {
connection.disconnect();
}
}).start();
}
});
addView(view);
}
if (cp.isEmpty()) {
TextView tv = new TextView(getContext(), null);
tv.setText(NO_CONNECTED_DEVICES_TEXT);
addView(tv);
}
}
});
}
}