com.damageddev.myotaskerplugin.services.BackgroundService.java Source code

Java tutorial

Introduction

Here is the source code for com.damageddev.myotaskerplugin.services.BackgroundService.java

Source

/*
 * Copyright 2013 two forty four a.m. LLC <http://www.twofortyfouram.com>
 *
 * 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 com.damageddev.myotaskerplugin.services;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import com.damageddev.myotaskerplugin.EditActivity;
import com.damageddev.myotaskerplugin.R;
import com.damageddev.myotaskerplugin.utils.Constants;
import com.damageddev.myotaskerplugin.utils.TaskerPlugin;
import com.thalmic.myo.AbstractDeviceListener;
import com.thalmic.myo.DeviceListener;
import com.thalmic.myo.Hub;
import com.thalmic.myo.Myo;
import com.thalmic.myo.Pose;
import com.thalmic.myo.Vector3;
import com.thalmic.myo.Quaternion;
import com.thalmic.myo.XDirection;

public final class BackgroundService extends Service {
    public static final int NOTIFICATION_ID = 6592;

    public static final String ACTION_DISCONNECT = "com.damageddev.myotaskerplugin.ACTION_DISCONNECT";
    public static final String ACTION_CONNECT = " com.damageddev.myotaskerplugin.ACTION_CONNECT";

    private static final String SHOW_MYO_STATUS_NOTIFICATION = "show_myo_status_notification";
    private static final Intent INTENT_REQUEST_REQUERY = new Intent(
            com.twofortyfouram.locale.Intent.ACTION_REQUEST_QUERY)
                    .putExtra(com.twofortyfouram.locale.Intent.EXTRA_ACTIVITY, EditActivity.class.getName());

    private boolean isUnlocked;

    private Toast mToast;
    private Hub mHub;

    private Vector3 vect;
    private Vector3 gyro;

    private float roll;
    private float pitch;
    private float yaw;

    private Vector3 lastVect;
    private Vector3 lastGyro;

    private float lastRoll;
    private float lastPitch;
    private float lastYaw;
    private long lastTimePose = 0;

    private boolean rollUnlock = false;
    private long lastPoseTime = 0;
    private int poseInRow = 0;
    private long lastTimestampRealtimeSend = 0;
    private boolean realTimeProgress = false;

    private long unlockTime;

    private Pose lastPos;
    private Pose lastPosFull = Pose.UNKNOWN;

    private NotificationManager mNotificationManager;
    private NotificationCompat.Builder mNotificationBuilder;

    private long mLastUnlockTime = 0;
    private long mLastUnlockGesture = 0;

    @Override
    public void onCreate() {
        super.onCreate();

        mHub = Hub.getInstance();
        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //mHub.setLockingPolicy(Hub.LockingPolicy.NONE);
    }

    private DeviceListener mListener = new AbstractDeviceListener() {
        @Override
        public void onConnect(Myo myo, long timestamp) {
            showToast(getString(R.string.myo_connected));

            SharedPreferences sharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME,
                    Context.MODE_MULTI_PROCESS);
            unlockTime = Long.valueOf(sharedPreferences.getString("relock_time", "5")) * 1000;

            if (sharedPreferences.getBoolean(SHOW_MYO_STATUS_NOTIFICATION, true)) {
                mNotificationBuilder = buildDisconnectNotification()
                        .setContentTitle(getString(R.string.myo_connected)).setContentText(myo.getName())
                        .setSubText(myo.getMacAddress());
                mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
            }
        }

        @Override
        public void onUnlock(Myo myo, long timestamp) {
            //myo.vibrate(Myo.VibrationType.LONG);
            //isUnlocked=true;
        }

        @Override
        public void onLock(Myo myo, long timestamp) {
            //isUnlocked=false;
        }

        @Override
        public void onDisconnect(Myo myo, long timestamp) {

            SharedPreferences sharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME,
                    Context.MODE_MULTI_PROCESS);

            if (sharedPreferences.getBoolean(SHOW_MYO_STATUS_NOTIFICATION, true)) {
                mNotificationBuilder = buildConnectNotification()
                        .setContentTitle(getString(R.string.disconnected_from_myo))
                        .setContentText(getString(R.string.last_connected_to) + " " + myo.getName());
                mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
            }
        }

        @Override
        public void onGyroscopeData(Myo myo, long timestamp, Vector3 gyr) {
            gyro = gyr;
        }

        @Override
        public void onOrientationData(Myo myo, long timestamp, Quaternion rotation) {

            isUnlocked = (mLastUnlockTime + unlockTime) > timestamp;
            if (!isUnlocked)
                rollUnlock = false;

            if (lastPosFull != Pose.REST && lastPosFull != Pose.UNKNOWN)
                poseInRow++;

            // Calculate Euler angles (roll, pitch, and yaw) from the quaternion.
            roll = (float) Math.toDegrees(Quaternion.roll(rotation));
            pitch = (float) Math.toDegrees(Quaternion.pitch(rotation));
            yaw = (float) Math.toDegrees(Quaternion.yaw(rotation));
            // Adjust roll and pitch for the orientation of the Myo on the arm.
            if (myo.getXDirection() != XDirection.TOWARD_ELBOW) {
                roll *= -1;
                pitch *= -1;
            }
            //Log.i("MainActivity", "dif: "+(timestamp-lastPoseTime)+" "+(lastPos==Pose.DOUBLE_TAP)+" "+(lastRoll-roll)/*+" ru:"+rollUnlock*/);
            Log.i("MainActivity", "posInRow dif: " + poseInRow);

            if (lastPos == Pose.DOUBLE_TAP && /*Math.abs(lastRoll-roll)>30*/vect.length() > 2
                    && (timestamp - lastPoseTime) < 1000 && !rollUnlock && !isUnlocked) {
                rollUnlock = true;
                mLastUnlockTime = timestamp;
                mLastUnlockGesture = timestamp;
                myo.vibrate(Myo.VibrationType.SHORT);
            }

            if (isUnlocked && poseInRow > 30) {
                if (!realTimeProgress) {
                    Log.i("LastRoll", "lastRoll:" + lastRoll);
                }
                realTimeProgress = true;
                if ((timestamp - lastTimestampRealtimeSend) > 300) {
                    lastTimestampRealtimeSend = timestamp;
                    mLastUnlockTime = timestamp;
                    if (lastPos == Pose.FIST) {
                        Bundle bundle = getPositionBundle("first_hold");
                        TaskerPlugin.Event.addPassThroughData(INTENT_REQUEST_REQUERY, bundle);
                        BackgroundService.this.sendBroadcast(INTENT_REQUEST_REQUERY);
                    }
                    if (lastPos == Pose.WAVE_IN) {
                        Bundle bundle = getPositionBundle("wave_in_hold");
                        TaskerPlugin.Event.addPassThroughData(INTENT_REQUEST_REQUERY, bundle);
                        BackgroundService.this.sendBroadcast(INTENT_REQUEST_REQUERY);
                    }
                    if (lastPos == Pose.WAVE_OUT) {
                        Bundle bundle = getPositionBundle("wave_out_hold");
                        TaskerPlugin.Event.addPassThroughData(INTENT_REQUEST_REQUERY, bundle);
                        BackgroundService.this.sendBroadcast(INTENT_REQUEST_REQUERY);
                    }
                    if (lastPos == Pose.FINGERS_SPREAD) {
                        Bundle bundle = getPositionBundle("fingers_spread_hold");
                        TaskerPlugin.Event.addPassThroughData(INTENT_REQUEST_REQUERY, bundle);
                        BackgroundService.this.sendBroadcast(INTENT_REQUEST_REQUERY);
                    }
                    lastGyro = gyro;
                    lastVect = vect;
                    lastPitch = pitch;
                    lastRoll = roll;
                    lastYaw = yaw;
                }
            }

        }

        @Override
        public void onAccelerometerData(Myo myo, long timestamp, Vector3 vec) {
            vect = vec;
            Log.i("AccelVector", "Length: " + vect.length());
        }

        public Bundle getPositionBundle(String pose) {
            Bundle bundle = new Bundle();

            bundle.putString(Constants.POSE, pose);
            bundle.putDouble(Constants.ACCEL_X, vect.x());
            bundle.putDouble(Constants.ACCEL_Y, vect.y());
            bundle.putDouble(Constants.ACCEL_Z, vect.z());

            bundle.putDouble(Constants.GYRO_X, gyro.x());
            bundle.putDouble(Constants.GYRO_X_DIFF, lastGyro.x() - gyro.x());
            bundle.putDouble(Constants.GYRO_Y, gyro.y());
            bundle.putDouble(Constants.GYRO_Y_DIFF, lastGyro.y() - gyro.y());
            bundle.putDouble(Constants.GYRO_Z, gyro.z());
            bundle.putDouble(Constants.GYRO_Z_DIFF, lastGyro.z() - gyro.z());

            bundle.putDouble(Constants.ROLL, roll);
            bundle.putDouble(Constants.ROLL_DIFF, lastRoll - roll);
            bundle.putDouble(Constants.PITCH, pitch);
            bundle.putDouble(Constants.PITCH_DIFF, lastPitch - pitch);
            bundle.putDouble(Constants.YAW, yaw);
            bundle.putDouble(Constants.YAW_DIFF, lastYaw - yaw);
            return bundle;
        }

        @Override
        public void onPose(Myo myo, long timestamp, Pose pose) {

            if ((timestamp - mLastUnlockGesture) < 700/* || (poseInRow<2 && pose != Pose.DOUBLE_TAP)*/) {
                Log.i("MainActivity", "lastPosFull false: " + pose.toString());
                return;
            }
            /*if(timestamp-lastTimePose<50)
               return;*/
            lastTimePose = timestamp;
            //showToast(pose.toString());

            Log.i("MainActivity", "poseInRow reset");
            poseInRow = 0;

            if (pose != Pose.REST && pose != Pose.UNKNOWN) {
                lastPos = pose;
                lastPoseTime = timestamp;
                lastGyro = gyro;
                lastVect = vect;
                lastPitch = pitch;
                lastRoll = roll;
                lastYaw = yaw;
            }

            SharedPreferences sharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME,
                    Context.MODE_MULTI_PROCESS);

            //long unlockTime = Long.valueOf(sharedPreferences.getString("relock_time", "5")) * 1000;

            //boolean isUnlocked = (mLastUnlockTime + unlockTime) > timestamp;

            /*
               if (pose == Pose.DOUBLE_TAP && !isUnlocked && rollUnlock) {
            mLastUnlockTime = timestamp;
            myo.vibrate(Myo.VibrationType.SHORT);
               }
               */

            if (isUnlocked && (pose == Pose.REST || pose == Pose.UNKNOWN) && !realTimeProgress) {
                Log.i("SendStatic", lastPosFull.toString());
                Bundle bundle = getPositionBundle(lastPosFull.toString());
                TaskerPlugin.Event.addPassThroughData(INTENT_REQUEST_REQUERY, bundle);
                BackgroundService.this.sendBroadcast(INTENT_REQUEST_REQUERY);
                mLastUnlockTime = timestamp;
            }
            if (isUnlocked && (pose != Pose.REST || pose != Pose.UNKNOWN)) {
                /*
                    TaskerPlugin.Event.addPassThroughData(INTENT_REQUEST_REQUERY, bundle);
                    BackgroundService.this.sendBroadcast(INTENT_REQUEST_REQUERY);
                    mLastUnlockTime = timestamp;
                    */

                if (sharedPreferences.getBoolean("show_toasts", true)) {
                    showToast(pose.toString());
                }

                if (sharedPreferences.getBoolean(SHOW_MYO_STATUS_NOTIFICATION, true)) {
                    mNotificationBuilder.setSubText(myo.getMacAddress()).setContentTitle(myo.getName())
                            .setContentText(getString(R.string.last_gesture) + " " + pose.toString());
                    mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
                }

            }
            lastPosFull = pose;
            Log.i("MainActivity", "lastPosFull: " + lastPosFull.toString());
            if (pose == Pose.DOUBLE_TAP && isUnlocked) {
                mLastUnlockTime = 0;
                isUnlocked = false;
                rollUnlock = false;
                lastPos = Pose.UNKNOWN;
                myo.vibrate(Myo.VibrationType.SHORT);
            }
            realTimeProgress = false;
        }

        @Override
        public void onAttach(Myo myo, long timestamp) {
            super.onAttach(myo, timestamp);

            SharedPreferences sharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME,
                    Context.MODE_MULTI_PROCESS);

            if (sharedPreferences.getBoolean(SHOW_MYO_STATUS_NOTIFICATION, true)) {
                mNotificationBuilder.setContentTitle(getString(R.string.myo_attached))
                        .setContentText(myo.getName());
                mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
            }
        }

        @Override
        public void onDetach(Myo myo, long timestamp) {
            super.onDetach(myo, timestamp);

            mHub.attachToAdjacentMyo();

            SharedPreferences sharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME,
                    Context.MODE_MULTI_PROCESS);

            if (sharedPreferences.getBoolean(SHOW_MYO_STATUS_NOTIFICATION, true)) {
                mNotificationBuilder.setContentTitle(getString(R.string.myo_detached)).setContentText(myo.getName())
                        .setContentText(getString(R.string.detached_myo) + " " + myo.getName());
                mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
            }
        }

        @Override
        public void onArmUnsync(Myo myo, long timestamp) {
            super.onArmUnsync(myo, timestamp);

            SharedPreferences sharedPreferences = getSharedPreferences(Constants.SHARED_PREFERENCES_NAME,
                    Context.MODE_MULTI_PROCESS);

            if (sharedPreferences.getBoolean(SHOW_MYO_STATUS_NOTIFICATION, true)) {
                mNotificationBuilder.setContentTitle(getString(R.string.myo_needs_sync));
                mNotificationManager.notify(NOTIFICATION_ID, mNotificationBuilder.build());
            }
        }
    };

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        if (intent != null) {
            String action = intent.getAction();

            if (TextUtils.isEmpty(action)) {
                init();
            } else {
                if (action.equals(ACTION_DISCONNECT)) {
                    mHub.shutdown();
                    mNotificationManager.cancelAll();
                } else if (action.equals(ACTION_CONNECT)) {
                    init();
                }
            }
        }

        return START_STICKY;
    }

    private void init() {
        if (!mHub.init(this, getPackageName())) {
            stopSelf();
        }

        mHub.setLockingPolicy(Hub.LockingPolicy.NONE);
        mHub.removeListener(mListener);
        mHub.addListener(mListener);
        mHub.attachToAdjacentMyo();

        mNotificationBuilder = buildConnectNotification();
    }

    private NotificationCompat.Builder buildConnectNotification() {
        Intent connectIntent = new Intent(ACTION_DISCONNECT);
        PendingIntent connectPendingIntent = PendingIntent.getService(this, 0, connectIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        return new NotificationCompat.Builder(BackgroundService.this).setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle(getString(R.string.myo_connected)).setOngoing(true)
                .addAction(R.drawable.ic_connect, getString(R.string.connect_to_myo), connectPendingIntent);
    }

    private NotificationCompat.Builder buildDisconnectNotification() {
        Intent disconnectIntent = new Intent(ACTION_DISCONNECT);
        PendingIntent disconnectPendingIntent = PendingIntent.getService(this, 0, disconnectIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);

        return new NotificationCompat.Builder(BackgroundService.this).setSmallIcon(R.drawable.ic_launcher)
                .setContentTitle(getString(R.string.myo_connected)).setOngoing(true)
                .addAction(R.drawable.ic_disconnect, getString(R.string.disconnect), disconnectPendingIntent);
    }

    @Override
    public IBinder onBind(final Intent arg0) {
        return null;
    }

    private void showToast(String text) {
        if (mToast == null) {
            mToast = Toast.makeText(this, text, Toast.LENGTH_SHORT);
        } else {
            mToast.setText(text);
        }

        mToast.show();
    }

}