This commit is contained in:
Harald Hoyer 2017-04-27 08:21:38 +02:00
parent a6f81f2ac8
commit d2e60c858f
9 changed files with 356 additions and 83 deletions

View file

@ -106,6 +106,8 @@
</content> </content>
<orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" /> <orderEntry type="jdk" jdkName="Android API 25 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="constraint-layout-solver-1.0.2" level="project" />
<orderEntry type="library" exported="" name="constraint-layout-1.0.2" level="project" />
<orderEntry type="library" exported="" name="support-core-ui-25.3.1" level="project" /> <orderEntry type="library" exported="" name="support-core-ui-25.3.1" level="project" />
<orderEntry type="library" exported="" name="cardview-v7-25.3.1" level="project" /> <orderEntry type="library" exported="" name="cardview-v7-25.3.1" level="project" />
<orderEntry type="library" exported="" name="support-v4-25.3.1" level="project" /> <orderEntry type="library" exported="" name="support-v4-25.3.1" level="project" />

View file

@ -20,6 +20,7 @@ dependencies {
compile "com.android.support:cardview-v7:25.3.1" compile "com.android.support:cardview-v7:25.3.1"
compile "com.android.support:appcompat-v7:25.3.1" compile "com.android.support:appcompat-v7:25.3.1"
compile 'com.android.support:support-v13:25.3.1' compile 'com.android.support:support-v13:25.3.1'
compile 'com.android.support.constraint:constraint-layout:1.0.2'
} }
// The sample build uses multiple directories to // The sample build uses multiple directories to
@ -35,7 +36,7 @@ android {
buildToolsVersion "25.0.2" buildToolsVersion "25.0.2"
defaultConfig { defaultConfig {
minSdkVersion 13 minSdkVersion 14
targetSdkVersion 25 targetSdkVersion 25
} }

View file

@ -39,6 +39,7 @@ import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ListView; import android.widget.ListView;
import android.widget.NumberPicker;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@ -60,11 +61,11 @@ public class BluetoothChatFragment extends Fragment {
private static final int REQUEST_ENABLE_BT = 3; private static final int REQUEST_ENABLE_BT = 3;
// Layout Views // Layout Views
private ListView mConversationView; //private ListView mConversationView;
private Button mStartButton; private Button mStartButton;
private Button mStopButton; private Button mStopButton;
private Button mDisconnectButton; private Button mDisconnectButton;
private NumberPicker mLevel;
/** /**
* Name of the connected device * Name of the connected device
*/ */
@ -72,8 +73,8 @@ public class BluetoothChatFragment extends Fragment {
/** /**
* Array adapter for the conversation thread * Array adapter for the conversation thread
*/
private ArrayAdapter<String> mConversationArrayAdapter; private ArrayAdapter<String> mConversationArrayAdapter;
*/
/** /**
* Local Bluetooth adapter * Local Bluetooth adapter
@ -147,10 +148,16 @@ public class BluetoothChatFragment extends Fragment {
@Override @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
mConversationView = (ListView) view.findViewById(R.id.in); //mConversationView = (ListView) view.findViewById(R.id.in);
mStartButton = (Button) view.findViewById(R.id.button_start); mStartButton = (Button) view.findViewById(R.id.button_start);
mStopButton = (Button) view.findViewById(R.id.button_stop); mStopButton = (Button) view.findViewById(R.id.button_stop);
mDisconnectButton = (Button) view.findViewById(R.id.button_disconnect); mDisconnectButton = (Button) view.findViewById(R.id.button_disconnect);
mLevel = (NumberPicker) view.findViewById(R.id.Level);
mLevel.setMaxValue(16);
mLevel.setMinValue(1);
mLevel.setValue(5);
mLevel.setWrapSelectorWheel(false);
mLevel.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
} }
/** /**
@ -158,11 +165,12 @@ public class BluetoothChatFragment extends Fragment {
*/ */
private void setupChat() { private void setupChat() {
Log.d(TAG, "setupChat()"); Log.d(TAG, "setupChat()");
/*
// Initialize the array adapter for the conversation thread // Initialize the array adapter for the conversation thread
mConversationArrayAdapter = new ArrayAdapter<>(getActivity(), R.layout.message); mConversationArrayAdapter = new ArrayAdapter<>(getActivity(), R.layout.message);
mConversationView.setAdapter(mConversationArrayAdapter); mConversationView.setAdapter(mConversationArrayAdapter);
*/
// Initialize the BluetoothChatService to perform bluetooth connections // Initialize the BluetoothChatService to perform bluetooth connections
mChatService = new BluetoothChatService(getActivity(), mHandler); mChatService = new BluetoothChatService(getActivity(), mHandler);
@ -263,7 +271,7 @@ public class BluetoothChatFragment extends Fragment {
switch (msg.arg1) { switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED: case BluetoothChatService.STATE_CONNECTED:
setStatus(getString(R.string.title_connected_to, mConnectedDeviceName)); setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
mConversationArrayAdapter.clear(); //mConversationArrayAdapter.clear();
mStartButton.setEnabled(true); mStartButton.setEnabled(true);
mStopButton.setEnabled(true); mStopButton.setEnabled(true);
mDisconnectButton.setEnabled(true); mDisconnectButton.setEnabled(true);
@ -285,22 +293,26 @@ public class BluetoothChatFragment extends Fragment {
break; break;
case Constants.MESSAGE_DATA: case Constants.MESSAGE_DATA:
IConsole.Data data = (IConsole.Data) msg.obj; IConsole.Data data = (IConsole.Data) msg.obj;
String dataMessage = String.format(Locale.US, "Time: %s Speed: %f Power: %f RPM: %d LVL: %d Dist: %f Cal: %d HF: %d", // FIXME
// insert text here
/*
String dataMessage = String.format(Locale.US, "Time: %d Speed: %3.1f Power: %3.1f RPM: %d LVL: %d Dist: %4.1f Cal: %d HF: %d",
data.mTime, data.mSpeed10 / 10.0, data.mPower10 / 10.0, data.mRPM, data.mTime, data.mSpeed10 / 10.0, data.mPower10 / 10.0, data.mRPM,
data.mLevel, data.mDistance10 / 10.0, data.mCalories, data.mHF); data.mLevel, data.mDistance10 / 10.0, data.mCalories, data.mHF);
mConversationArrayAdapter.add(mConnectedDeviceName + ": " + dataMessage); */
//mConversationArrayAdapter.add(mConnectedDeviceName + ": " + dataMessage);
break; break;
case Constants.MESSAGE_WRITE: case Constants.MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj; //byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer // construct a string from the buffer
String writeMessage = new String(writeBuf); //String writeMessage = new String(writeBuf);
mConversationArrayAdapter.add("Me: " + writeMessage); //mConversationArrayAdapter.add("Me: " + writeMessage);
break; break;
case Constants.MESSAGE_READ: case Constants.MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj; //byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer // construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1); //String readMessage = new String(readBuf, 0, msg.arg1);
mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage); //mConversationArrayAdapter.add(mConnectedDeviceName + ": " + readMessage);
break; break;
case Constants.MESSAGE_DEVICE_NAME: case Constants.MESSAGE_DEVICE_NAME:
// save the connected device's name // save the connected device's name

View file

@ -208,7 +208,7 @@ public class BluetoothChatService {
} }
public synchronized boolean stopIConsole() { public synchronized boolean stopIConsole() {
return mConnectedThread.startIConsole(); return mConnectedThread.stopIConsole();
} }
/** /**
@ -345,7 +345,7 @@ public class BluetoothChatService {
mmIConsole = new IConsole(mmInStream, mmOutStream, new IConsole.DataListener() { mmIConsole = new IConsole(mmInStream, mmOutStream, new IConsole.DataListener() {
@Override @Override
public void onData(IConsole.Data data) { public void onData(IConsole.Data data) {
Log.i(TAG, "mConnectedThread: onData"); //Log.i(TAG, "mConnectedThread: onData");
// Share the sent message back to the UI Activity // Share the sent message back to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_DATA, -1, -1, data) mHandler.obtainMessage(Constants.MESSAGE_DATA, -1, -1, data)
.sendToTarget(); .sendToTarget();
@ -358,11 +358,11 @@ public class BluetoothChatService {
if (e instanceof IOException) if (e instanceof IOException)
connectionLost(); connectionLost();
} }
}, new IConsole.DebugListener() { }, /* new IConsole.DebugListener() {
@Override @Override
public void onRead(byte[] buffer) { public void onRead(byte[] buffer) {
if (buffer.length > 0) { if (buffer.length > 0) {
String hexbuf = IConsole.byteArrayToHex(Arrays.copyOfRange(buffer, 0, buffer.length)); String hexbuf = IConsole.byteArrayToHex(buffer);
// Send the obtained bytes to the UI Activity // Send the obtained bytes to the UI Activity
mHandler.obtainMessage(Constants.MESSAGE_READ, hexbuf.length(), -1, hexbuf.getBytes()) mHandler.obtainMessage(Constants.MESSAGE_READ, hexbuf.length(), -1, hexbuf.getBytes())
@ -378,23 +378,24 @@ public class BluetoothChatService {
mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, hexbuf.getBytes()) mHandler.obtainMessage(Constants.MESSAGE_WRITE, -1, -1, hexbuf.getBytes())
.sendToTarget(); .sendToTarget();
} }
}); }*/ null);
} }
public void run() { public void run() {
Log.i(TAG, "BEGIN mConnectedThread"); Log.i(TAG, "BEGIN mConnectedThread");
mmIConsole.start();
while (mState == STATE_CONNECTED) { while (mState == STATE_CONNECTED) {
if (!mmIConsole.processIO()) if (!mmIConsole.processIO()) {
Log.i(TAG, "processIO = false");
break; break;
}
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
; // ignore ; // ignore
} }
} }
Log.i(TAG, "END mConnectedThread");
} }

View file

@ -4,13 +4,17 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import org.surfsite.iconsole.common.logger.Log;
/** /**
* Created by harald on 25.04.17. * Created by harald on 25.04.17.
*/ */
class IConsole { class IConsole {
private static final String TAG = "IConsole";
private static final byte[] PING = {(byte) 0xf0, (byte) 0xa0, (byte) 0x01, (byte) 0x01, (byte) 0x92 }; private static final byte[] PING = {(byte) 0xf0, (byte) 0xa0, (byte) 0x01, (byte) 0x01, (byte) 0x92 };
private static final byte[] INIT_A0 = {(byte) 0xf0, (byte) 0xa0, 0x02, 0x02, (byte) 0x94}; private static final byte[] INIT_A0 = {(byte) 0xf0, (byte) 0xa0, 0x02, 0x02, (byte) 0x94};
//private static final byte[] PONG = {(byte) 0xf0, (byte) 0xb0, 0x01, 0x01, (byte) 0xa2}; //private static final byte[] PONG = {(byte) 0xf0, (byte) 0xb0, 0x01, 0x01, (byte) 0xa2};
@ -126,7 +130,7 @@ class IConsole {
boolean send(byte[] packet, byte expect, int plen) throws IOException { boolean send(byte[] packet, byte expect, int plen) throws IOException {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if ((now - mTimesent) < 200) { if ((now - mTimesent) < ((mCurrentState == State.READ) ? 500 : 200)) {
return false; return false;
} }
@ -140,11 +144,12 @@ class IConsole {
// Send packet // Send packet
mOutputStream.write(packet); mOutputStream.write(packet);
if (null != mDataListener) if (null != mDebugListener)
mDebugListener.onWrite(packet); mDebugListener.onWrite(packet);
//Log.d(TAG, "sent: " + byteArrayToHex(packet));
mTimesent = System.currentTimeMillis(); mTimesent = System.currentTimeMillis();
mExpectPacket = packet; mExpectPacket = packet.clone();
mExpectPacket[1] = expect; mExpectPacket[1] = expect;
mExpectLen = plen; mExpectLen = plen;
mWaitAck = true; mWaitAck = true;
@ -172,18 +177,24 @@ class IConsole {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if ((now - mTimesent) > 1000000) { if ((now - mTimesent) > 10000) {
mWaitAck = false; mWaitAck = false;
return null; return null;
} }
if (mInputStream.available() < mExpectLen) if (mInputStream.available() < mExpectLen) {
//Log.d(TAG, String.format(Locale.US, "Avail: %d Expected: %d", mInputStream.available(), mExpectLen));
return null; return null;
}
bytes = mInputStream.read(buffer); bytes = mInputStream.read(buffer);
if (null != mDebugListener) if (null != mDebugListener) {
mDebugListener.onRead(Arrays.copyOfRange(buffer, 0, bytes)); mDebugListener.onRead(Arrays.copyOfRange(buffer, 0, bytes));
//Log.d(TAG, "wait ack got: " + byteArrayToHex(Arrays.copyOfRange(buffer, 0, bytes)));
}
//Log.d(TAG, "wait ack checking");
if (bytes != mExpectLen) { if (bytes != mExpectLen) {
throw new IOException("Wrong number of bytes read. Expected " + mExpectLen + ", got " + bytes); throw new IOException("Wrong number of bytes read. Expected " + mExpectLen + ", got " + bytes);
@ -197,13 +208,16 @@ class IConsole {
throw new IOException("Byte 1 wrong. Expected " + String.format("%02x", mExpectPacket[1]) + ", got " + String.format("%02x", buffer[1])); throw new IOException("Byte 1 wrong. Expected " + String.format("%02x", mExpectPacket[1]) + ", got " + String.format("%02x", buffer[1]));
} }
//Log.d(TAG, "wait ack success");
mWaitAck = false;
return buffer; return buffer;
} }
private boolean processIOSend() throws IOException { private boolean processIOSend() throws IOException {
switch (mCurrentState) { switch (mCurrentState) {
case BEGIN: case BEGIN:
mCurrentState = mNextState; send(PING);
break; break;
case PING: case PING:
send(PING); send(PING);
@ -230,7 +244,7 @@ class IConsole {
send(STOP); send(STOP);
break; break;
case READ: case READ:
send(READ); send(READ, 21);
break; break;
case SETLEVEL: case SETLEVEL:
send_level(mSetLevel); send_level(mSetLevel);
@ -242,8 +256,11 @@ class IConsole {
private boolean processIOAck() throws IOException, TimeoutException { private boolean processIOAck() throws IOException, TimeoutException {
byte[] got = null; byte[] got = null;
got = wait_ack(); got = wait_ack();
if (null == got) if (null == got) {
return true; return true;
}
//Log.d(TAG, "processIOAck next state");
if(mCurrentState == State.READ) if(mCurrentState == State.READ)
mDataListener.onData(new Data(got)); mDataListener.onData(new Data(got));
@ -288,14 +305,19 @@ class IConsole {
} }
boolean processIO() { boolean processIO() {
//Log.i(TAG, "Begin processIO");
synchronized (this) { synchronized (this) {
try { try {
if (!mWaitAck) { if (!mWaitAck) {
//Log.i(TAG, "processIOSend");
return processIOSend(); return processIOSend();
} else { } else {
//Log.i(TAG, "processIOAck");
return processIOAck(); return processIOAck();
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "processIO", e);
mDataListener.onError(e); mDataListener.onError(e);
return false; return false;
} }

View file

@ -74,6 +74,7 @@ public class MainActivity extends SampleActivityBase {
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
/*
switch(item.getItemId()) { switch(item.getItemId()) {
case R.id.menu_toggle_log: case R.id.menu_toggle_log:
mLogShown = !mLogShown; mLogShown = !mLogShown;
@ -86,6 +87,7 @@ public class MainActivity extends SampleActivityBase {
supportInvalidateOptionsMenu(); supportInvalidateOptionsMenu();
return true; return true;
} }
*/
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }

View file

@ -20,35 +20,19 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/sample_main_layout"> android:id="@+id/sample_main_layout">
<ViewAnimator <FrameLayout
android:id="@+id/sample_output" android:id="@+id/sample_output"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0px" android:layout_height="0px"
android:layout_weight="1"> android:layout_weight="1">
<ScrollView
style="@style/Widget.SampleMessageTile"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
style="@style/Widget.SampleMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="@dimen/horizontal_page_margin"
android:paddingRight="@dimen/horizontal_page_margin"
android:paddingTop="@dimen/vertical_page_margin"
android:paddingBottom="@dimen/vertical_page_margin"
android:text="@string/intro_message" />
</ScrollView>
<fragment <fragment
android:name="org.surfsite.iconsole.common.logger.LogFragment" android:name="org.surfsite.iconsole.common.logger.LogFragment"
android:id="@+id/log_fragment" android:id="@+id/log_fragment"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</ViewAnimator> </FrameLayout>
<View <View
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -14,39 +14,279 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" > tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="0dp" >
<TextView
android:id="@+id/Time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="@string/time_n00_00_00"
android:textAlignment="center"
app:layout_constraintBottom_toTopOf="@+id/guideline5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.513"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent" />
<NumberPicker
android:id="@+id/Level"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
app:layout_constraintLeft_toLeftOf="@+id/guideline"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="@+id/guideline4"
android:layout_marginTop="16dp" />
<TextView
android:id="@+id/Speed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="@string/speed_n0_0_km_h"
android:textAlignment="center"
app:layout_constraintTop_toTopOf="@+id/guideline4"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/guideline6"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
android:layout_marginRight="16dp" />
<TextView
android:id="@+id/Power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="@string/power_n0_0_w"
android:textAlignment="center"
android:gravity="center"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/guideline5"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/guideline4" />
<TextView
android:id="@+id/RPM"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="@string/rpm_n0"
android:textAlignment="center"
android:gravity="center"
app:layout_constraintTop_toTopOf="@+id/guideline6"
android:layout_marginTop="16dp"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
app:layout_constraintRight_toLeftOf="@+id/guideline"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/guideline2" />
<TextView
android:id="@+id/Distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="@string/distance_n0_0_km"
android:textAlignment="center"
android:gravity="center"
app:layout_constraintTop_toTopOf="@+id/guideline5"
android:layout_marginTop="16dp"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintVertical_bias="0.538"
app:layout_constraintRight_toLeftOf="@+id/guideline"
android:layout_marginRight="16dp" />
<TextView
android:id="@+id/Calories"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:text="@string/calories_n0_cal"
android:textAlignment="center"
android:gravity="center"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/guideline6"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintHorizontal_bias="0.507"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/guideline2" />
<TextView
android:id="@+id/Heart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:text="@string/heart_n0"
android:textAlignment="center"
android:gravity="center"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/guideline4"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/guideline6"
app:layout_constraintVertical_bias="0.461"
app:layout_constraintRight_toLeftOf="@+id/guideline"
android:layout_marginRight="16dp" />
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline3"
app:layout_constraintGuide_percent="0.4"
android:orientation="vertical"
tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="237dp" />
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline4"
app:layout_constraintGuide_percent="0.4"
android:orientation="horizontal"
tools:layout_editor_absoluteY="125dp"
tools:layout_editor_absoluteX="0dp" />
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline5"
app:layout_constraintGuide_percent="0.2"
android:orientation="horizontal"
tools:layout_editor_absoluteY="62dp"
tools:layout_editor_absoluteX="0dp" />
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline6"
app:layout_constraintGuide_percent="0.6"
android:orientation="horizontal"
tools:layout_editor_absoluteY="187dp"
tools:layout_editor_absoluteX="0dp" />
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline"
app:layout_constraintGuide_percent="0.8"
android:orientation="vertical"
tools:layout_editor_absoluteY="0dp"
tools:layout_editor_absoluteX="474dp" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/level"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="@+id/guideline"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toTopOf="@+id/guideline4"
app:layout_constraintTop_toTopOf="@+id/guideline5"
android:layout_marginTop="16dp" />
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline2"
app:layout_constraintGuide_percent="0.8"
android:orientation="horizontal"
tools:layout_editor_absoluteY="249dp"
tools:layout_editor_absoluteX="0dp" />
<ListView
android:id="@+id/in"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll" />
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" > android:orientation="horizontal"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="16dp"
app:layout_constraintTop_toTopOf="@+id/guideline2"
android:layout_marginTop="16dp"
android:layout_marginRight="16dp"
app:layout_constraintRight_toRightOf="parent"
android:layout_marginLeft="16dp"
app:layout_constraintLeft_toLeftOf="parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp">
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button <Button
android:id="@+id/button_start" android:id="@+id/button_start"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/start" /> android:text="@string/start" />
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button <Button
android:id="@+id/button_stop" android:id="@+id/button_stop"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/stop" /> android:text="@string/stop" />
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
<Button <Button
android:id="@+id/button_disconnect" android:id="@+id/button_disconnect"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/disconnect" /> android:text="@string/disconnect" />
<Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout> </LinearLayout>
</LinearLayout> </android.support.constraint.ConstraintLayout>

View file

@ -39,5 +39,14 @@
<string name="start">Start</string> <string name="start">Start</string>
<string name="stop">Stop</string> <string name="stop">Stop</string>
<string name="disconnect">Disconnect</string> <string name="disconnect">Disconnect</string>
<string name="time_n00_00_00">Time\n00:00:00</string>
<string name="speed_n0_0_km_h">Speed\n0.0 km/h</string>
<string name="rpm_n0">RPM\n0</string>
<string name="level_n1">Level\n1</string>
<string name="distance_n0_0_km">Distance\n0.0 km</string>
<string name="calories_n0_cal">Calories\n0 Cal</string>
<string name="heart_n0">Heart\n0</string>
<string name="power_n0_0_w">Power\n0.0 W</string>
<string name="level">Level</string>
</resources> </resources>