diff options
author | Trygve Laugstøl <trygvis@inamo.no> | 2014-11-30 23:55:54 +0100 |
---|---|---|
committer | Trygve Laugstøl <trygvis@inamo.no> | 2014-12-01 00:17:04 +0100 |
commit | 7a7d015f8a68f5e0d06fe6e3d9422d5f418f653d (patch) | |
tree | 35d8a59e3d5ae1e0b600d91b2ac4283380bdc896 /app/src/main/java/no/topi | |
download | fiken-display-android-7a7d015f8a68f5e0d06fe6e3d9422d5f418f653d.tar.gz fiken-display-android-7a7d015f8a68f5e0d06fe6e3d9422d5f418f653d.tar.bz2 fiken-display-android-7a7d015f8a68f5e0d06fe6e3d9422d5f418f653d.tar.xz fiken-display-android-7a7d015f8a68f5e0d06fe6e3d9422d5f418f653d.zip |
o Initial import of Fiken Status Display app.
Diffstat (limited to 'app/src/main/java/no/topi')
6 files changed, 865 insertions, 0 deletions
diff --git a/app/src/main/java/no/topi/fiken/display/Constants.java b/app/src/main/java/no/topi/fiken/display/Constants.java new file mode 100644 index 0000000..f568e1c --- /dev/null +++ b/app/src/main/java/no/topi/fiken/display/Constants.java @@ -0,0 +1,10 @@ +package no.topi.fiken.display; + +import java.util.UUID; + +public interface Constants { + String TRYGVIS_IO_BASE_UUID = "32D0xxxx-035D-59C5-70D3-BC8E4A1FD83F"; + UUID TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID = UUID.fromString(TRYGVIS_IO_BASE_UUID.replace("xxxx", "0001")); + UUID TRYGVIS_IO_GAUGE_UUID = UUID.fromString(TRYGVIS_IO_BASE_UUID.replace("xxxx", "0002")); + UUID TRYGVIS_IO_LED_UUID = UUID.fromString(TRYGVIS_IO_BASE_UUID.replace("xxxx", "0003")); +} diff --git a/app/src/main/java/no/topi/fiken/display/DefaultDisplayService.java b/app/src/main/java/no/topi/fiken/display/DefaultDisplayService.java new file mode 100644 index 0000000..b1aa2e7 --- /dev/null +++ b/app/src/main/java/no/topi/fiken/display/DefaultDisplayService.java @@ -0,0 +1,255 @@ +package no.topi.fiken.display; + +import android.app.Service; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.util.Log; +import android.widget.Toast; + +public class DefaultDisplayService extends Service implements DisplayService { + private final Context context = DefaultDisplayService.this; + private final static String TAG = DefaultDisplayService.class.getSimpleName(); + + private final IBinder binder = new LocalBinder(this); + + private BluetoothManager mBluetoothManager; + private BluetoothAdapter mBluetoothAdapter; + private BluetoothGattService displayService; + private BluetoothGatt gatt; + + private Handler handler; + private int UPDATE_RSSI_DELAY = 1000; + + private Runnable updateRssi = new Runnable() { + @Override + public void run() { + if(gatt != null) { + gatt.readRemoteRssi(); + } + + handler.postDelayed(this, UPDATE_RSSI_DELAY); + } + }; + + public static enum ServiceState { + BROKEN, + IDLE, + SCANNING, + CONNECTED, + } + + private ServiceState serviceState = ServiceState.BROKEN; + + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + @Override + public void onCreate() { + handler = new Handler(); + + handler.postDelayed(updateRssi, UPDATE_RSSI_DELAY); + } + + public boolean initialize() { + // For API level 18 and above, get a reference to BluetoothAdapter through + // BluetoothManager. + if (mBluetoothManager == null) { + mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + if (mBluetoothManager == null) { + Log.e(TAG, "Unable to initialize BluetoothManager."); + return false; + } + } + + mBluetoothAdapter = mBluetoothManager.getAdapter(); + if (mBluetoothAdapter == null) { + Log.e(TAG, "Unable to obtain a BluetoothAdapter."); + return false; + } + + Log.e(TAG, "Bluetooth initialized"); + + serviceState = ServiceState.IDLE; + + return true; + } + + @Override + public boolean connect(final String address) { + if (serviceState != ServiceState.IDLE) { + if (!(serviceState == ServiceState.CONNECTED && gatt.getDevice().getAddress().equals(address))) { + Log.e(TAG, "connect(): Not idle: " + serviceState); + return false; + } + + Log.i(TAG, "connect(): already connected: " + serviceState); + return true; + } + + BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); + + gatt = device.connectGatt(this, false, new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { +// Toast.makeText(context, "Connected", Toast.LENGTH_SHORT).show(); + if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothGatt.STATE_CONNECTED) { + boolean ok = gatt.discoverServices(); + + if (!ok) { + disconnect(); + } else { + Intent intent = IntentAction.DEVICE_UPDATE.intent(); + intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), address); + intent.putExtra(IntentExtra.CONNECTED.name(), true); + sendBroadcast(intent); + } + } else { + Log.w(TAG, "Could not connect to device"); +// Toast.makeText(context, "Could not connect to device", Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + Log.i(TAG, "onServicesDiscovered"); + + Log.i(TAG, "Constants.TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID = " + Constants.TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID); + + for (BluetoothGattService bluetoothGattService : gatt.getServices()) { + Log.i(TAG, "bluetoothGattService.getUuid() = " + bluetoothGattService.getUuid()); + } + + displayService = gatt.getService(Constants.TRYGVIS_IO_FIKEN_STATUS_PANEL_UUID); + + Log.i(TAG, "service=" + displayService); + + Intent intent = IntentAction.DEVICE_UPDATE.intent(); + intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), address); + intent.putExtra(IntentExtra.DEVICE_IS_DISPLAY.name(), displayService != null); + sendBroadcast(intent); + } + + @Override + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + Log.i(TAG, "onCharacteristicRead"); + } + + @Override + public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + Log.i(TAG, "onCharacteristicWrite"); + } + + @Override + public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + Log.i(TAG, "onCharacteristicChanged"); + } + + @Override + public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + Log.i(TAG, "onDescriptorRead"); + } + + @Override + public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + Log.i(TAG, "onDescriptorWrite"); + } + + @Override + public void onReliableWriteCompleted(BluetoothGatt gatt, int status) { + Log.i(TAG, "onReliableWriteCompleted"); + } + + @Override + public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { + Log.i(TAG, "onReadRemoteRssi, status=" + status + ", rssi=" + rssi); + if (status == BluetoothGatt.GATT_SUCCESS) { + Intent intent = IntentAction.DEVICE_UPDATE.intent(); + intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), gatt.getDevice().getAddress()); + intent.putExtra(IntentExtra.RSSI.name(), rssi); + sendBroadcast(intent); + } + } + }); + + if (gatt != null) { + serviceState = ServiceState.CONNECTED; + return true; + } else { + return false; + } + } + + @Override + public void disconnect() { + if (serviceState != ServiceState.CONNECTED) { + Log.d(TAG, "disconnect(): Not connected: " + serviceState); + return; + } + + serviceState = ServiceState.IDLE; + + if (gatt != null) { + try { + gatt.disconnect(); + } catch (Exception e) { + Log.w(TAG, "gatt.disconnect()", e); + } + try { + gatt.close(); + } catch (Exception e) { + Log.w(TAG, "gatt.close()", e); + } + gatt = null; + } + + displayService = null; + } + + @Override + public void startScan() { + if (serviceState != ServiceState.IDLE) { + Toast.makeText(context, "startScan(): Not idle", Toast.LENGTH_SHORT).show(); + return; + } + + serviceState = ServiceState.SCANNING; + + mBluetoothAdapter.startLeScan(leScanCallback); + } + + @Override + public void stopScan() { + Log.d(TAG, "stopScan(): stopping scanning"); + + if (serviceState != ServiceState.SCANNING) { + Log.d(TAG, "stopScan(): not scanning"); + return; + } + mBluetoothAdapter.stopLeScan(leScanCallback); + serviceState = ServiceState.IDLE; + } + + private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() { + @Override + public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { + Log.i(TAG, "onLeScan()"); + Intent intent = IntentAction.DEVICE_UPDATE.intent(); + intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), device.getAddress()); + intent.putExtra(IntentExtra.DEVICE_NAME.name(), device.getName()); + intent.putExtra(IntentExtra.RSSI.name(), rssi); + sendBroadcast(intent); + } + }; +} diff --git a/app/src/main/java/no/topi/fiken/display/DisplayControlActivity.java b/app/src/main/java/no/topi/fiken/display/DisplayControlActivity.java new file mode 100644 index 0000000..1147c0c --- /dev/null +++ b/app/src/main/java/no/topi/fiken/display/DisplayControlActivity.java @@ -0,0 +1,141 @@ +package no.topi.fiken.display; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Bundle; +import android.os.IBinder; +import android.view.Menu; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; + +import static java.lang.String.valueOf; +import static no.topi.fiken.display.DisplayService.DeviceInfo; +import static no.topi.fiken.display.DisplayService.IntentAction; +import static no.topi.fiken.display.DisplayService.IntentExtra; +import static no.topi.fiken.display.DisplayService.LocalBinder; + +public class DisplayControlActivity extends Activity { + private final static String TAG = DisplayControlActivity.class.getSimpleName(); + + private DisplayService displayService; + private DeviceInfo deviceInfo; + + private TextView deviceNameView; + private TextView deviceRssiView; + private LinearLayout gaugesLayout; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_display_control); + + final Intent intent = getIntent(); + String deviceAddress = intent.getStringExtra(IntentExtra.DEVICE_ADDRESS.name()); + deviceInfo = new DeviceInfo(deviceAddress, 0); + deviceInfo.name = intent.getStringExtra(IntentExtra.DEVICE_NAME.name()); + + Intent displayServiceIntent = new Intent(this, DefaultDisplayService.class); + bindService(displayServiceIntent, serviceConnection, BIND_AUTO_CREATE); + + deviceNameView = (TextView) findViewById(R.id.device_name); + deviceRssiView = (TextView) findViewById(R.id.device_rssi); + gaugesLayout = (LinearLayout) findViewById(R.id.gauges); + + Button disconnectButton = (Button) findViewById(R.id.button_disconnect); + disconnectButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + disconnect(); + } + }); + + updateValues(); + } + + private void updateValues() { + deviceNameView.setText(deviceInfo.name != null ? deviceInfo.name : getText(R.string.name_unknown)); + deviceRssiView.setText(getText(R.string.rssi) + ": " + (deviceInfo.rssi != 0 ? valueOf(deviceInfo.rssi) : "")); + } + + @Override + protected void onResume() { + super.onResume(); + registerReceiver(displayServiceBroadcastReceiver, IntentAction.ALL_FILTER); + } + + @Override + protected void onPause() { + super.onPause(); + unregisterReceiver(displayServiceBroadcastReceiver); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + displayService.disconnect(); + unbindService(serviceConnection); + displayService = null; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_display_control, menu); + return true; + } + + public void disconnect() { + if (displayService != null) { + displayService.disconnect(); + } + + finish(); + } + + private final ServiceConnection serviceConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName componentName, IBinder service) { + displayService = ((LocalBinder) service).getService(); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + displayService = null; + } + }; + + private final BroadcastReceiver displayServiceBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + + IntentAction action = IntentAction.valueOf(intent); + + String deviceAddress = intent.getStringExtra(IntentExtra.DEVICE_ADDRESS.name()); + + if (action == IntentAction.DEVICE_UPDATE && deviceInfo.address.equals(deviceAddress)) { + runOnUiThread(new Runnable() { + @Override + public void run() { + deviceInfo.update(intent); + + if (intent.hasExtra(IntentExtra.CONNECTED.name())) { + boolean connected = intent.getBooleanExtra(IntentExtra.CONNECTED.name(), false); + + if (!connected) { + finish(); + } + } + updateValues(); + } + }); + } + } + }; +} diff --git a/app/src/main/java/no/topi/fiken/display/DisplayService.java b/app/src/main/java/no/topi/fiken/display/DisplayService.java new file mode 100644 index 0000000..c907138 --- /dev/null +++ b/app/src/main/java/no/topi/fiken/display/DisplayService.java @@ -0,0 +1,102 @@ +package no.topi.fiken.display; + +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Binder; + +public interface DisplayService { + + enum IntentExtra { + DEVICE_NAME, + DEVICE_ADDRESS, + DEVICE_IS_DISPLAY, + RSSI, + SCANNING, + CONNECTED, + } + + public static enum IntentAction { + DEVICE_UPDATE; + + private final String key = getClass().getName() + "." + name(); + + public Intent intent() { + return new Intent(key); + } + + public static final IntentFilter ALL_FILTER = new IntentFilter() {{ + for (DefaultDisplayService.IntentAction intentAction : DefaultDisplayService.IntentAction.values()) { + addAction(intentAction.key); + } + }}; + + public static IntentAction valueOf(Intent intent) { + try { + return valueOf(intent.getAction().replaceAll(".*\\.", "")); + } catch (IllegalArgumentException e) { + return null; + } + } + } + + public class LocalBinder extends Binder { + private final DisplayService service; + + public LocalBinder(DisplayService service) { + this.service = service; + } + + DisplayService getService() { + return service; + } + } + + boolean initialize(); + + void startScan(); + + void stopScan(); + + boolean connect(String address); + + public void disconnect(); + + class DeviceInfo { + final String address; + int rssi = 0; + Boolean isDisplay = null; + String name; + + DeviceInfo(String address, int rssi) { + this.address = address; + this.rssi = rssi; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + DeviceInfo that = (DeviceInfo) o; + + return address.equals(that.address); + } + + @Override + public int hashCode() { + return address.hashCode(); + } + + public void update(Intent intent) { + if (intent.hasExtra(IntentExtra.DEVICE_IS_DISPLAY.name())) { + isDisplay = intent.getBooleanExtra(IntentExtra.DEVICE_IS_DISPLAY.name(), false); + } + if (intent.hasExtra(IntentExtra.RSSI.name())) { + rssi = intent.getIntExtra(IntentExtra.RSSI.name(), 0); + } + if (intent.hasExtra(IntentExtra.DEVICE_NAME.name())) { + name = intent.getStringExtra(IntentExtra.DEVICE_NAME.name()); + } + } + } +} diff --git a/app/src/main/java/no/topi/fiken/display/ExceptionHandler.java b/app/src/main/java/no/topi/fiken/display/ExceptionHandler.java new file mode 100644 index 0000000..3d4560b --- /dev/null +++ b/app/src/main/java/no/topi/fiken/display/ExceptionHandler.java @@ -0,0 +1,22 @@ +package no.topi.fiken.display; + +import android.util.Log; + +public class ExceptionHandler implements Thread.UncaughtExceptionHandler { + private final static String TAG = DefaultDisplayService.class.getSimpleName(); + + public static final ExceptionHandler EXCEPTION_HANDLER = new ExceptionHandler(); + + @Override + public void uncaughtException(Thread thread, Throwable ex) { + Log.e(TAG, "Uncaught", ex); + + if (ex instanceof RuntimeException) { + throw (RuntimeException) ex; + } + if (ex instanceof Error) { + throw (Error) ex; + } + throw new RuntimeException(ex); + } +} diff --git a/app/src/main/java/no/topi/fiken/display/MainActivity.java b/app/src/main/java/no/topi/fiken/display/MainActivity.java new file mode 100644 index 0000000..d9dc073 --- /dev/null +++ b/app/src/main/java/no/topi/fiken/display/MainActivity.java @@ -0,0 +1,335 @@ +package no.topi.fiken.display; + +import android.app.ActionBar; +import android.app.Activity; +import android.app.ListActivity; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.ArrayList; +import java.util.List; + +import static java.lang.String.valueOf; +import static no.topi.fiken.display.DisplayService.IntentAction; +import static no.topi.fiken.display.DisplayService.IntentExtra; +import static no.topi.fiken.display.ExceptionHandler.EXCEPTION_HANDLER; + +public class MainActivity extends ListActivity { + private final static String TAG = MainActivity.class.getSimpleName(); + + // Stops scanning after 10 seconds. + private static final long SCAN_PERIOD = 3 * 1000; + + private static final int REQUEST_ENABLE_BT = 1; + + private DisplayListAdapter displayList; + private Handler handler; + private BluetoothAdapter mBluetoothAdapter; + private boolean mScanning; + private DisplayService displayService; + private String deviceToShow; + + @Override + protected void onCreate(Bundle savedInstanceState) { + Log.i(TAG, "onCreate"); + Thread.setDefaultUncaughtExceptionHandler(EXCEPTION_HANDLER); + super.onCreate(savedInstanceState); + + ActionBar actionBar = getActionBar(); + if (actionBar != null) { + actionBar.setTitle(R.string.title_devices); + } + handler = new Handler(); + + // Use this check to determine whether BLE is supported on the device. Then you can + // selectively disable BLE-related features. + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.ble_not_supported, Toast.LENGTH_SHORT).show(); + finish(); + } + + // Initializes a Bluetooth adapter. For API level 18 and above, get a reference to + // BluetoothAdapter through BluetoothManager. + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = bluetoothManager.getAdapter(); + + // Checks if Bluetooth is supported on the device. + if (mBluetoothAdapter == null) { + Toast.makeText(this, R.string.error_bluetooth_not_supported, Toast.LENGTH_SHORT).show(); + finish(); + } + + ServiceConnection serviceConnection = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName componentName, IBinder service) { + displayService = ((DisplayService.LocalBinder) service).getService(); + if (!displayService.initialize()) { + finish(); + } + + startScan(); + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + stopScan(); + displayService = null; + } + }; + + Intent displayServiceIntent = new Intent(this, DefaultDisplayService.class); + bindService(displayServiceIntent, serviceConnection, BIND_AUTO_CREATE); + } + + @Override + protected void onResume() { + Log.i(TAG, "onResume"); + + super.onResume(); + + // Ensures Bluetooth is enabled on the device. If Bluetooth is not currently enabled, + // fire an intent to display a dialog asking the user to grant permission to enable it. + if (!mBluetoothAdapter.isEnabled()) { + Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); + } + + registerReceiver(displayServiceBroadcastReceiver, IntentAction.ALL_FILTER); + } + + @Override + protected void onPause() { + Log.i(TAG, "onPause"); + + super.onPause(); + stopScan(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + Log.i(TAG, "onActivityResult"); + + // User chose not to enable Bluetooth. + if (requestCode == REQUEST_ENABLE_BT && resultCode == Activity.RESULT_CANCELED) { + finish(); + return; + } + + super.onActivityResult(requestCode, resultCode, data); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + Log.i(TAG, "onCreateOptionsMenu"); + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + + if (!mScanning) { + menu.findItem(R.id.menu_stop).setVisible(false); + menu.findItem(R.id.menu_scan).setVisible(true); + menu.findItem(R.id.menu_refresh).setActionView(null); + } else { + menu.findItem(R.id.menu_stop).setVisible(true); + menu.findItem(R.id.menu_scan).setVisible(false); + menu.findItem(R.id.menu_refresh).setActionView(R.layout.actionbar_indeterminate_progress); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + Log.i(TAG, "onOptionsItemSelected"); + + switch (item.getItemId()) { + case R.id.menu_scan: + startScan(); + break; + case R.id.menu_stop: + stopScan(); + break; + } + return super.onOptionsItemSelected(item); + } + + private void startScan() { + displayList = new DisplayListAdapter(); + setListAdapter(displayList); + + displayService.startScan(); + + // Stops scanning after a pre-defined scan period. + handler.postDelayed(new Runnable() { + @Override + public void run() { + displayService.stopScan(); + invalidateOptionsMenu(); + } + }, SCAN_PERIOD); + } + + private void stopScan() { + if (displayService != null) { + displayService.stopScan(); + } + } + + @Override + protected void onListItemClick(ListView l, View v, int position, long id) { + stopScan(); + + DisplayService.DeviceInfo state = displayList.getDevice(position); + + if (!displayService.connect(state.address)) { + Toast.makeText(this, "Could not connect to " + state.address, Toast.LENGTH_SHORT).show(); + } else { + deviceToShow = state.address; + } + } + + private final BroadcastReceiver displayServiceBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + runOnUiThread(new Runnable() { + @Override + public void run() { + IntentAction action = IntentAction.valueOf(intent); + + String deviceAddress = intent.getStringExtra(IntentExtra.DEVICE_ADDRESS.name()); + + if (action == IntentAction.DEVICE_UPDATE && deviceAddress != null) { + DisplayService.DeviceInfo device = displayList.getDevice(deviceAddress, true); + + device.update(intent); + + if (intent.hasExtra(IntentExtra.CONNECTED.name())) { + boolean connected = intent.getBooleanExtra(IntentExtra.CONNECTED.name(), false); + + if (connected) { + if (deviceToShow != null && deviceToShow.equals(device.address)) { + Log.i(TAG, "connected to " + deviceToShow); + final Intent intent = new Intent(context, DisplayControlActivity.class); + intent.putExtra(IntentExtra.DEVICE_ADDRESS.name(), device.address); + intent.putExtra(IntentExtra.DEVICE_NAME.name(), device.name); + startActivity(intent); + } + } + } + displayList.notifyDataSetChanged(); + } + + if (intent.hasExtra(IntentExtra.SCANNING.name())) { + mScanning = intent.getBooleanExtra(IntentExtra.SCANNING.name(), false); + invalidateOptionsMenu(); + } + } + }); + } + }; + + static class ViewHolder { + final TextView deviceName; + final TextView deviceAddress; + final TextView rssi; + final TextView isDisplay; + + ViewHolder(TextView deviceName, TextView deviceAddress, TextView rssi, TextView isDisplay) { + this.deviceName = deviceName; + this.deviceAddress = deviceAddress; + this.rssi = rssi; + this.isDisplay = isDisplay; + } + } + + private class DisplayListAdapter extends BaseAdapter { + private List<DisplayService.DeviceInfo> devices = new ArrayList<DisplayService.DeviceInfo>(); + private LayoutInflater inflater = MainActivity.this.getLayoutInflater(); + + public DisplayService.DeviceInfo getDevice(int position) { + return devices.get(position); + } + + public DisplayService.DeviceInfo getDevice(String address, boolean create) { + for (DisplayService.DeviceInfo device : devices) { + if (device.address.equals(address)) { + return device; + } + } + + DisplayService.DeviceInfo deviceInfo = null; + if (create) { + deviceInfo = new DisplayService.DeviceInfo(address, 0); + devices.add(deviceInfo); + } + return deviceInfo; + } + + @Override + public int getCount() { + return devices.size(); + } + + @Override + public Object getItem(int i) { + return devices.get(i); + } + + @Override + public long getItemId(int i) { + return i; + } + + @Override + public View getView(int i, View view, ViewGroup viewGroup) { + ViewHolder viewHolder; + + if (view == null) { + view = inflater.inflate(R.layout.listitem_device, null); + viewHolder = new ViewHolder( + (TextView) view.findViewById(R.id.device_name), + (TextView) view.findViewById(R.id.device_address), + (TextView) view.findViewById(R.id.device_rssi), + (TextView) view.findViewById(R.id.device_isDisplay)); + view.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) view.getTag(); + } + + DisplayService.DeviceInfo state = devices.get(i); + if (state.name != null && state.name.length() > 0) { + viewHolder.deviceName.setText(state.name); + } else { + viewHolder.deviceName.setText(R.string.unknown_device); + } + viewHolder.deviceAddress.setText(state.address); + + viewHolder.rssi.setText(getText(R.string.rssi) + ": " + + (state.rssi != 0 ? valueOf(state.rssi) : getText(R.string.rssi_unknown))); + + viewHolder.isDisplay.setText("Is display: " + + (state.isDisplay != null ? state.isDisplay : "unknown")); + view.setClickable(state.isDisplay != null && state.isDisplay); + + return view; + } + } +} |