Skip to content

Commit

Permalink
Re-architects ScanView to to remove complexity
Browse files Browse the repository at this point in the history
- No longer hacks a listview, everything is in a LinearLayout
- No longer requires separate classes for connected and disconnected meter tiles, they use their own LinearLayouts now
  • Loading branch information
jwhong committed Aug 30, 2015
1 parent 0bbd9d4 commit 0aea1b5
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 186 deletions.
266 changes: 124 additions & 142 deletions app/src/main/java/com/mooshim/mooshimeter/main/ScanActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
Expand All @@ -37,10 +36,8 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

Expand Down Expand Up @@ -70,22 +67,24 @@ public class ScanActivity extends FragmentActivity {

private static final List<MooshimeterDevice> mMeterList = new ArrayList<MooshimeterDevice>();
private static final Map<String,MooshimeterDevice> mMeterDict = new HashMap<String, MooshimeterDevice>();
private static final List<ViewGroup> mTileList = new ArrayList<ViewGroup>();

// Housekeeping
private static final Lock utilLock = new ReentrantLock();
private static final Condition scanThreadCondition = utilLock.newCondition();

// GUI Widgets
private DeviceListAdapter mDeviceAdapter = null;
private TextView mEmptyMsg;
private TextView mStatus;
private Button mBtnScan = null;
private ListView mDeviceListView = null;
private LinearLayout mDeviceScrollView = null;

// Flags for the scan logic thread
private static boolean mScanOngoing = false;
private static MooshimeterDevice mConnectionRequester = null;

private LayoutInflater mInflater;

@Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
Expand All @@ -112,31 +111,16 @@ public void onCreate(Bundle savedInstanceState) {

setContentView(R.layout.fragment_scan);
// Initialize widgets
mStatus = (TextView) findViewById(R.id.status);
mBtnScan = (Button) findViewById(R.id.btn_scan);
mDeviceListView = (ListView) findViewById(R.id.device_list);
mEmptyMsg = (TextView) findViewById(R.id.no_device);
mStatus = (TextView) findViewById(R.id.status);
mBtnScan = (Button) findViewById(R.id.btn_scan);
mDeviceScrollView = (LinearLayout) findViewById(R.id.device_list);
mEmptyMsg = (TextView) findViewById(R.id.no_device);

mDeviceListView.setClickable(true);
mDeviceListView.setOnItemClickListener(mDeviceClickListener);
mDeviceScrollView.setClickable(true);

mDeviceAdapter = new DeviceListAdapter(this);
mDeviceListView.setAdapter(mDeviceAdapter);
mInflater = LayoutInflater.from(this);
}

private AdapterView.OnItemClickListener mDeviceClickListener = new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int pos, long id) {
final MooshimeterDevice m = mMeterList.get(pos);
if( m.mConnectionState == BluetoothProfile.STATE_CONNECTED
|| m.mConnectionState == BluetoothProfile.STATE_CONNECTING ) {
startSingleMeterActivity(m);
} else {
final Button bv = (Button)view.findViewById(R.id.btnConnect);
toggleConnectionState(bv,m);
}
}
};

@Override
public void onResume() {
super.onResume();
Expand Down Expand Up @@ -214,7 +198,7 @@ void updateScanningButton(boolean scanning) {
mBtnScan.setText("Scan");
mBtnScan.setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_action_refresh, 0);
mEmptyMsg.setText(R.string.scan_advice);
mDeviceAdapter.notifyDataSetChanged();
refreshAllMeterTiles();
}
if(mMeterDict.size() == 0) {
mEmptyMsg.setVisibility(View.VISIBLE);
Expand Down Expand Up @@ -246,19 +230,125 @@ public void run() {
});
}

private void addDevice(MooshimeterDevice d) {
private void addDevice(final MooshimeterDevice d) {
mEmptyMsg.setVisibility(View.GONE);

if(mMeterList.contains(d)) {
// The meter as already been added
Log.e(TAG, "Tried to add the same meter twice");
return;
}

mMeterList.add(d);
mMeterDict.put(d.getAddress(), d);

mDeviceAdapter.notifyDataSetChanged();
final LinearLayout wrapper = new LinearLayout(this);
wrapper.setOrientation(LinearLayout.VERTICAL);
wrapper.setLayoutParams(mDeviceScrollView.getLayoutParams());

wrapper.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if( d.mConnectionState == BluetoothProfile.STATE_CONNECTED
|| d.mConnectionState == BluetoothProfile.STATE_CONNECTING ) {
startSingleMeterActivity(d);
} else {
final Button bv = (Button)view.findViewById(R.id.btnConnect);
toggleConnectionState(bv,d);
}
}
});

wrapper.addView(mInflater.inflate(R.layout.element_mm_titlebar, wrapper, false));
//wrapper.setTag(Integer.valueOf(R.layout.element_mm_titlebar));

refreshMeterTile(d, wrapper);
mDeviceScrollView.addView(wrapper);
mTileList.add(wrapper);

if (mMeterList.size() > 1)
setStatus(mMeterList.size() + " devices");
else
setStatus("1 device");
}

private void refreshMeterTile(final MooshimeterDevice d, final ViewGroup wrapper) {
if(wrapper.getChildCount()==0) {
Log.e(TAG,"Received empty wrapper");
}
if(wrapper.getChildCount()>0) {
// Update the title bar
int rssi = d.mRssi;
String name;
String build;
if(d.mOADMode) {
name = "Bootloader";
} else {
name = d.getBLEDevice().getName();
if (name == null) {
name = new String("Unknown device");
}
}

if(d.mBuildTime == 0) {
build = "Invalid firmware";
} else {
build = "Build: "+d.mBuildTime;
}

String descr = name + "\n" + build + "\nRssi: " + rssi + " dBm";
((TextView) wrapper.findViewById(R.id.descr)).setText(descr);

final Button bv = (Button)wrapper.findViewById(R.id.btnConnect);

int bgid = d.mConnectionState==BluetoothProfile.STATE_CONNECTED ? R.drawable.connected:R.drawable.disconnected;
bv.setBackground(getResources().getDrawable(bgid));

// Set the click listeners
bv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
toggleConnectionState(bv,d);
}
});
}
if(d.mInitialized && !d.isInOADMode()) {
// We are representing a connected meter
if(wrapper.getChildCount() != 2) {
// We need to create a new value pane
wrapper.addView(mInflater.inflate(R.layout.element_mm_readingsbar, mDeviceScrollView, false));
}
if(!d.isNotificationEnabled(d.getChar(MooshimeterDevice.mUUID.METER_SAMPLE))) {
// We need to enable notifications
d.playSampleStream(new Runnable() {
@Override
public void run() {
TextView ch1 = (TextView)wrapper.findViewById(R.id.ch1_value_label);
TextView ch2 = (TextView)wrapper.findViewById(R.id.ch2_value_label);
TextView ch1_unit = (TextView)wrapper.findViewById(R.id.ch1_unit_label);
TextView ch2_unit = (TextView)wrapper.findViewById(R.id.ch2_unit_label);
valueLabelRefresh(0,d, ch1, ch1_unit);
valueLabelRefresh(1,d, ch2, ch2_unit);
}
});
}
} else {
//We are representing a disconnected meter or a meter in OAD mode
if(wrapper.getChildCount() == 2) {
// We need to eliminate a pane
wrapper.removeViewAt(1);
}
}
}

private void refreshAllMeterTiles() {
for(int i = 0; i < mDeviceScrollView.getChildCount(); i++) {
final ViewGroup vg = mTileList.get(i);
final MooshimeterDevice d = mMeterList.get(i);
refreshMeterTile(d,vg);
}
}

/////////////////////////////
// Data Structure Manipulation
/////////////////////////////
Expand Down Expand Up @@ -386,7 +476,7 @@ else if(field_id == 0) {
m.mRssi = rssi;
m.mOADMode = oad_mode;
m.mBuildTime = build_time;
mDeviceAdapter.notifyDataSetChanged();
refreshAllMeterTiles();
}
}
});
Expand All @@ -412,10 +502,12 @@ public synchronized void startScan() {
}
}
for(MooshimeterDevice m : remove) {
mDeviceScrollView.removeView(mTileList.remove(mMeterList.indexOf(m)));
mMeterList.remove(m);
mMeterDict.remove(m.getAddress());
}
mDeviceAdapter.notifyDataSetChanged();
refreshAllMeterTiles();

final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if( !bluetoothAdapter.startLeScan(mLeScanCallback) ) {
// Starting the scan failed!
Expand Down Expand Up @@ -516,114 +608,4 @@ public void run() {
}
});
}

class DeviceListAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private Map<Integer,ViewGroup> mViews;

public DeviceListAdapter(Context context) {
mInflater = LayoutInflater.from(context);
mViews = new HashMap<Integer, ViewGroup>();
}

public int getCount() {
return mMeterDict.size();
}

public Object getItem(int position) {
return mMeterList.get(position);
}

public long getItemId(int position) {
return position;
}

@Override
public int getViewTypeCount() {
return 2; // Count of different layouts
}

@Override
public int getItemViewType(int position) {
final MooshimeterDevice m = mMeterList.get(position);
if(m.mInitialized && !m.isInOADMode()) {
return 1;
} else {
return 0;
}
}

public View getView(final int position, View convertView, ViewGroup parent) {
final ViewGroup vg;

final MooshimeterDevice m = mMeterList.get(position);

//final int desired_view_id = getItemViewType(position)==1?R.layout.element_mm_full:R.layout.element_mm_titlebar;

if(m.mInitialized && !m.isInOADMode()) {
vg = (ViewGroup) mInflater.inflate(R.layout.element_mm_full, parent, false);
vg.setTag(Integer.valueOf(R.layout.element_mm_full));
View tmp = mViews.get(position);
if(tmp != null) {
// Copy the text over from the last incarnation
((TextView)vg.findViewById(R.id.ch1_value_label)).setText(((TextView)mViews.get(position).findViewById(R.id.ch1_value_label)).getText());
((TextView)vg.findViewById(R.id.ch2_value_label)).setText(((TextView)mViews.get(position).findViewById(R.id.ch2_value_label)).getText());
((TextView)vg.findViewById(R.id.ch1_unit_label)).setText(((TextView)mViews.get(position).findViewById(R.id.ch1_unit_label)).getText());
((TextView)vg.findViewById(R.id.ch2_unit_label)).setText(((TextView)mViews.get(position).findViewById(R.id.ch2_unit_label)).getText());
}
mViews.put(position,vg);
if(!m.isNotificationEnabled(m.getChar(MooshimeterDevice.mUUID.METER_SAMPLE))) {
m.playSampleStream(new Runnable() {
@Override
public void run() {
TextView ch1 = (TextView)mViews.get(position).findViewById(R.id.ch1_value_label);
TextView ch2 = (TextView)mViews.get(position).findViewById(R.id.ch2_value_label);
TextView ch1_unit = (TextView)mViews.get(position).findViewById(R.id.ch1_unit_label);
TextView ch2_unit = (TextView)mViews.get(position).findViewById(R.id.ch2_unit_label);
valueLabelRefresh(0,m, ch1, ch1_unit);
valueLabelRefresh(1,m, ch2, ch2_unit);
}
});
}
} else {
vg = (ViewGroup) mInflater.inflate(R.layout.element_mm_titlebar, parent, false);
vg.setTag(Integer.valueOf(R.layout.element_mm_titlebar));
}

int rssi = m.mRssi;
String name;
String build;
if(m.mOADMode) {
name = "Bootloader";
} else {
name = m.getBLEDevice().getName();
if (name == null) {
name = new String("Unknown device");
}
}

if(m.mBuildTime == 0) {
build = "Invalid firmware";
} else {
build = "Build: "+m.mBuildTime;
}

String descr = name + "\n" + build + "\nRssi: " + rssi + " dBm";
((TextView) vg.findViewById(R.id.descr)).setText(descr);

final Button bv = (Button)vg.findViewById(R.id.btnConnect);

int bgid = m.mConnectionState==BluetoothProfile.STATE_CONNECTED ? R.drawable.connected:R.drawable.disconnected;
bv.setBackground(getResources().getDrawable(bgid));

// Set the click listeners
bv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
toggleConnectionState(bv,m);
}
});
return vg;
}
}
}
38 changes: 0 additions & 38 deletions app/src/main/res/layout/element_mm_full.xml

This file was deleted.

Loading

0 comments on commit 0aea1b5

Please sign in to comment.