package eu.hgross.blaubot.android.views;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.apache.commons.collections4.queue.CircularFifoQueue;
import java.util.concurrent.atomic.AtomicInteger;
import eu.hgross.blaubot.android.R;
import eu.hgross.blaubot.core.Blaubot;
import eu.hgross.blaubot.core.IBlaubotDevice;
import eu.hgross.blaubot.core.ILifecycleListener;
import eu.hgross.blaubot.ui.IBlaubotDebugView;
/**
* A dedicated view to show events from the IBlaubotLifeCycleListener.
*/
public class LifeCycleView extends LinearLayout implements IBlaubotDebugView {
private static final int MAX_EVENTS_DEFAULT = 50;
private static final String NO_EVENTS_SO_FAR_TEXT = "No events so far.";
private class ViewEntry {
String labelText;
int drawableResourceId;
}
private Blaubot mBlaubot;
private CircularFifoQueue<ViewEntry> mLastEvents;
private int mMaxEvents = MAX_EVENTS_DEFAULT;
private Handler mUiHandler;
private final Object queueMonitor = new Object();
public LifeCycleView(Context context) {
super(context);
initView(context, null);
}
public LifeCycleView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
private void initView(Context context, AttributeSet attrs) {
if(attrs != null) {
TypedArray a = context.getTheme().obtainStyledAttributes(
attrs,
R.styleable.LifeCycleView,
0, 0);
try {
mMaxEvents= a.getInt(R.styleable.LifeCycleView_maxEvents, mMaxEvents);
} finally {
a.recycle();
}
}
mLastEvents = new CircularFifoQueue<>(mMaxEvents);
mUiHandler = new Handler(Looper.getMainLooper());
}
/**
* Counts the number of devices (own inclusive) in the network based on the life cycle events
*/
private AtomicInteger networkSizeCounter = new AtomicInteger();
private ILifecycleListener mLifeCycleListener = new ILifecycleListener() {
@Override
public void onConnected() {
networkSizeCounter.incrementAndGet();
addToQueue("onConnected()", android.R.drawable.presence_online);
}
@Override
public void onDisconnected() {
networkSizeCounter.decrementAndGet();
addToQueue("onDisconnected()", android.R.drawable.presence_busy);
}
@Override
public void onDeviceJoined(IBlaubotDevice blaubotDevice) {
networkSizeCounter.incrementAndGet();
addToQueue("onDeviceJoined("+blaubotDevice+")", android.R.drawable.ic_menu_add);
}
@Override
public void onDeviceLeft(IBlaubotDevice blaubotDevice) {
networkSizeCounter.decrementAndGet();
addToQueue("onDeviceLeft("+blaubotDevice+")", android.R.drawable.ic_menu_close_clear_cancel);
}
@Override
public void onPrinceDeviceChanged(IBlaubotDevice oldPrince, IBlaubotDevice newPrince) {
addToQueue("onPrinceDeviceChanged(" + oldPrince + ", " + newPrince + ")", android.R.drawable.ic_menu_edit);
}
@Override
public void onKingDeviceChanged(IBlaubotDevice oldKing, IBlaubotDevice newKing) {
addToQueue("onKingDeviceChanged(" + oldKing + ", " + newKing + ")", android.R.drawable.ic_menu_edit);
}
/**
* Adds an event to the lastEvents ring buffer
* @param eventText the text to add
* @param drawableResourceId the resource id for the icon to show
*/
private void addToQueue(String eventText, int drawableResourceId) {
final ViewEntry p = new ViewEntry();
p.labelText = eventText;
p.drawableResourceId = drawableResourceId;
synchronized (queueMonitor) {
mLastEvents.add(p);
}
upateUI();
}
};
/**
* Register this view with the given blaubot instance
*
* @param blaubot
* the blaubot instance to connect with
*/
@Override
public void registerBlaubotInstance(Blaubot blaubot) {
if (mBlaubot != null) {
unregisterBlaubotInstance();
}
this.mBlaubot = blaubot;
// register listeners
blaubot.addLifecycleListener(mLifeCycleListener);
// force some updates
upateUI();
}
@Override
public void unregisterBlaubotInstance() {
if(this.mBlaubot != null) {
mBlaubot.removeLifecycleListener(mLifeCycleListener);
mBlaubot = null;
}
upateUI();
}
private void upateUI() {
mUiHandler.post(new Runnable() {
@Override
public void run() {
final int height = getHeight(), width = getWidth();
if(getOrientation() == VERTICAL) {
setMinimumHeight(height);
} else {
setMinimumWidth(width);
}
removeAllViews();
// Number of devices
TextView numberOfDevicesTextView = new TextView(getContext());
numberOfDevicesTextView.setText("Blaubot network size: " + networkSizeCounter);
addView(numberOfDevicesTextView);
synchronized (queueMonitor) {
if(!mLastEvents.isEmpty()) {
for(ViewEntry eventPair : mLastEvents) {
final View view = inflate(getContext(), R.layout.blaubot_lifecycle_view_list_item, null);
final ImageView imageView = (ImageView) view.findViewById(R.id.icon);
final TextView label = (TextView) view.findViewById(R.id.uniqueDeviceIdLabel);
final Drawable icon = getResources().getDrawable(eventPair.drawableResourceId);
imageView.setImageDrawable(icon);
label.setText(eventPair.labelText);
addView(view);
}
} else {
TextView v = new TextView(getContext());
v.setText(NO_EVENTS_SO_FAR_TEXT);
addView(v);
}
}
}
});
}
}