Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package tech.timmo.terminalwatch;
- import android.annotation.SuppressLint;
- import android.content.BroadcastReceiver;
- import android.content.Context;
- import android.content.Intent;
- import android.content.IntentFilter;
- import android.content.SharedPreferences;
- import android.content.pm.PackageManager;
- import android.content.res.Resources;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Rect;
- import android.os.AsyncTask;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.preference.PreferenceManager;
- import android.support.annotation.NonNull;
- import android.support.annotation.Nullable;
- import android.support.v4.content.ContextCompat;
- import android.support.wearable.watchface.CanvasWatchFaceService;
- import android.support.wearable.watchface.WatchFaceStyle;
- import android.text.format.DateFormat;
- import android.util.Log;
- import android.view.SurfaceHolder;
- import android.view.WindowInsets;
- import com.google.android.gms.common.ConnectionResult;
- import com.google.android.gms.common.Scopes;
- import com.google.android.gms.common.api.GoogleApiClient;
- import com.google.android.gms.common.api.ResultCallback;
- import com.google.android.gms.common.api.Scope;
- import com.google.android.gms.common.api.Status;
- import com.google.android.gms.fitness.Fitness;
- import com.google.android.gms.fitness.data.DataPoint;
- import com.google.android.gms.fitness.data.DataSource;
- import com.google.android.gms.fitness.data.DataType;
- import com.google.android.gms.fitness.data.Field;
- import com.google.android.gms.fitness.data.Value;
- import com.google.android.gms.fitness.request.DataSourcesRequest;
- import com.google.android.gms.fitness.request.OnDataPointListener;
- import com.google.android.gms.fitness.request.SensorRequest;
- import com.google.android.gms.fitness.result.DataSourcesResult;
- import com.google.android.gms.wearable.DataApi;
- import com.google.android.gms.wearable.DataEvent;
- import com.google.android.gms.wearable.DataEventBuffer;
- import com.google.android.gms.wearable.DataItem;
- import com.google.android.gms.wearable.DataMap;
- import com.google.android.gms.wearable.DataMapItem;
- import com.google.android.gms.wearable.Wearable;
- import java.lang.ref.WeakReference;
- import java.util.ArrayList;
- import java.util.Calendar;
- import java.util.TimeZone;
- import java.util.concurrent.TimeUnit;
- import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
- public class WatchFace extends CanvasWatchFaceService implements
- DataApi.DataListener,
- GoogleApiClient.ConnectionCallbacks,
- GoogleApiClient.OnConnectionFailedListener {
- private static final String TAG = WatchFace.class.getSimpleName();
- private static final long INTERACTIVE_UPDATE_RATE_MS = TimeUnit.SECONDS.toMillis(1);
- private static final long GET_EXTRAS_UPDATE_RATE_MS = TimeUnit.MINUTES.toMillis(1);
- private static final int MSG_UPDATE_TIME = 0;
- boolean permissionsGranted;
- private String user, hostname, mPhoneBatt, mCurrTemp, mHeartRate = "";
- private int timeFormat, dateFormat;
- private boolean period;
- private GoogleApiClient googleApiClient;
- private OnDataPointListener onDataPointListener;
- @Override
- public void onCreate() {
- super.onCreate();
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
- // Check for permissions
- if (!checkPermissions() && preferences.getBoolean(Utility.PREF_FIRST_RUN, true)) {
- startActivity(new Intent(WatchFace.this, WatchFacePermissionActivity.class)
- .setFlags(FLAG_ACTIVITY_NEW_TASK));
- }
- preferences.edit().putBoolean(Utility.PREF_FIRST_RUN, false).apply();
- permissionsGranted = checkPermissions();
- Log.d(TAG, permissionsGranted ? "Permissions Granted!" : "Permissions Denied.");
- googleApiClient = new GoogleApiClient.Builder(this)
- .addApi(Wearable.API)
- .addConnectionCallbacks(this)
- .addOnConnectionFailedListener(this)
- .addApi(Fitness.SENSORS_API)
- .addScope(new Scope(Scopes.FITNESS_LOCATION_READ))
- .build();
- googleApiClient.connect();
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- Wearable.DataApi.removeListener(googleApiClient, this);
- Fitness.SensorsApi.remove(
- googleApiClient,
- onDataPointListener)
- .setResultCallback(new ResultCallback<Status>() {
- @Override
- public void onResult(@NonNull Status status) {
- if (status.isSuccess()) {
- Log.i(TAG, "Listener was removed!");
- } else {
- Log.i(TAG, "Listener was not removed.");
- }
- }
- });
- googleApiClient.disconnect();
- }
- @Override
- public void onConnected(@Nullable Bundle bundle) {
- Wearable.DataApi.addListener(googleApiClient, this);
- Log.i(TAG, "Connected!");
- if (permissionsGranted) {
- // Now you can make calls to the Fitness APIs.
- Fitness.SensorsApi.findDataSources(googleApiClient, new DataSourcesRequest.Builder()
- // At least one datatype must be specified.
- .setDataTypes(DataType.TYPE_HEART_RATE_BPM)
- // Can specify whether data type is raw or derived.
- .setDataSourceTypes(DataSource.TYPE_RAW)
- .build())
- .setResultCallback(new ResultCallback<DataSourcesResult>() {
- @Override
- public void onResult(@NonNull DataSourcesResult dataSourcesResult) {
- Log.i(TAG, "Result: " + dataSourcesResult.getStatus().toString());
- for (DataSource dataSource : dataSourcesResult.getDataSources()) {
- Log.i(TAG, "Data source found: " + dataSource.toString());
- Log.i(TAG, "Data Source type: " + dataSource.getDataType().getName());
- mHeartRate = dataSource.getDataType().equals(DataType.TYPE_HEART_RATE_BPM)
- ? dataSource.toString() + " BPM" : "";
- //Let's register a listener to receive Activity data!
- if (dataSource.getDataType().equals(DataType.TYPE_HEART_RATE_BPM)
- && onDataPointListener == null) {
- Log.i(TAG, "Data source for LOCATION_SAMPLE found! Registering.");
- registerFitnessDataListener(dataSource);
- }
- }
- }
- });
- }
- }
- @Override
- public void onConnectionSuspended(int i) {
- // If your connection to the sensor gets lost at some point,
- // you'll be able to determine the reason and react to it here.
- if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_NETWORK_LOST) {
- Log.i(TAG, "Connection lost. Cause: Network Lost.");
- } else if (i == GoogleApiClient.ConnectionCallbacks.CAUSE_SERVICE_DISCONNECTED) {
- Log.i(TAG, "Connection lost. Reason: Service Disconnected");
- }
- }
- @Override
- public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
- Log.e(TAG, "Google Play services connection failed: " + connectionResult);
- }
- @Override
- public Engine onCreateEngine() {
- return new Engine();
- }
- @Override
- public void onDataChanged(DataEventBuffer dataEvents) {
- for (DataEvent event : dataEvents) {
- if (event.getType() == DataEvent.TYPE_CHANGED) {
- // DataItem changed
- DataItem item = event.getDataItem();
- if (item.getUri().getPath().compareTo("/prefs") == 0) {
- DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
- updateFacePrefs(
- dataMap.getString(Utility.PREF_USER),
- dataMap.getString(Utility.PREF_HOSTNAME),
- dataMap.getInt(Utility.PREF_TIME_FORMAT),
- dataMap.getBoolean(Utility.PREF_PERIOD),
- dataMap.getInt(Utility.PREF_DATE_FORMAT)
- );
- }
- if (item.getUri().getPath().compareTo("/extras") == 0) {
- DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
- updateFaceExtras(
- dataMap.getString(Utility.EXTRA_BATT),
- dataMap.getString(Utility.EXTRA_TEMP)
- //dataMap.getString(Utility.EXTRA_HEART)
- );
- }
- }
- // else if (event.getType() == DataEvent.TYPE_DELETED) {
- // DataItem deleted
- // }
- }
- }
- private void updateFacePrefs(String user, String hostname,
- int timeFormat, boolean period, int dateFormat) {
- this.user = user;
- this.hostname = hostname;
- this.timeFormat = timeFormat;
- this.period = period;
- this.dateFormat = dateFormat;
- PreferenceManager.getDefaultSharedPreferences(this).edit()
- .putString(Utility.PREF_USER, user)
- .putString(Utility.PREF_HOSTNAME, hostname)
- .putInt(Utility.PREF_TIME_FORMAT, timeFormat)
- .putBoolean(Utility.PREF_PERIOD, period)
- .putInt(Utility.PREF_DATE_FORMAT, dateFormat)
- .apply();
- }
- private void updateFaceExtras(String batteryLvl, String temp) { //, String mHeartRate
- //TODO
- mPhoneBatt = batteryLvl;
- mCurrTemp = temp;
- }
- private void registerFitnessDataListener(DataSource dataSource) {
- onDataPointListener = new OnDataPointListener() {
- @Override
- public void onDataPoint(DataPoint dataPoint) {
- for (Field field : dataPoint.getDataType().getFields()) {
- Value val = dataPoint.getValue(field);
- Log.i(TAG, "Detected DataPoint field: " + field.getName());
- Log.i(TAG, "Detected DataPoint value: " + val);
- }
- }
- };
- Fitness.SensorsApi.add(
- googleApiClient,
- new SensorRequest.Builder()
- .setDataSource(dataSource) // Optional but recommended for custom data sets.
- .setDataType(DataType.TYPE_HEART_RATE_BPM) // Can't be omitted.
- .setSamplingRate(10, TimeUnit.SECONDS)
- .build(),
- onDataPointListener)
- .setResultCallback(new ResultCallback<Status>() {
- @Override
- public void onResult(@NonNull Status status) {
- if (status.isSuccess()) {
- Log.i(TAG, "Listener registered!");
- } else {
- Log.i(TAG, "Listener not registered.");
- }
- }
- });
- }
- private boolean checkPermissions() {
- int permissionCheck1 = ContextCompat.checkSelfPermission(WatchFace.this,
- Manifest.permission.ACCESS_FINE_LOCATION);
- int permissionCheck2 = ContextCompat.checkSelfPermission(WatchFace.this,
- Manifest.permission.BODY_SENSORS);
- return permissionCheck1 == PackageManager.PERMISSION_GRANTED
- && permissionCheck2 == PackageManager.PERMISSION_GRANTED;
- }
- private static class EngineHandler extends Handler {
- private final WeakReference<WatchFace.Engine> mWeakReference;
- EngineHandler(WatchFace.Engine reference) {
- mWeakReference = new WeakReference<>(reference);
- }
- @Override
- public void handleMessage(Message msg) {
- WatchFace.Engine engine = mWeakReference.get();
- if (engine != null) {
- switch (msg.what) {
- case MSG_UPDATE_TIME:
- engine.handleUpdateTimeMessage();
- break;
- }
- }
- }
- }
- private class Engine extends CanvasWatchFaceService.Engine {
- private static final int MSG_GET_EXTRAS = 1000;
- private final Handler mUpdateTimeHandler = new EngineHandler(this);
- private final Rect mCardBounds = new Rect();
- private final Paint mPeekCardBackgroundPaint = new Paint();
- private Paint mBackgroundPaint;
- private Paint mTextPaint;
- private Calendar calendar;
- private final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- calendar.setTimeZone(TimeZone.getDefault());
- invalidate();
- }
- };
- private ArrayList<String> arrayListExtras, arrayListLines;
- private AsyncTask<Void, Void, ArrayList<String>> mLoadExtrasTask;
- @SuppressLint("HandlerLeak")
- private final Handler mGetExtrasHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case MSG_GET_EXTRAS:
- if (mLoadExtrasTask != null) {
- mLoadExtrasTask.cancel(true);
- }
- mLoadExtrasTask = new LoadExtrasTask();
- mLoadExtrasTask.execute();
- break;
- }
- }
- };
- private boolean mAmbient, mBlink;
- private boolean mRegisteredTimeZoneReceiver = false;
- private float mXOffset, mXOffsetExL, mXOffsetExR;
- private float[] mYOffsets;
- private boolean mLowBitAmbient;
- private float mTextSize;
- @Override
- public void onCreate(SurfaceHolder holder) {
- super.onCreate(holder);
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(WatchFace.this);
- user = preferences.getString(Utility.PREF_USER, "user");
- hostname = preferences.getString(Utility.PREF_HOSTNAME, "wear");
- timeFormat = preferences.getInt(Utility.PREF_TIME_FORMAT, 0);
- period = preferences.getBoolean(Utility.PREF_PERIOD, DateFormat.is24HourFormat(WatchFace.this));
- dateFormat = preferences.getInt(Utility.PREF_DATE_FORMAT, 0);
- setWatchFaceStyle(new WatchFaceStyle.Builder(WatchFace.this)
- .setCardPeekMode(WatchFaceStyle.PEEK_MODE_SHORT)
- .setAmbientPeekMode(WatchFaceStyle.AMBIENT_PEEK_MODE_VISIBLE)
- .setPeekOpacityMode(WatchFaceStyle.PEEK_OPACITY_MODE_TRANSLUCENT)
- .setBackgroundVisibility(WatchFaceStyle.BACKGROUND_VISIBILITY_INTERRUPTIVE)
- .setShowSystemUiTime(false)
- .setAcceptsTapEvents(true)
- .build());
- Resources resources = WatchFace.this.getResources();
- mYOffsets = new float[]{
- resources.getDimension(R.dimen.digital_y_offset_0),
- resources.getDimension(R.dimen.digital_y_offset_1),
- resources.getDimension(R.dimen.digital_y_offset_2),
- resources.getDimension(R.dimen.digital_y_offset_3),
- resources.getDimension(R.dimen.digital_y_offset_4),
- resources.getDimension(R.dimen.digital_y_offset_5),
- resources.getDimension(R.dimen.digital_y_offset_6),
- resources.getDimension(R.dimen.digital_y_offset_7)
- };
- mBackgroundPaint = new Paint();
- mBackgroundPaint.setColor(getColor(R.color.background));
- mTextPaint = new Paint();
- mTextPaint = createTextPaint(getColor(R.color.digital_text));
- calendar = Calendar.getInstance();
- arrayListLines = new ArrayList<>();
- arrayListExtras = new ArrayList<>();
- arrayListExtras.add("");
- arrayListExtras.add("");
- arrayListExtras.add("");
- arrayListExtras.add("");
- }
- @Override
- public void onDestroy() {
- mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
- super.onDestroy();
- }
- private Paint createTextPaint(int textColor) {
- Paint paint = new Paint();
- paint.setColor(textColor);
- paint.setTypeface(Utility.getFont(WatchFace.this, 0));
- //preferences.getInt(Utility.PREF_FONT, 0)));
- paint.setAntiAlias(true);
- return paint;
- }
- @Override
- public void onVisibilityChanged(boolean visible) {
- super.onVisibilityChanged(visible);
- if (visible) {
- registerReceiver();
- // Update time zone in case it changed while we weren't visible.
- calendar.setTimeZone(TimeZone.getDefault());
- mGetExtrasHandler.sendEmptyMessage(MSG_GET_EXTRAS);
- invalidate();
- } else {
- unregisterReceiver();
- mGetExtrasHandler.removeMessages(MSG_GET_EXTRAS);
- if (mLoadExtrasTask != null) {
- mLoadExtrasTask.cancel(true);
- }
- }
- // Whether the timer should be running depends on whether we're visible (as well as
- // whether we're in ambient mode), so we may need to start or stop the timer.
- updateTimer();
- }
- private void registerReceiver() {
- if (mRegisteredTimeZoneReceiver) {
- return;
- }
- mRegisteredTimeZoneReceiver = true;
- IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED);
- WatchFace.this.registerReceiver(mTimeZoneReceiver, filter);
- }
- private void unregisterReceiver() {
- if (!mRegisteredTimeZoneReceiver) {
- return;
- }
- mRegisteredTimeZoneReceiver = false;
- WatchFace.this.unregisterReceiver(mTimeZoneReceiver);
- }
- @Override
- public void onApplyWindowInsets(WindowInsets insets) {
- super.onApplyWindowInsets(insets);
- Resources resources = WatchFace.this.getResources();
- boolean isRound = insets.isRound();
- mXOffset = resources.getDimension(isRound
- ? R.dimen.digital_x_offset_round
- : R.dimen.digital_x_offset);
- mXOffsetExL = resources.getDimension(isRound
- ? R.dimen.digital_x_offset_ex_l_round
- : R.dimen.digital_x_offset_ex_l);
- mXOffsetExR = resources.getDimension(isRound
- ? R.dimen.digital_x_offset_ex_r_round
- : R.dimen.digital_x_offset_ex_r);
- mTextSize = resources.getDimension(isRound
- ? R.dimen.digital_text_size_round
- : R.dimen.digital_text_size);
- mTextPaint.setTextSize(mTextSize);
- }
- @Override
- public void onPropertiesChanged(Bundle properties) {
- super.onPropertiesChanged(properties);
- mLowBitAmbient = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
- }
- @Override
- public void onTimeTick() {
- super.onTimeTick();
- invalidate();
- }
- @Override
- public void onAmbientModeChanged(boolean inAmbientMode) {
- super.onAmbientModeChanged(inAmbientMode);
- if (mAmbient != inAmbientMode) {
- mAmbient = inAmbientMode;
- if (mLowBitAmbient) {
- mTextPaint.setAntiAlias(!inAmbientMode);
- }
- invalidate();
- }
- // Whether the timer should be running depends on whether we're visible (as well as
- // whether we're in ambient mode), so we may need to start or stop the timer.
- updateTimer();
- }
- @Override
- public void onTapCommand(int tapType, int x, int y, long eventTime) {
- switch (tapType) {
- case TAP_TYPE_TOUCH:
- // The user has started touching the screen.
- break;
- case TAP_TYPE_TOUCH_CANCEL:
- // The user has started a different gesture or otherwise cancelled the tap.
- break;
- case TAP_TYPE_TAP:
- // The user has completed the tap gesture.
- mBlink = false;
- invalidate();
- //updateTimer();
- break;
- }
- invalidate();
- }
- @Override
- public void onPeekCardPositionUpdate(Rect bounds) {
- super.onPeekCardPositionUpdate(bounds);
- //if (Log.isLoggable(TAG, Log.DEBUG)) {
- // Log.d(TAG, "onPeekCardPositionUpdate: " + bounds);
- //}
- if (!bounds.equals(mCardBounds)) {
- mCardBounds.set(bounds);
- invalidate();
- }
- }
- @Override
- public void onDraw(Canvas canvas, Rect bounds) {
- canvas.drawColor(Color.BLACK);
- if (isInAmbientMode()) {
- canvas.drawRect(mCardBounds, mPeekCardBackgroundPaint);
- }
- long now = System.currentTimeMillis();
- calendar.setTimeInMillis(now);
- arrayListLines.clear();
- arrayListLines.addAll(arrayListExtras);
- arrayListLines.addAll(Utility.getTimeDate(
- calendar,
- user,
- hostname,
- mAmbient ? 0 : timeFormat,
- period,
- dateFormat));
- // TODO CHECK PERMS FIRST IN ONCREATE
- try {
- canvas.drawText(arrayListLines.get(0), mXOffsetExL, mYOffsets[0], mTextPaint);
- canvas.drawText(arrayListLines.get(1), bounds.right - mXOffsetExR, mYOffsets[1], mTextPaint);
- canvas.drawText(arrayListLines.get(2), mXOffsetExL, mYOffsets[2], mTextPaint);
- canvas.drawText(arrayListLines.get(3), bounds.right - mXOffsetExR, mYOffsets[3], mTextPaint);
- } catch (NullPointerException e) {
- Log.e(TAG, e.toString());
- }
- canvas.drawText(arrayListLines.get(4), mXOffset, mYOffsets[4], mTextPaint);
- canvas.drawText(arrayListLines.get(5), mXOffset, mYOffsets[5], mTextPaint);
- canvas.drawText(arrayListLines.get(6), mXOffset, mYOffsets[6], mTextPaint);
- if (!mBlink && !mAmbient) {
- mBlink = true;
- canvas.drawText(arrayListLines.get(7), mXOffset, mYOffsets[7], mTextPaint);
- } else {
- mBlink = false;
- canvas.drawText(arrayListLines.get(8), mXOffset, mYOffsets[7], mTextPaint);
- }
- }
- private void updateTimer() {
- mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
- if (shouldTimerBeRunning()) {
- mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
- }
- }
- private boolean shouldTimerBeRunning() {
- return isVisible() && !isInAmbientMode();
- }
- private void handleUpdateTimeMessage() {
- invalidate();
- if (shouldTimerBeRunning()) {
- long timeMs = System.currentTimeMillis();
- long delayMs = INTERACTIVE_UPDATE_RATE_MS
- - (timeMs % INTERACTIVE_UPDATE_RATE_MS);
- mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
- }
- }
- private class LoadExtrasTask extends AsyncTask<Void, Void, ArrayList<String>> {
- @Override
- protected ArrayList<String> doInBackground(Void... voids) {
- ArrayList<String> arrayListExtras = new ArrayList<>();
- arrayListExtras.add(Utility.getBattLvl(WatchFace.this));
- arrayListExtras.add(mPhoneBatt);
- arrayListExtras.add(mCurrTemp);
- arrayListExtras.add(mHeartRate);
- return arrayListExtras;
- }
- @Override
- protected void onPostExecute(ArrayList<String> arrayList) {
- if (arrayList != null) {
- arrayListExtras = arrayList;
- invalidate();
- }
- if (isVisible()) {
- mGetExtrasHandler.sendEmptyMessageDelayed(
- MSG_GET_EXTRAS, GET_EXTRAS_UPDATE_RATE_MS);
- }
- }
- }
- }
- }
Add Comment
Please, Sign In to add comment