summaryrefslogtreecommitdiff
path: root/app/src
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2015-01-04 11:12:12 +0100
committerTrygve Laugstøl <trygvis@inamo.no>2015-01-04 11:12:12 +0100
commit1b9a4defe73f3aa8c10aa4af49002f0cebd1c292 (patch)
tree3a6b5bdae9eb6e35fd024bb5d3f7da6dbd2b0732 /app/src
parente8a052fd2c03b399550b6c9be3199d35fdd47f10 (diff)
downloadio.trygvis.soilmoisture-android-1b9a4defe73f3aa8c10aa4af49002f0cebd1c292.tar.gz
io.trygvis.soilmoisture-android-1b9a4defe73f3aa8c10aa4af49002f0cebd1c292.tar.bz2
io.trygvis.soilmoisture-android-1b9a4defe73f3aa8c10aa4af49002f0cebd1c292.tar.xz
io.trygvis.soilmoisture-android-1b9a4defe73f3aa8c10aa4af49002f0cebd1c292.zip
o Adding SoilMonitors support in core and view. Still more to do.
Diffstat (limited to 'app/src')
-rw-r--r--app/src/main/AndroidManifest.xml2
-rw-r--r--app/src/main/java/io/trygvis/android/bt/DefaultBtService.java4
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/DefaultSoilMoistureService.java (renamed from app/src/main/java/io/trygvis/soilmoisture/DefaultSmDevicesManager.java)42
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/MainActivity.java234
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/SmDevice.java11
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/SoilMoistureService.java (renamed from app/src/main/java/io/trygvis/soilmoisture/SmDevicesManager.java)10
-rw-r--r--app/src/main/java/io/trygvis/soilmoisture/SoilMonitor.java35
-rw-r--r--app/src/main/res/layout/main.xml15
-rw-r--r--app/src/main/res/menu/gatt_services.xml29
-rw-r--r--app/src/main/res/menu/main.xml37
-rw-r--r--app/src/main/res/menu/menu_main.xml5
-rw-r--r--app/src/main/res/values/strings.xml2
12 files changed, 298 insertions, 128 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 91cd1b2..500bd8d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -47,7 +47,7 @@
</service>
<service
- android:name=".DefaultSmDevicesManager"
+ android:name=".DefaultSoilMoistureService"
android:enabled="true"
android:exported="false">
</service>
diff --git a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java
index 5e13a1f..3c14c1f 100644
--- a/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java
+++ b/app/src/main/java/io/trygvis/android/bt/DefaultBtService.java
@@ -179,6 +179,10 @@ public class DefaultBtService<A extends BtDevice.BtDeviceWrapper<A>> extends Ser
return binder;
}
+ /**
+ * TODO: move this to initialize or somewhere it can be called so it doesn't block the UI
+ * thread.
+ */
@Override
public void onCreate() {
Bundle data;
diff --git a/app/src/main/java/io/trygvis/soilmoisture/DefaultSmDevicesManager.java b/app/src/main/java/io/trygvis/soilmoisture/DefaultSoilMoistureService.java
index 301bfc7..8a36476 100644
--- a/app/src/main/java/io/trygvis/soilmoisture/DefaultSmDevicesManager.java
+++ b/app/src/main/java/io/trygvis/soilmoisture/DefaultSoilMoistureService.java
@@ -25,19 +25,18 @@ import io.trygvis.bluetooth.TrygvisIoUuids;
import static io.trygvis.android.bt.BtService.BtServiceListenerBroadcastReceiver;
-public class DefaultSmDevicesManager extends Service implements SmDevicesManager {
- private final static String TAG = DefaultSmDevicesManager.class.getSimpleName();
+public class DefaultSoilMoistureService extends Service implements SoilMoistureService {
+ private final static String TAG = DefaultSoilMoistureService.class.getSimpleName();
private final IBinder binder = new LocalBinder<>(this);
@SuppressWarnings("UnusedDeclaration")
- private final DefaultSmDevicesManager context = DefaultSmDevicesManager.this;
+ private final DefaultSoilMoistureService context = DefaultSoilMoistureService.this;
private ServiceConnection serviceConnection;
private BtService<SmDevice> btService;
-
@Override
public IBinder onBind(Intent intent) {
return binder;
@@ -52,7 +51,7 @@ public class DefaultSmDevicesManager extends Service implements SmDevicesManager
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
btService = ((LocalBinder<BtService<SmDevice>>) service).getService();
- boolean ok = btService.initialize(DefaultSmDevicesManager.this::onNewDevice);
+ boolean ok = btService.initialize(DefaultSoilMoistureService.this::onNewDevice);
sendBroadcast(createReady(ok));
}
@@ -111,25 +110,20 @@ public class DefaultSmDevicesManager extends Service implements SmDevicesManager
BluetoothGattService service = gatt.getService(TrygvisIoUuids.Services.SOIL_MOISTURE_SERVICE);
- if (service == null) {
- smDevice.setIsUseful(false);
- return false;
- }
+ boolean useful = false;
+ if (service != null) {
+ BluetoothGattCharacteristic characteristic = service.getCharacteristic(TrygvisIoUuids.Characteristics.SOIL_MOISTURE);
- BluetoothGattCharacteristic characteristic = service.getCharacteristic(TrygvisIoUuids.Characteristics.SOIL_MOISTURE);
+ useful = characteristic != null;
- if (characteristic == null) {
- smDevice.setIsUseful(false);
- return false;
+ smDevice.setIsUseful(useful);
}
- smDevice.setIsUseful(true);
- sendBroadcast(createNewDevice(address));
-
gatt.disconnect();
- return true;
- });
+ return false;
+ }).
+ onFinally(() -> sendBroadcast(createNewDevice(address)));
btDevice.connect(executor);
} else {
@@ -172,7 +166,7 @@ public class DefaultSmDevicesManager extends Service implements SmDevicesManager
}
// -----------------------------------------------------------------------
- //
+ // Event creation and dispatching
// -----------------------------------------------------------------------
private SmDevice onNewDevice(BtDevice<SmDevice> btDevice) {
@@ -180,28 +174,28 @@ public class DefaultSmDevicesManager extends Service implements SmDevicesManager
}
private Intent createReady(boolean success) {
- return new Intent(SmDeviceListener.INTENT_NAME).
+ return new Intent(SoilMoistureListener.INTENT_NAME).
putExtra("event", "ready").
putExtra("success", success);
}
private Intent createScanStarted() {
- return new Intent(SmDeviceListener.INTENT_NAME).
+ return new Intent(SoilMoistureListener.INTENT_NAME).
putExtra("event", "scanStarted");
}
private Intent createScanStopped() {
- return new Intent(SmDeviceListener.INTENT_NAME).
+ return new Intent(SoilMoistureListener.INTENT_NAME).
putExtra("event", "scanStopped");
}
private Intent createNewDevice(String address) {
- return new Intent(SmDeviceListener.INTENT_NAME).
+ return new Intent(SoilMoistureListener.INTENT_NAME).
putExtra("event", "newDevice").
putExtra("address", address);
}
- public static void dispatchEvent(Intent intent, SmDeviceListener listener) {
+ public static void dispatchEvent(Intent intent, SoilMoistureListener listener) {
String event = intent.getStringExtra("event");
Log.i(TAG, "Dispatching event " + intent.getAction() + "/" + event);
switch (event) {
diff --git a/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java b/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java
index 6adc96c..64e8202 100644
--- a/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java
+++ b/app/src/main/java/io/trygvis/soilmoisture/MainActivity.java
@@ -6,6 +6,8 @@ import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.database.DataSetObservable;
+import android.database.DataSetObserver;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
@@ -14,8 +16,8 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.BaseAdapter;
import android.widget.Button;
+import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -31,7 +33,7 @@ import io.trygvis.android.LocalBinder;
import io.trygvis.android.bt.BtActivitySupport;
import static io.trygvis.soilmoisture.ExceptionHandler.EXCEPTION_HANDLER;
-import static io.trygvis.soilmoisture.SmDevicesManager.SmDeviceListener;
+import static io.trygvis.soilmoisture.SoilMoistureService.SoilMoistureListener;
import static java.lang.String.valueOf;
public class MainActivity extends ListActivity {
@@ -42,12 +44,12 @@ public class MainActivity extends ListActivity {
private static final int REQUEST_ENABLE_BT = 1;
private final BtActivitySupport btActivitySupport = new BtActivitySupport(this, REQUEST_ENABLE_BT);
- private final SmDeviceListener serviceListener = new MySmDeviceListener();
+ private final SoilMoistureListener serviceListener = new MySoilMoistureListener();
private final MainActivity context = this;
private DeviceListAdapter deviceList;
private ServiceConnection serviceConnection;
- private SmDevicesManager smDevicesManager;
+ private SoilMoistureService soilMoistureService;
private ProgressDialog initializing;
private boolean ready;
@@ -73,22 +75,24 @@ public class MainActivity extends ListActivity {
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
Log.i(TAG, "onServiceConnected");
- smDevicesManager = ((LocalBinder<SmDevicesManager>) service).getService();
- registerReceiver(serviceListener, SmDeviceListener.INTENT_FILTER);
+ soilMoistureService = ((LocalBinder<SoilMoistureService>) service).getService();
+ registerReceiver(serviceListener, SoilMoistureListener.INTENT_FILTER);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
Log.i(TAG, "onServiceDisconnected");
- smDevicesManager = null;
+ soilMoistureService = null;
stopScan();
}
};
- bindService(new Intent(this, DefaultSmDevicesManager.class), serviceConnection, BIND_AUTO_CREATE);
+ bindService(new Intent(this, DefaultSoilMoistureService.class), serviceConnection, BIND_AUTO_CREATE);
initializing = ProgressDialog.
show(this, "Initializing", "Connecting to Bluetooth system.", true);
+
+ setContentView(R.layout.main);
}
@Override
@@ -112,7 +116,7 @@ public class MainActivity extends ListActivity {
return;
}
- registerReceiver(serviceListener, SmDeviceListener.INTENT_FILTER);
+ registerReceiver(serviceListener, SoilMoistureListener.INTENT_FILTER);
}
@Override
@@ -141,20 +145,30 @@ public class MainActivity extends ListActivity {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
+ MenuItem stop = menu.findItem(R.id.menu_stop);
+ MenuItem scan = menu.findItem(R.id.menu_scan);
+ MenuItem refresh = menu.findItem(R.id.menu_refresh);
+ MenuItem showAll = menu.findItem(R.id.menu_show_all);
+ MenuItem groupByDevice = menu.findItem(R.id.menu_group_by_device);
+
if (ready) {
- if (!smDevicesManager.isScanning()) {
- menu.findItem(R.id.menu_stop).setVisible(false);
- menu.findItem(R.id.menu_scan).setVisible(true);
- menu.findItem(R.id.menu_refresh).setActionView(null);
+ if (!soilMoistureService.isScanning()) {
+ stop.setVisible(false);
+ scan.setVisible(true);
+ 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);
+ stop.setVisible(true);
+ scan.setVisible(false);
+ refresh.setActionView(R.layout.actionbar_indeterminate_progress);
}
+ showAll.setChecked(deviceList.isShowAll());
+ groupByDevice.setChecked(deviceList.isGroupByDevice());
} else {
- menu.findItem(R.id.menu_stop).setVisible(false);
- menu.findItem(R.id.menu_scan).setVisible(true);
- menu.findItem(R.id.menu_refresh).setActionView(null);
+ stop.setVisible(false);
+ scan.setVisible(true);
+ refresh.setActionView(null);
+ showAll.setVisible(false);
+ groupByDevice.setVisible(false);
}
return true;
}
@@ -163,6 +177,7 @@ public class MainActivity extends ListActivity {
public boolean onOptionsItemSelected(MenuItem item) {
Log.i(TAG, "onOptionsItemSelected");
+ boolean consumed = true;
switch (item.getItemId()) {
case R.id.menu_scan:
startScan();
@@ -170,39 +185,47 @@ public class MainActivity extends ListActivity {
case R.id.menu_stop:
stopScan();
break;
+ case R.id.menu_show_all:
+ item.setChecked(!item.isChecked());
+ deviceList.setShowAll(item.isChecked());
+ break;
+ case R.id.menu_group_by_device:
+ item.setChecked(!item.isChecked());
+ deviceList.setGroupByDevice(item.isChecked());
+ break;
+ default:
+ consumed = super.onOptionsItemSelected(item);
}
- return super.onOptionsItemSelected(item);
+ return consumed;
}
private void startScan() {
- smDevicesManager.startScanning(SCAN_PERIOD);
+ soilMoistureService.startScanning(SCAN_PERIOD);
}
private void stopScan() {
- if (smDevicesManager != null) {
- smDevicesManager.stopScanning();
+ if (soilMoistureService != null) {
+ soilMoistureService.stopScanning();
}
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
stopScan();
-
-// SmDevice state = smDevicesManager.getDevices(SmDevice.deviceComparator).get(position);
}
// -----------------------------------------------------------------------
//
// -----------------------------------------------------------------------
- static class DeviceListItem {
+ static class DeviceItem {
final TextView deviceName;
final TextView deviceAddress;
final TextView rssi;
final ProgressBar spinner;
final Button connect;
- DeviceListItem(View view) {
+ DeviceItem(View view) {
this.deviceName = (TextView) view.findViewById(R.id.device_name);
this.deviceAddress = (TextView) view.findViewById(R.id.device_address);
this.rssi = (TextView) view.findViewById(R.id.device_rssi);
@@ -211,39 +234,162 @@ public class MainActivity extends ListActivity {
}
}
- private class DeviceListAdapter extends BaseAdapter {
+ private class DeviceListAdapter implements ListAdapter {
+ private final DataSetObservable dataSetObservable = new DataSetObservable();
private List<SmDevice> devices = new ArrayList<>();
+ private List<Object> current = new ArrayList<>();
private LayoutInflater inflater = MainActivity.this.getLayoutInflater();
+ private boolean groupByDevice = true;
+ private boolean showAll = false;
+
+ public void sort() {
+ Log.i(TAG, "sort(), groupByDevice=" + groupByDevice + ", showAll=" + showAll);
+ current = new ArrayList<>();
+
+ List<SmDevice> usefulDevices = new ArrayList<>(devices.size());
+ List<SmDevice> unusefulDevices = new ArrayList<>(devices.size());
+ for (SmDevice d : devices) {
+ (d.isUseful() ? usefulDevices : unusefulDevices).add(d);
+ }
+ List<SoilMonitor> monitors = new ArrayList<>();
+ for (SmDevice d : devices) {
+ monitors.addAll(d.getMonitors());
+ }
+
+ if (groupByDevice) {
+ current.addAll(usefulDevices);
+ if (showAll) {
+ current.addAll(unusefulDevices);
+ }
+ } else {
+ current.addAll(monitors);
+ }
+ dataSetObservable.notifyChanged();
+ }
+
+ public void notifyDataSetChanged() {
+ dataSetObservable.notifyChanged();
+ }
+
+ public void setShowAll(boolean showAll) {
+ if (showAll == this.showAll) {
+ return;
+ }
+
+ this.showAll = showAll;
+ sort();
+ }
+
+ public boolean isShowAll() {
+ return showAll;
+ }
+
+ public void setGroupByDevice(boolean groupByDevice) {
+ if (groupByDevice == this.groupByDevice) {
+ return;
+ }
+
+ this.groupByDevice = groupByDevice;
+ sort();
+ }
+
+ public boolean isGroupByDevice() {
+ return groupByDevice;
+ }
+
+ // -----------------------------------------------------------------------
+ // ListAdapter Implementation
+ // -----------------------------------------------------------------------
+
+ @Override
+ public void registerDataSetObserver(DataSetObserver observer) {
+ dataSetObservable.registerObserver(observer);
+ }
+
+ @Override
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+ dataSetObservable.unregisterObserver(observer);
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return true;
+ }
+
+ @Override
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ Object o = current.get(position);
+
+ if (o instanceof SmDevice) {
+ return 0;
+ } else if (o instanceof SoilMonitor) {
+ return 1;
+ }
+
+ throw new RuntimeException("Unknown kind: " + o.getClass());
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 2;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return current.isEmpty();
+ }
+
@Override
public int getCount() {
- return devices.size();
+ return current.size();
}
@Override
- public SmDevice getItem(int i) {
- return devices.get(i);
+ public Object getItem(int position) {
+ return current.get(position);
}
@Override
- public long getItemId(int i) {
- return i;
+ public long getItemId(int position) {
+ return position;
}
@Override
- public View getView(int i, View view, ViewGroup viewGroup) {
- DeviceListItem item;
+ public View getView(int position, View view, ViewGroup viewGroup) {
+ Object o = current.get(position);
+ if (o instanceof SmDevice) {
+ return getSmDeviceView((SmDevice) o, view);
+ } else if (o instanceof SoilMonitor) {
+ return getSoilMonitorView((SoilMonitor) o, view);
+ }
+
+ throw new RuntimeException("Not implemented");
+ }
+
+ private View getSmDeviceView(SmDevice smDevice, View view) {
+
+ DeviceItem item;
if (view == null) {
view = inflater.inflate(R.layout.listitem_device, null);
- item = new DeviceListItem(view);
+ item = new DeviceItem(view);
view.setTag(item);
view.setClickable(false);
} else {
- item = (DeviceListItem) view.getTag();
+ item = (DeviceItem) view.getTag();
}
- SmDevice smDevice = getItem(i);
if (smDevice.getName() != null) {
item.deviceName.setText(smDevice.getName());
} else {
@@ -261,9 +407,13 @@ public class MainActivity extends ListActivity {
return view;
}
+
+ private View getSoilMonitorView(SoilMonitor soilMonitor, View view) {
+ throw new RuntimeException("Not implemented");
+ }
}
- private class MySmDeviceListener extends SmDeviceListener {
+ private class MySoilMoistureListener extends SoilMoistureListener {
@Override
public void onReady(boolean ok) {
if (!ok) {
@@ -297,11 +447,9 @@ public class MainActivity extends ListActivity {
@Override
public void onNewDevice(String address) {
- SmDevice device = smDevicesManager.getDevice(address);
+ SmDevice device = soilMoistureService.getDevice(address);
deviceList.devices.add(device);
- deviceList.notifyDataSetInvalidated();
-
- Log.i(TAG, "deviceList.devices.size() = " + deviceList.devices.size());
+ deviceList.sort();
}
}
}
diff --git a/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java b/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java
index 1ed7ecb..169f4b3 100644
--- a/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java
+++ b/app/src/main/java/io/trygvis/soilmoisture/SmDevice.java
@@ -2,13 +2,12 @@ package io.trygvis.soilmoisture;
import android.util.Log;
-import java.util.Comparator;
+import java.util.ArrayList;
+import java.util.List;
import io.trygvis.android.bt.BtDevice;
class SmDevice implements BtDevice.BtDeviceWrapper<SmDevice> {
- public static final Comparator<SmDevice> deviceComparator = (a, b) -> a.getBtDevice().getAddress().compareTo(b.getBtDevice().getAddress());
-
private final static String TAG = SmDevice.class.getSimpleName();
private final BtDevice<SmDevice> btDevice;
@@ -17,6 +16,8 @@ class SmDevice implements BtDevice.BtDeviceWrapper<SmDevice> {
private Boolean isUseful;
+ private List<SoilMonitor> monitors = new ArrayList<>();
+
public SmDevice(BtDevice<SmDevice> btDevice) {
this.btDevice = btDevice;
Log.i(TAG, "new device");
@@ -52,4 +53,8 @@ class SmDevice implements BtDevice.BtDeviceWrapper<SmDevice> {
public String getName() {
return name;
}
+
+ public List<SoilMonitor> getMonitors() {
+ return monitors;
+ }
}
diff --git a/app/src/main/java/io/trygvis/soilmoisture/SmDevicesManager.java b/app/src/main/java/io/trygvis/soilmoisture/SoilMoistureService.java
index 531061a..8100649 100644
--- a/app/src/main/java/io/trygvis/soilmoisture/SmDevicesManager.java
+++ b/app/src/main/java/io/trygvis/soilmoisture/SoilMoistureService.java
@@ -8,9 +8,7 @@ import android.content.IntentFilter;
import java.util.Comparator;
import java.util.List;
-import io.trygvis.android.bt.BtDevice;
-
-public interface SmDevicesManager {
+public interface SoilMoistureService {
List<SmDevice> getDevices(Comparator<SmDevice> comparator);
SmDevice getDevice(String address);
@@ -21,9 +19,9 @@ public interface SmDevicesManager {
void stopScanning();
- public abstract static class SmDeviceListener extends BroadcastReceiver {
+ public abstract static class SoilMoistureListener extends BroadcastReceiver {
- public static final String INTENT_NAME = SmDeviceListener.class.getName();
+ public static final String INTENT_NAME = SoilMoistureListener.class.getName();
public static final IntentFilter INTENT_FILTER = new IntentFilter(INTENT_NAME);
@@ -32,7 +30,7 @@ public interface SmDevicesManager {
return;
}
- DefaultSmDevicesManager.dispatchEvent(intent, this);
+ DefaultSoilMoistureService.dispatchEvent(intent, this);
}
public void onReady(boolean ok) {
diff --git a/app/src/main/java/io/trygvis/soilmoisture/SoilMonitor.java b/app/src/main/java/io/trygvis/soilmoisture/SoilMonitor.java
new file mode 100644
index 0000000..564202d
--- /dev/null
+++ b/app/src/main/java/io/trygvis/soilmoisture/SoilMonitor.java
@@ -0,0 +1,35 @@
+package io.trygvis.soilmoisture;
+
+import java.util.Date;
+
+class SoilMonitor {
+ private final SmDevice device;
+
+ private Date timestamp;
+
+ private int lastValue;
+
+ SoilMonitor(SmDevice device) {
+ this.device = device;
+ }
+
+ public SmDevice getDevice() {
+ return device;
+ }
+
+ public int getLastValue() {
+ return lastValue;
+ }
+
+ public void setLastValue(int lastValue) {
+ this.lastValue = lastValue;
+ }
+
+ public Date getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(Date timestamp) {
+ this.timestamp = timestamp;
+ }
+}
diff --git a/app/src/main/res/layout/main.xml b/app/src/main/res/layout/main.xml
new file mode 100644
index 0000000..c96edfd
--- /dev/null
+++ b/app/src/main/res/layout/main.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp">
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"/>
+
+</LinearLayout>
diff --git a/app/src/main/res/menu/gatt_services.xml b/app/src/main/res/menu/gatt_services.xml
deleted file mode 100644
index 25d64b6..0000000
--- a/app/src/main/res/menu/gatt_services.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:id="@+id/menu_refresh"
- android:checkable="false"
- android:orderInCategory="1"
- android:showAsAction="ifRoom"/>
- <item android:id="@+id/menu_connect"
- android:title="@string/menu_connect"
- android:orderInCategory="100"
- android:showAsAction="ifRoom|withText"/>
- <item android:id="@+id/menu_disconnect"
- android:title="@string/menu_disconnect"
- android:orderInCategory="101"
- android:showAsAction="ifRoom|withText"/>
-</menu> \ No newline at end of file
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
index 08b604e..2272040 100644
--- a/app/src/main/res/menu/main.xml
+++ b/app/src/main/res/menu/main.xml
@@ -1,29 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/menu_refresh"
android:checkable="false"
android:orderInCategory="1"
android:showAsAction="ifRoom"/>
- <item android:id="@+id/menu_scan"
+
+ <item
+ android:id="@+id/menu_scan"
android:title="@string/menu_scan"
android:orderInCategory="100"
android:showAsAction="ifRoom|withText"/>
- <item android:id="@+id/menu_stop"
+
+ <item
+ android:id="@+id/menu_stop"
android:title="@string/menu_stop"
android:orderInCategory="101"
android:showAsAction="ifRoom|withText"/>
-</menu> \ No newline at end of file
+
+ <item
+ android:id="@+id/menu_group_by_device"
+ android:title="@string/group_by_device"
+ android:orderInCategory="140"
+ android:checkable="true"/>
+
+ <item
+ android:id="@+id/menu_show_all"
+ android:title="@string/show_all"
+ android:orderInCategory="150"
+ android:checkable="true"/>
+
+</menu>
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
deleted file mode 100644
index 87a750e..0000000
--- a/app/src/main/res/menu/menu_main.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
- <item android:id="@+id/action_settings" android:title="@string/action_settings"
- android:orderInCategory="100" android:showAsAction="never" />
-</menu>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 8aa5e33..0764a26 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -31,5 +31,7 @@
<string name="title_name">Name</string>
<string name="refresh">Refresh</string>
<string name="current_value">Current value</string>
+ <string name="show_all">Show all</string>
+ <string name="group_by_device">Group by device</string>
</resources>