ii
This commit is contained in:
parent
d2e60c858f
commit
39af7e815e
|
@ -36,7 +36,7 @@ android {
|
|||
buildToolsVersion "25.0.2"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 25
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
android:configChanges="orientation|keyboardHidden"
|
||||
android:label="@string/select_device"
|
||||
android:theme="@android:style/Theme.Holo.Dialog"/>
|
||||
|
||||
<service android:name=".BluetoothChatService"></service>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -16,37 +16,33 @@
|
|||
|
||||
package org.surfsite.iconsole;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.ActionBar;
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ListView;
|
||||
import android.widget.NumberPicker;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.surfsite.iconsole.R;
|
||||
import org.surfsite.iconsole.common.logger.Log;
|
||||
|
||||
import java.util.Locale;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* This fragment controls Bluetooth to communicate with other devices.
|
||||
|
@ -66,6 +62,13 @@ public class BluetoothChatFragment extends Fragment {
|
|||
private Button mStopButton;
|
||||
private Button mDisconnectButton;
|
||||
private NumberPicker mLevel;
|
||||
private TextView mSpeedText;
|
||||
private TextView mPowerText;
|
||||
private TextView mRPMText;
|
||||
private TextView mDistanceText;
|
||||
private TextView mCaloriesText;
|
||||
private TextView mHFText;
|
||||
private TextView mTimeText;
|
||||
/**
|
||||
* Name of the connected device
|
||||
*/
|
||||
|
@ -85,6 +88,7 @@ public class BluetoothChatFragment extends Fragment {
|
|||
* Member object for the chat services
|
||||
*/
|
||||
private BluetoothChatService mChatService = null;
|
||||
private boolean mIsBound;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -118,10 +122,12 @@ public class BluetoothChatFragment extends Fragment {
|
|||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mChatService != null) {
|
||||
mChatService.stop();
|
||||
mChatService.stopBT();
|
||||
}
|
||||
Log.d(TAG, "onDestroy()");
|
||||
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,7 +141,7 @@ public class BluetoothChatFragment extends Fragment {
|
|||
// Only if the state is STATE_NONE, do we know that we haven't started already
|
||||
if (mChatService.getState() == BluetoothChatService.STATE_NONE) {
|
||||
// Start the Bluetooth chat services
|
||||
mChatService.start();
|
||||
mChatService.startBT();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +164,54 @@ public class BluetoothChatFragment extends Fragment {
|
|||
mLevel.setValue(5);
|
||||
mLevel.setWrapSelectorWheel(false);
|
||||
mLevel.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
|
||||
mSpeedText = (TextView) view.findViewById(R.id.Speed);
|
||||
mPowerText = (TextView) view.findViewById(R.id.Power);
|
||||
mRPMText = (TextView) view.findViewById(R.id.RPM);
|
||||
mDistanceText = (TextView) view.findViewById(R.id.Distance);
|
||||
mCaloriesText = (TextView) view.findViewById(R.id.Calories);
|
||||
mHFText = (TextView) view.findViewById(R.id.Heart);
|
||||
mTimeText = (TextView) view.findViewById(R.id.Time);
|
||||
}
|
||||
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
// This is called when the connection with the service has been
|
||||
// established, giving us the service object we can use to
|
||||
// interact with the service. Because we have bound to a explicit
|
||||
// service that we know is running in our own process, we can
|
||||
// cast its IBinder to a concrete class and directly access it.
|
||||
mChatService = ((BluetoothChatService.BluetoothChatServiceI)service).getService();
|
||||
((BluetoothChatService.BluetoothChatServiceI)service).setHandler(mHandler);
|
||||
Log.d(TAG, "onServiceConnected()");
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
// This is called when the connection with the service has been
|
||||
// unexpectedly disconnected -- that is, its process crashed.
|
||||
// Because it is running in our same process, we should never
|
||||
// see this happen.
|
||||
mChatService = null;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
void doBindService() {
|
||||
Log.d(TAG, "doBindService()");
|
||||
|
||||
// Establish a connection with the service. We use an explicit
|
||||
// class name because we want a specific service implementation that
|
||||
// we know will be running in our own process (and thus won't be
|
||||
// supporting component replacement by other applications).
|
||||
getActivity().bindService(new Intent(getActivity(), BluetoothChatService.class), mConnection , Context.BIND_AUTO_CREATE);
|
||||
mIsBound = true;
|
||||
}
|
||||
|
||||
void doUnbindService() {
|
||||
if (mIsBound) {
|
||||
// Detach our existing connection.
|
||||
getActivity().unbindService(mConnection);
|
||||
mIsBound = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -165,37 +219,45 @@ public class BluetoothChatFragment extends Fragment {
|
|||
*/
|
||||
private void setupChat() {
|
||||
Log.d(TAG, "setupChat()");
|
||||
/*
|
||||
// Initialize the array adapter for the conversation thread
|
||||
mConversationArrayAdapter = new ArrayAdapter<>(getActivity(), R.layout.message);
|
||||
|
||||
mConversationView.setAdapter(mConversationArrayAdapter);
|
||||
*/
|
||||
|
||||
// Initialize the BluetoothChatService to perform bluetooth connections
|
||||
mChatService = new BluetoothChatService(getActivity(), mHandler);
|
||||
if (!mIsBound)
|
||||
doBindService();
|
||||
|
||||
mStartButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mChatService != null)
|
||||
mChatService.startIConsole();
|
||||
}
|
||||
});
|
||||
|
||||
mStopButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mChatService.stopIConsole();
|
||||
if (mChatService != null)
|
||||
mChatService.stopIConsole();
|
||||
}
|
||||
});
|
||||
|
||||
mDisconnectButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mChatService.stop();
|
||||
if (mChatService != null)
|
||||
mChatService.stopBT();
|
||||
}
|
||||
});
|
||||
|
||||
mStartButton.setEnabled(false);
|
||||
mStopButton.setEnabled(false);
|
||||
mDisconnectButton.setEnabled(false);
|
||||
mLevel.setEnabled(false);
|
||||
mLevel.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mChatService != null)
|
||||
mChatService.setLevel(mLevel.getValue());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,7 +278,10 @@ public class BluetoothChatFragment extends Fragment {
|
|||
* @param message A string of text to send.
|
||||
*/
|
||||
private void sendMessage(String message) {
|
||||
// Check that we're actually connected before trying anything
|
||||
if (mChatService == null)
|
||||
return;
|
||||
|
||||
// Check that we're actually connected before trying anything
|
||||
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
|
||||
Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
|
@ -263,6 +328,7 @@ public class BluetoothChatFragment extends Fragment {
|
|||
* The Handler that gets information back from the BluetoothChatService
|
||||
*/
|
||||
private final Handler mHandler = new Handler() {
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
FragmentActivity activity = getActivity();
|
||||
|
@ -275,12 +341,14 @@ public class BluetoothChatFragment extends Fragment {
|
|||
mStartButton.setEnabled(true);
|
||||
mStopButton.setEnabled(true);
|
||||
mDisconnectButton.setEnabled(true);
|
||||
mLevel.setEnabled(true);
|
||||
break;
|
||||
case BluetoothChatService.STATE_CONNECTING:
|
||||
setStatus(R.string.title_connecting);
|
||||
mStartButton.setEnabled(false);
|
||||
mStopButton.setEnabled(false);
|
||||
mDisconnectButton.setEnabled(false);
|
||||
mLevel.setEnabled(false);
|
||||
break;
|
||||
case BluetoothChatService.STATE_LISTEN:
|
||||
case BluetoothChatService.STATE_NONE:
|
||||
|
@ -288,19 +356,22 @@ public class BluetoothChatFragment extends Fragment {
|
|||
mStartButton.setEnabled(false);
|
||||
mStopButton.setEnabled(false);
|
||||
mDisconnectButton.setEnabled(false);
|
||||
mLevel.setEnabled(false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case Constants.MESSAGE_DATA:
|
||||
if (!(msg.obj instanceof IConsole.Data))
|
||||
return;
|
||||
IConsole.Data data = (IConsole.Data) msg.obj;
|
||||
// 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.mLevel, data.mDistance10 / 10.0, data.mCalories, data.mHF);
|
||||
*/
|
||||
//mConversationArrayAdapter.add(mConnectedDeviceName + ": " + dataMessage);
|
||||
mSpeedText.setText(String.format("Speed\n% 3.1f", data.mSpeed10 / 10.0));
|
||||
mPowerText.setText(String.format("Power\n% 3.1f", data.mPower10 / 10.0));
|
||||
mRPMText.setText(String.format("RPM\n%d", data.mRPM));
|
||||
mDistanceText.setText(String.format("Distance\n% 3.1f", data.mDistance10 / 10.0));
|
||||
mCaloriesText.setText(String.format("Calories\n% 3.1f", data.mSpeed10 / 10.0));
|
||||
mHFText.setText(String.format("Heart\n%d", data.mHF));
|
||||
mTimeText.setText(String.format("Time:\n%s",data.getTimeStr()));
|
||||
mLevel.setValue(data.mLevel);
|
||||
break;
|
||||
case Constants.MESSAGE_WRITE:
|
||||
//byte[] writeBuf = (byte[]) msg.obj;
|
||||
|
@ -374,7 +445,8 @@ public class BluetoothChatFragment extends Fragment {
|
|||
// Get the BluetoothDevice object
|
||||
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
|
||||
// Attempt to connect to the device
|
||||
mChatService.connect(device);
|
||||
if (mChatService != null)
|
||||
mChatService.connect(device);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,20 +16,26 @@
|
|||
|
||||
package org.surfsite.iconsole;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
|
||||
import org.surfsite.iconsole.common.logger.Log;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
@ -38,7 +44,7 @@ import java.util.UUID;
|
|||
* incoming connections, a thread for connecting with a device, and a
|
||||
* thread for performing data transmissions when connected.
|
||||
*/
|
||||
public class BluetoothChatService {
|
||||
public class BluetoothChatService extends Service {
|
||||
// Debugging
|
||||
private static final String TAG = "BluetoothChatService";
|
||||
// Name for the SDP record when creating server socket
|
||||
|
@ -49,7 +55,7 @@ public class BluetoothChatService {
|
|||
private static final UUID SERIAL_PORT_CLASS = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
|
||||
// Member fields
|
||||
private final BluetoothAdapter mAdapter;
|
||||
private final Handler mHandler;
|
||||
private Handler mHandler;
|
||||
|
||||
private ConnectThread mConnectThread;
|
||||
private ConnectedThread mConnectedThread;
|
||||
|
@ -61,60 +67,47 @@ public class BluetoothChatService {
|
|||
public static final int STATE_LISTEN = 1; // now listening for incoming connections
|
||||
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
|
||||
public static final int STATE_CONNECTED = 3; // now connected to a remote device
|
||||
private NotificationManager mNM;
|
||||
|
||||
/**
|
||||
* Constructor. Prepares a new BluetoothChat session.
|
||||
*
|
||||
* @param context The UI Activity Context
|
||||
* @param handler A Handler to send messages back to the UI Activity
|
||||
*/
|
||||
public BluetoothChatService(Context context, Handler handler) {
|
||||
private int NOTIFICATION = R.string.local_service_started;
|
||||
|
||||
public BluetoothChatService() {
|
||||
super();
|
||||
mAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
mState = STATE_NONE;
|
||||
mNewState = mState;
|
||||
mHandler = handler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update UI title according to the current state of the chat connection
|
||||
*/
|
||||
private synchronized void updateUserInterfaceTitle() {
|
||||
mState = getState();
|
||||
Log.d(TAG, "updateUserInterfaceTitle() " + mNewState + " -> " + mState);
|
||||
mNewState = mState;
|
||||
|
||||
// Give the new state to the Handler so the UI Activity can update
|
||||
mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, mNewState, -1).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current connection state.
|
||||
*/
|
||||
public synchronized int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the chat service. Specifically start AcceptThread to begin a
|
||||
* session in listening (server) mode. Called by the Activity onResume()
|
||||
*/
|
||||
public synchronized void start() {
|
||||
Log.d(TAG, "start");
|
||||
|
||||
// Cancel any thread attempting to make a connection
|
||||
if (mConnectThread != null) {
|
||||
mConnectThread.cancel();
|
||||
mConnectThread = null;
|
||||
public class BluetoothChatServiceI extends Binder {
|
||||
BluetoothChatService getService() {
|
||||
return BluetoothChatService.this;
|
||||
}
|
||||
|
||||
// Cancel any thread currently running a connection
|
||||
if (mConnectedThread != null) {
|
||||
mConnectedThread.cancel();
|
||||
mConnectedThread = null;
|
||||
void setHandler(Handler handler) {
|
||||
mHandler = handler;
|
||||
}
|
||||
// Update UI title
|
||||
updateUserInterfaceTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
|
||||
|
||||
// Display a notification about us starting. We put an icon in the status bar.
|
||||
showNotification();
|
||||
}
|
||||
|
||||
boolean startIConsole() {
|
||||
return mConnectedThread.startIConsole();
|
||||
}
|
||||
|
||||
boolean stopIConsole() {
|
||||
return mConnectedThread.stopIConsole();
|
||||
}
|
||||
|
||||
boolean setLevel(int level) {
|
||||
return mConnectedThread.setLevel(level);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -146,6 +139,100 @@ public class BluetoothChatService {
|
|||
updateUserInterfaceTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
Log.i(TAG, "onBind");
|
||||
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
|
||||
// This is the object that receives interactions from clients. See
|
||||
// RemoteService for a more complete example.
|
||||
private final IBinder mBinder = new BluetoothChatServiceI();
|
||||
|
||||
/**
|
||||
* Update UI title according to the current state of the chat connection
|
||||
*/
|
||||
private synchronized void updateUserInterfaceTitle() {
|
||||
mState = getState();
|
||||
Log.d(TAG, "updateUserInterfaceTitle() " + mNewState + " -> " + mState);
|
||||
mNewState = mState;
|
||||
|
||||
// Give the new state to the Handler so the UI Activity can update
|
||||
mHandler.obtainMessage(Constants.MESSAGE_STATE_CHANGE, mNewState, -1).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current connection state.
|
||||
*/
|
||||
public synchronized int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the chat service. Specifically startBT AcceptThread to begin a
|
||||
* session in listening (server) mode. Called by the Activity onResume()
|
||||
*/
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
Log.i(TAG, "Received onStartCommand() id " + startId + ": " + intent);
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
stopBT();
|
||||
// Cancel the persistent notification.
|
||||
mNM.cancel(NOTIFICATION);
|
||||
|
||||
// Tell the user we stopped.
|
||||
Log.i(TAG, "onDestroy");
|
||||
super.onDestroy();
|
||||
|
||||
}
|
||||
/**
|
||||
* Show a notification while this service is running.
|
||||
*/
|
||||
private void showNotification() {
|
||||
// In this sample, we'll use the same text for the ticker and the expanded notification
|
||||
CharSequence text = getText(R.string.local_service_started);
|
||||
|
||||
// The PendingIntent to launch our activity if the user selects this notification
|
||||
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
|
||||
new Intent(this, MainActivity.class), 0);
|
||||
|
||||
// Set the info for the views that show in the notification panel.
|
||||
Notification notification = new Notification.Builder(this)
|
||||
.setSmallIcon(R.drawable.ic_action_device_access_bluetooth_searching) // the status icon
|
||||
.setTicker(text) // the status text
|
||||
.setWhen(System.currentTimeMillis()) // the time stamp
|
||||
.setContentTitle(getText(R.string.local_service_label)) // the label of the entry
|
||||
.setContentText(text) // the contents of the entry
|
||||
.setContentIntent(contentIntent) // The intent to send when the entry is clicked
|
||||
.build();
|
||||
|
||||
// Send the notification.
|
||||
mNM.notify(NOTIFICATION, notification);
|
||||
}
|
||||
|
||||
void startBT() {
|
||||
Log.d(TAG, "startBT");
|
||||
|
||||
// Cancel any thread attempting to make a connection
|
||||
if (mConnectThread != null) {
|
||||
mConnectThread.cancel();
|
||||
mConnectThread = null;
|
||||
}
|
||||
|
||||
// Cancel any thread currently running a connection
|
||||
if (mConnectedThread != null) {
|
||||
mConnectedThread.cancel();
|
||||
mConnectedThread = null;
|
||||
}
|
||||
// Update UI title
|
||||
updateUserInterfaceTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ConnectedThread to begin managing a Bluetooth connection
|
||||
*
|
||||
|
@ -185,8 +272,8 @@ public class BluetoothChatService {
|
|||
/**
|
||||
* Stop all threads
|
||||
*/
|
||||
public synchronized void stop() {
|
||||
Log.d(TAG, "stop");
|
||||
public synchronized void stopBT() {
|
||||
Log.d(TAG, "stopBT");
|
||||
|
||||
if (mConnectThread != null) {
|
||||
mConnectThread.cancel();
|
||||
|
@ -203,13 +290,6 @@ public class BluetoothChatService {
|
|||
updateUserInterfaceTitle();
|
||||
}
|
||||
|
||||
public synchronized boolean startIConsole() {
|
||||
return mConnectedThread.startIConsole();
|
||||
}
|
||||
|
||||
public synchronized boolean stopIConsole() {
|
||||
return mConnectedThread.stopIConsole();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate that the connection attempt failed and notify the UI Activity.
|
||||
|
@ -227,7 +307,7 @@ public class BluetoothChatService {
|
|||
updateUserInterfaceTitle();
|
||||
|
||||
// Start the service over to restart listening mode
|
||||
BluetoothChatService.this.start();
|
||||
BluetoothChatService.this.startBT();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -246,7 +326,7 @@ public class BluetoothChatService {
|
|||
updateUserInterfaceTitle();
|
||||
|
||||
// Start the service over to restart listening mode
|
||||
BluetoothChatService.this.start();
|
||||
BluetoothChatService.this.startBT();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -254,7 +334,7 @@ public class BluetoothChatService {
|
|||
* with a device. It runs straight through; the connection either
|
||||
* succeeds or fails.
|
||||
*/
|
||||
private class ConnectThread extends Thread {
|
||||
class ConnectThread extends Thread {
|
||||
private final BluetoothSocket mmSocket;
|
||||
private final BluetoothDevice mmDevice;
|
||||
|
||||
|
@ -318,7 +398,7 @@ public class BluetoothChatService {
|
|||
* This thread runs during a connection with a remote device.
|
||||
* It handles all incoming and outgoing transmissions.
|
||||
*/
|
||||
private class ConnectedThread extends Thread {
|
||||
class ConnectedThread extends Thread {
|
||||
private final BluetoothSocket mmSocket;
|
||||
private final InputStream mmInStream;
|
||||
private final OutputStream mmOutStream;
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.AdapterView;
|
||||
|
@ -33,7 +34,6 @@ import android.widget.ListView;
|
|||
import android.widget.TextView;
|
||||
|
||||
import org.surfsite.iconsole.R;
|
||||
import org.surfsite.iconsole.common.logger.Log;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -153,7 +153,7 @@ public class DeviceListActivity extends Activity {
|
|||
// Turn on sub-title for new devices
|
||||
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
|
||||
|
||||
// If we're already discovering, stop it
|
||||
// If we're already discovering, stopBT it
|
||||
if (mBtAdapter.isDiscovering()) {
|
||||
mBtAdapter.cancelDiscovery();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
package org.surfsite.iconsole;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import org.surfsite.iconsole.common.logger.Log;
|
||||
|
||||
/**
|
||||
* Created by harald on 25.04.17.
|
||||
|
@ -52,7 +54,8 @@ class IConsole {
|
|||
private final DataListener mDataListener;
|
||||
private final DebugListener mDebugListener;
|
||||
|
||||
IConsole(InputStream inputStream, OutputStream outputStream, DataListener dataListener, DebugListener debugListener) {
|
||||
IConsole(InputStream inputStream, OutputStream outputStream,
|
||||
@Nullable DataListener dataListener, @Nullable DebugListener debugListener) {
|
||||
this.mInputStream = inputStream;
|
||||
this.mOutputStream = outputStream;
|
||||
this.mDataListener = dataListener;
|
||||
|
@ -90,6 +93,25 @@ class IConsole {
|
|||
this.mPower10 = 100 * (bytes[16] - 1) + bytes[17] - 1;
|
||||
this.mLevel = bytes[18] -1;
|
||||
}
|
||||
|
||||
String getTimeStr() {
|
||||
long day, hour, min, sec;
|
||||
StringBuilder b = new StringBuilder();
|
||||
day = mTime / 60 / 60 / 24;
|
||||
if (day > 0)
|
||||
b.append(String.format(Locale.US, "%02d:", day));
|
||||
hour = (mTime % (60 * 60 * 24)) / 60 / 60;
|
||||
if (hour > 0)
|
||||
if (day > 0)
|
||||
b.append(String.format(Locale.US, "%02d:", hour));
|
||||
else
|
||||
b.append(String.format(Locale.US, "%d:", hour));
|
||||
min = (mTime % (60 * 60)) / 60;
|
||||
sec = mTime % 60;
|
||||
b.append(String.format(Locale.US, "%02d:%02d", min, sec));
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface DataListener {
|
||||
|
@ -127,7 +149,7 @@ class IConsole {
|
|||
return true;
|
||||
}
|
||||
|
||||
boolean send(byte[] packet, byte expect, int plen) throws IOException {
|
||||
private boolean send(byte[] packet, byte expect, int plen) throws IOException {
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
if ((now - mTimesent) < ((mCurrentState == State.READ) ? 500 : 200)) {
|
||||
|
@ -136,6 +158,7 @@ class IConsole {
|
|||
|
||||
// Flush input stream
|
||||
try {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
mInputStream.skip(mInputStream.available());
|
||||
} catch (IOException e) {
|
||||
; // ignore
|
||||
|
@ -263,7 +286,8 @@ class IConsole {
|
|||
//Log.d(TAG, "processIOAck next state");
|
||||
|
||||
if(mCurrentState == State.READ)
|
||||
mDataListener.onData(new Data(got));
|
||||
if (null != mDataListener)
|
||||
mDataListener.onData(new Data(got));
|
||||
|
||||
mCurrentState = mNextState;
|
||||
switch (mNextState) {
|
||||
|
@ -318,7 +342,8 @@ class IConsole {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "processIO", e);
|
||||
mDataListener.onError(e);
|
||||
if (null != mDataListener)
|
||||
mDataListener.onError(e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,18 +17,22 @@
|
|||
|
||||
package org.surfsite.iconsole;
|
||||
|
||||
import android.app.Activity;
|
||||
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.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ViewAnimator;
|
||||
|
||||
import org.surfsite.iconsole.R;
|
||||
import org.surfsite.iconsole.common.activities.SampleActivityBase;
|
||||
import org.surfsite.iconsole.common.logger.Log;
|
||||
import org.surfsite.iconsole.common.logger.LogFragment;
|
||||
import org.surfsite.iconsole.common.logger.LogWrapper;
|
||||
import org.surfsite.iconsole.common.logger.MessageOnlyLogFilter;
|
||||
|
||||
|
||||
/**
|
||||
* A simple launcher activity containing a summary sample description, sample log and a custom
|
||||
|
@ -37,7 +41,7 @@ import org.surfsite.iconsole.common.logger.MessageOnlyLogFilter;
|
|||
* For devices with displays with a width of 720dp or greater, the sample log is always visible,
|
||||
* on other devices it's visibility is controlled by an item on the Action Bar.
|
||||
*/
|
||||
public class MainActivity extends SampleActivityBase {
|
||||
public class MainActivity extends FragmentActivity {
|
||||
|
||||
public static final String TAG = "MainActivity";
|
||||
|
||||
|
@ -55,6 +59,12 @@ public class MainActivity extends SampleActivityBase {
|
|||
transaction.replace(R.id.sample_content_fragment, fragment);
|
||||
transaction.commit();
|
||||
}
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
ComponentName componentName = startService(new Intent(this, BluetoothChatService.class));
|
||||
if (componentName == null)
|
||||
Log.e(TAG, "componentName == null");
|
||||
else
|
||||
Log.i(TAG, "Service started");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,7 +76,7 @@ public class MainActivity extends SampleActivityBase {
|
|||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
MenuItem logToggle = menu.findItem(R.id.menu_toggle_log);
|
||||
logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
|
||||
//logToggle.setVisible(findViewById(R.id.sample_output) instanceof ViewAnimator);
|
||||
logToggle.setTitle(mLogShown ? R.string.sample_hide_log : R.string.sample_show_log);
|
||||
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
|
@ -90,9 +100,7 @@ public class MainActivity extends SampleActivityBase {
|
|||
*/
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
/** Create a chain of targets that will receive log data */
|
||||
@Override
|
||||
/*
|
||||
public void initializeLogging() {
|
||||
// Wraps Android's native log framework.
|
||||
LogWrapper logWrapper = new LogWrapper();
|
||||
|
@ -110,4 +118,5 @@ public class MainActivity extends SampleActivityBase {
|
|||
|
||||
Log.i(TAG, "Ready");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
package org.surfsite.iconsole.common.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
|
||||
import org.surfsite.iconsole.common.logger.Log;
|
||||
import org.surfsite.iconsole.common.logger.LogWrapper;
|
||||
|
||||
/**
|
||||
* Base launcher activity, to handle most of the common plumbing for samples.
|
||||
*/
|
||||
public class SampleActivityBase extends FragmentActivity {
|
||||
|
||||
public static final String TAG = "SampleActivityBase";
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
initializeLogging();
|
||||
}
|
||||
|
||||
/** Set up targets to receive log data */
|
||||
public void initializeLogging() {
|
||||
// Using Log, front-end to the logging chain, emulates android.util.log method signatures.
|
||||
// Wraps Android's native log framework
|
||||
LogWrapper logWrapper = new LogWrapper();
|
||||
Log.setLogNode(logWrapper);
|
||||
|
||||
Log.i(TAG, "Ready");
|
||||
}
|
||||
}
|
|
@ -1,236 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.surfsite.iconsole.common.logger;
|
||||
|
||||
/**
|
||||
* Helper class for a list (or tree) of LoggerNodes.
|
||||
*
|
||||
* <p>When this is set as the head of the list,
|
||||
* an instance of it can function as a drop-in replacement for {@link android.util.Log}.
|
||||
* Most of the methods in this class server only to map a method call in Log to its equivalent
|
||||
* in LogNode.</p>
|
||||
*/
|
||||
public class Log {
|
||||
// Grabbing the native values from Android's native logging facilities,
|
||||
// to make for easy migration and interop.
|
||||
public static final int NONE = -1;
|
||||
public static final int VERBOSE = android.util.Log.VERBOSE;
|
||||
public static final int DEBUG = android.util.Log.DEBUG;
|
||||
public static final int INFO = android.util.Log.INFO;
|
||||
public static final int WARN = android.util.Log.WARN;
|
||||
public static final int ERROR = android.util.Log.ERROR;
|
||||
public static final int ASSERT = android.util.Log.ASSERT;
|
||||
|
||||
// Stores the beginning of the LogNode topology.
|
||||
private static LogNode mLogNode;
|
||||
|
||||
/**
|
||||
* Returns the next LogNode in the linked list.
|
||||
*/
|
||||
public static LogNode getLogNode() {
|
||||
return mLogNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the LogNode data will be sent to.
|
||||
*/
|
||||
public static void setLogNode(LogNode node) {
|
||||
mLogNode = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the LogNode to print the log data provided. Other LogNodes can
|
||||
* be chained to the end of the LogNode as desired.
|
||||
*
|
||||
* @param priority Log level of the data being logged. Verbose, Error, etc.
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void println(int priority, String tag, String msg, Throwable tr) {
|
||||
if (mLogNode != null) {
|
||||
mLogNode.println(priority, tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the LogNode to print the log data provided. Other LogNodes can
|
||||
* be chained to the end of the LogNode as desired.
|
||||
*
|
||||
* @param priority Log level of the data being logged. Verbose, Error, etc.
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged. The actual message to be logged.
|
||||
*/
|
||||
public static void println(int priority, String tag, String msg) {
|
||||
println(priority, tag, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at VERBOSE priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void v(String tag, String msg, Throwable tr) {
|
||||
println(VERBOSE, tag, msg, tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at VERBOSE priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
*/
|
||||
public static void v(String tag, String msg) {
|
||||
v(tag, msg, null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints a message at DEBUG priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void d(String tag, String msg, Throwable tr) {
|
||||
println(DEBUG, tag, msg, tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at DEBUG priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
*/
|
||||
public static void d(String tag, String msg) {
|
||||
d(tag, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at INFO priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void i(String tag, String msg, Throwable tr) {
|
||||
println(INFO, tag, msg, tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at INFO priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
*/
|
||||
public static void i(String tag, String msg) {
|
||||
i(tag, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at WARN priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void w(String tag, String msg, Throwable tr) {
|
||||
println(WARN, tag, msg, tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at WARN priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
*/
|
||||
public static void w(String tag, String msg) {
|
||||
w(tag, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at WARN priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void w(String tag, Throwable tr) {
|
||||
w(tag, null, tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at ERROR priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void e(String tag, String msg, Throwable tr) {
|
||||
println(ERROR, tag, msg, tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at ERROR priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
*/
|
||||
public static void e(String tag, String msg) {
|
||||
e(tag, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at ASSERT priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void wtf(String tag, String msg, Throwable tr) {
|
||||
println(ASSERT, tag, msg, tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at ASSERT priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged.
|
||||
*/
|
||||
public static void wtf(String tag, String msg) {
|
||||
wtf(tag, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a message at ASSERT priority.
|
||||
*
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public static void wtf(String tag, Throwable tr) {
|
||||
wtf(tag, null, tr);
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
|
||||
package org.surfsite.iconsole.common.logger;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
/**
|
||||
* Simple fraggment which contains a LogView and uses is to output log data it receives
|
||||
* through the LogNode interface.
|
||||
*/
|
||||
public class LogFragment extends Fragment {
|
||||
|
||||
private LogView mLogView;
|
||||
private ScrollView mScrollView;
|
||||
|
||||
public LogFragment() {}
|
||||
|
||||
public View inflateViews() {
|
||||
mScrollView = new ScrollView(getActivity());
|
||||
ViewGroup.LayoutParams scrollParams = new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
mScrollView.setLayoutParams(scrollParams);
|
||||
|
||||
mLogView = new LogView(getActivity());
|
||||
ViewGroup.LayoutParams logParams = new ViewGroup.LayoutParams(scrollParams);
|
||||
logParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
mLogView.setLayoutParams(logParams);
|
||||
mLogView.setClickable(true);
|
||||
mLogView.setFocusable(true);
|
||||
mLogView.setTypeface(Typeface.MONOSPACE);
|
||||
|
||||
// Want to set padding as 16 dips, setPadding takes pixels. Hooray math!
|
||||
int paddingDips = 16;
|
||||
double scale = getResources().getDisplayMetrics().density;
|
||||
int paddingPixels = (int) ((paddingDips * (scale)) + .5);
|
||||
mLogView.setPadding(paddingPixels, paddingPixels, paddingPixels, paddingPixels);
|
||||
mLogView.setCompoundDrawablePadding(paddingPixels);
|
||||
|
||||
mLogView.setGravity(Gravity.BOTTOM);
|
||||
mLogView.setTextAppearance(getActivity(), android.R.style.TextAppearance_Holo_Medium);
|
||||
|
||||
mScrollView.addView(mLogView);
|
||||
return mScrollView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
|
||||
View result = inflateViews();
|
||||
|
||||
mLogView.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
mScrollView.fullScroll(ScrollView.FOCUS_DOWN);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public LogView getLogView() {
|
||||
return mLogView;
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 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.
|
||||
*/
|
||||
package org.surfsite.iconsole.common.logger;
|
||||
|
||||
/**
|
||||
* Basic interface for a logging system that can output to one or more targets.
|
||||
* Note that in addition to classes that will output these logs in some format,
|
||||
* one can also implement this interface over a filter and insert that in the chain,
|
||||
* such that no targets further down see certain data, or see manipulated forms of the data.
|
||||
* You could, for instance, write a "ToHtmlLoggerNode" that just converted all the log data
|
||||
* it received to HTML and sent it along to the next node in the chain, without printing it
|
||||
* anywhere.
|
||||
*/
|
||||
public interface LogNode {
|
||||
|
||||
/**
|
||||
* Instructs first LogNode in the list to print the log data provided.
|
||||
* @param priority Log level of the data being logged. Verbose, Error, etc.
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged. The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
public void println(int priority, String tag, String msg, Throwable tr);
|
||||
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.surfsite.iconsole.common.logger;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.util.*;
|
||||
import android.widget.TextView;
|
||||
|
||||
/** Simple TextView which is used to output log data received through the LogNode interface.
|
||||
*/
|
||||
public class LogView extends TextView implements LogNode {
|
||||
|
||||
public LogView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public LogView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public LogView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the log data and prints it out to the LogView.
|
||||
* @param priority Log level of the data being logged. Verbose, Error, etc.
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged. The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
@Override
|
||||
public void println(int priority, String tag, String msg, Throwable tr) {
|
||||
|
||||
|
||||
String priorityStr = null;
|
||||
|
||||
// For the purposes of this View, we want to print the priority as readable text.
|
||||
switch(priority) {
|
||||
case android.util.Log.VERBOSE:
|
||||
priorityStr = "VERBOSE";
|
||||
break;
|
||||
case android.util.Log.DEBUG:
|
||||
priorityStr = "DEBUG";
|
||||
break;
|
||||
case android.util.Log.INFO:
|
||||
priorityStr = "INFO";
|
||||
break;
|
||||
case android.util.Log.WARN:
|
||||
priorityStr = "WARN";
|
||||
break;
|
||||
case android.util.Log.ERROR:
|
||||
priorityStr = "ERROR";
|
||||
break;
|
||||
case android.util.Log.ASSERT:
|
||||
priorityStr = "ASSERT";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Handily, the Log class has a facility for converting a stack trace into a usable string.
|
||||
String exceptionStr = null;
|
||||
if (tr != null) {
|
||||
exceptionStr = android.util.Log.getStackTraceString(tr);
|
||||
}
|
||||
|
||||
// Take the priority, tag, message, and exception, and concatenate as necessary
|
||||
// into one usable line of text.
|
||||
final StringBuilder outputBuilder = new StringBuilder();
|
||||
|
||||
String delimiter = "\t";
|
||||
appendIfNotNull(outputBuilder, priorityStr, delimiter);
|
||||
appendIfNotNull(outputBuilder, tag, delimiter);
|
||||
appendIfNotNull(outputBuilder, msg, delimiter);
|
||||
appendIfNotNull(outputBuilder, exceptionStr, delimiter);
|
||||
|
||||
// In case this was originally called from an AsyncTask or some other off-UI thread,
|
||||
// make sure the update occurs within the UI thread.
|
||||
((Activity) getContext()).runOnUiThread( (new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Display the text we just generated within the LogView.
|
||||
appendToLog(outputBuilder.toString());
|
||||
}
|
||||
})));
|
||||
|
||||
if (mNext != null) {
|
||||
mNext.println(priority, tag, msg, tr);
|
||||
}
|
||||
}
|
||||
|
||||
public LogNode getNext() {
|
||||
return mNext;
|
||||
}
|
||||
|
||||
public void setNext(LogNode node) {
|
||||
mNext = node;
|
||||
}
|
||||
|
||||
/** Takes a string and adds to it, with a separator, if the bit to be added isn't null. Since
|
||||
* the logger takes so many arguments that might be null, this method helps cut out some of the
|
||||
* agonizing tedium of writing the same 3 lines over and over.
|
||||
* @param source StringBuilder containing the text to append to.
|
||||
* @param addStr The String to append
|
||||
* @param delimiter The String to separate the source and appended strings. A tab or comma,
|
||||
* for instance.
|
||||
* @return The fully concatenated String as a StringBuilder
|
||||
*/
|
||||
private StringBuilder appendIfNotNull(StringBuilder source, String addStr, String delimiter) {
|
||||
if (addStr != null) {
|
||||
if (addStr.length() == 0) {
|
||||
delimiter = "";
|
||||
}
|
||||
|
||||
return source.append(addStr).append(delimiter);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
// The next LogNode in the chain.
|
||||
LogNode mNext;
|
||||
|
||||
/** Outputs the string as a new line of log data in the LogView. */
|
||||
public void appendToLog(String s) {
|
||||
append("\n" + s);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2012 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.
|
||||
*/
|
||||
package org.surfsite.iconsole.common.logger;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Helper class which wraps Android's native Log utility in the Logger interface. This way
|
||||
* normal DDMS output can be one of the many targets receiving and outputting logs simultaneously.
|
||||
*/
|
||||
public class LogWrapper implements LogNode {
|
||||
|
||||
// For piping: The next node to receive Log data after this one has done its work.
|
||||
private LogNode mNext;
|
||||
|
||||
/**
|
||||
* Returns the next LogNode in the linked list.
|
||||
*/
|
||||
public LogNode getNext() {
|
||||
return mNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the LogNode data will be sent to..
|
||||
*/
|
||||
public void setNext(LogNode node) {
|
||||
mNext = node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints data out to the console using Android's native log mechanism.
|
||||
* @param priority Log level of the data being logged. Verbose, Error, etc.
|
||||
* @param tag Tag for for the log data. Can be used to organize log statements.
|
||||
* @param msg The actual message to be logged. The actual message to be logged.
|
||||
* @param tr If an exception was thrown, this can be sent along for the logging facilities
|
||||
* to extract and print useful information.
|
||||
*/
|
||||
@Override
|
||||
public void println(int priority, String tag, String msg, Throwable tr) {
|
||||
// There actually are log methods that don't take a msg parameter. For now,
|
||||
// if that's the case, just convert null to the empty string and move on.
|
||||
String useMsg = msg;
|
||||
if (useMsg == null) {
|
||||
useMsg = "";
|
||||
}
|
||||
|
||||
// If an exeption was provided, convert that exception to a usable string and attach
|
||||
// it to the end of the msg method.
|
||||
if (tr != null) {
|
||||
msg += "\n" + Log.getStackTraceString(tr);
|
||||
}
|
||||
|
||||
// This is functionally identical to Log.x(tag, useMsg);
|
||||
// For instance, if priority were Log.VERBOSE, this would be the same as Log.v(tag, useMsg)
|
||||
Log.println(priority, tag, useMsg);
|
||||
|
||||
// If this isn't the last node in the chain, move things along.
|
||||
if (mNext != null) {
|
||||
mNext.println(priority, tag, msg, tr);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package org.surfsite.iconsole.common.logger;
|
||||
|
||||
/**
|
||||
* Simple {@link LogNode} filter, removes everything except the message.
|
||||
* Useful for situations like on-screen log output where you don't want a lot of metadata displayed,
|
||||
* just easy-to-read message updates as they're happening.
|
||||
*/
|
||||
public class MessageOnlyLogFilter implements LogNode {
|
||||
|
||||
LogNode mNext;
|
||||
|
||||
/**
|
||||
* Takes the "next" LogNode as a parameter, to simplify chaining.
|
||||
*
|
||||
* @param next The next LogNode in the pipeline.
|
||||
*/
|
||||
public MessageOnlyLogFilter(LogNode next) {
|
||||
mNext = next;
|
||||
}
|
||||
|
||||
public MessageOnlyLogFilter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void println(int priority, String tag, String msg, Throwable tr) {
|
||||
if (mNext != null) {
|
||||
getNext().println(Log.NONE, null, msg, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next LogNode in the chain.
|
||||
*/
|
||||
public LogNode getNext() {
|
||||
return mNext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the LogNode data will be sent to..
|
||||
*/
|
||||
public void setNext(LogNode node) {
|
||||
mNext = node;
|
||||
}
|
||||
|
||||
}
|
|
@ -20,48 +20,6 @@
|
|||
android:layout_height="match_parent"
|
||||
android:id="@+id/sample_main_layout">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/sample_output"
|
||||
android:layout_width="0px"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
style="@style/Widget.SampleMessageTile"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
style="@style/Widget.SampleMessage"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="@dimen/margin_medium"
|
||||
android:paddingRight="@dimen/margin_medium"
|
||||
android:paddingTop="@dimen/margin_large"
|
||||
android:paddingBottom="@dimen/margin_large"
|
||||
android:text="@string/intro_message" />
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/darker_gray" />
|
||||
|
||||
<fragment
|
||||
android:name="org.surfsite.iconsole.common.logger.LogFragment"
|
||||
android:id="@+id/log_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/darker_gray" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/sample_content_fragment"
|
||||
android:layout_weight="2"
|
||||
|
|
|
@ -20,28 +20,9 @@
|
|||
android:layout_height="match_parent"
|
||||
android:id="@+id/sample_main_layout">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/sample_output"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px"
|
||||
android:layout_weight="1">
|
||||
|
||||
<fragment
|
||||
android:name="org.surfsite.iconsole.common.logger.LogFragment"
|
||||
android:id="@+id/log_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@android:color/darker_gray" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/sample_content_fragment"
|
||||
android:layout_weight="2"
|
||||
android:layout_weight="4"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0px" />
|
||||
|
||||
|
|
|
@ -22,147 +22,272 @@
|
|||
tools:layout_editor_absoluteY="0dp"
|
||||
tools:layout_editor_absoluteX="0dp" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView8"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="RPM"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/RPM"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline6"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView7"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Calories"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Calories"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline3"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline6"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView6"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Heart"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Heart"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline"
|
||||
android:layout_marginRight="16dp"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView5"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Distance"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Distance"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline"
|
||||
android:layout_marginRight="16dp"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline5"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView4"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Speed"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Speed"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline3"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4"
|
||||
android:layout_marginTop="16dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView3"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Power"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Power"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline5"
|
||||
app:layout_constraintVertical_bias="0.333" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Time"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
app:layout_constraintBottom_toTopOf="@+id/Time"
|
||||
app:layout_constraintHorizontal_bias="0.501"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<NumberPicker
|
||||
android:id="@+id/Level"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline2"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guideline"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4"
|
||||
app:layout_constraintHorizontal_bias="0.484"
|
||||
app:layout_constraintVertical_bias="0.671" />
|
||||
|
||||
<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_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/time_n00_00_00"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline5"
|
||||
app:layout_constraintHorizontal_bias="0.501"
|
||||
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" />
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Speed"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/speed_n0_0_km_h"
|
||||
android:textAlignment="center"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
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" />
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4" />
|
||||
|
||||
<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" />
|
||||
android:id="@+id/Power"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/power_n0_0_w"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline4"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline5" />
|
||||
|
||||
<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/RPM"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/rpm_n0"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline2"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline6" />
|
||||
|
||||
<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" />
|
||||
<TextView
|
||||
android:id="@+id/Distance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/distance_n0_0_km"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline4"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline5"
|
||||
app:layout_constraintVertical_bias="0.538" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Calories"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/calories_n0_cal"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline2"
|
||||
app:layout_constraintHorizontal_bias="0.507"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline6" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/Heart"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:fontFamily="monospace"
|
||||
android:gravity="center"
|
||||
android:text="@string/heart_n0"
|
||||
android:textAlignment="center"
|
||||
android:textAppearance="@android:style/TextAppearance.DeviceDefault.Medium"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/guideline6"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/guideline3"
|
||||
app:layout_constraintRight_toLeftOf="@+id/guideline"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline4"
|
||||
app:layout_constraintVertical_bias="0.461" />
|
||||
|
||||
<android.support.constraint.Guideline
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -235,58 +360,58 @@
|
|||
tools:layout_editor_absoluteX="0dp" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/guideline2">
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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">
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
<Button
|
||||
android:id="@+id/button_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/start" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_start"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/start" />
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
<Button
|
||||
android:id="@+id/button_stop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/stop" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_stop"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/stop" />
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="4" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
<Button
|
||||
android:id="@+id/button_disconnect"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/disconnect" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_disconnect"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/disconnect" />
|
||||
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
<Space
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1" />
|
||||
</LinearLayout>
|
||||
|
||||
</android.support.constraint.ConstraintLayout>
|
||||
|
|
|
@ -39,14 +39,16 @@
|
|||
<string name="start">Start</string>
|
||||
<string name="stop">Stop</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="time_n00_00_00">00:00:00</string>
|
||||
<string name="speed_n0_0_km_h">0.0</string>
|
||||
<string name="rpm_n0">0</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="distance_n0_0_km">0.0</string>
|
||||
<string name="calories_n0_cal">0</string>
|
||||
<string name="heart_n0">0</string>
|
||||
<string name="power_n0_0_w">0.0</string>
|
||||
<string name="level">Level</string>
|
||||
<string name="local_service_started">iConsole Bluetooth active</string>
|
||||
<string name="local_service_label">OpeniConsole</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -38,5 +38,4 @@
|
|||
<item name="android:shadowDy">-3.5</item>
|
||||
<item name="android:shadowRadius">2</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue