com.prod.intelligent7.engineautostart.ConnectDaemonService.java Source code

Java tutorial

Introduction

Here is the source code for com.prod.intelligent7.engineautostart.ConnectDaemonService.java

Source

/*
 * 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 com.prod.intelligent7.engineautostart;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.TimeZone;
import java.util.Vector;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;

//import com.google.android.gms.gcm.GoogleCloudMessaging;

import android.app.AlarmManager;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.Vibrator;
import android.provider.Settings;
import android.support.v4.app.NotificationCompat;
import android.text.format.Time;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;

/**
 * This {@code IntentService} does the actual handling of the GCM message.
 * {@code GcmBroadcastReceiver} (a {@code WakefulBroadcastReceiver}) holds a
 * partial wake lock for this service while the service does its work. When the
 * service is finished, it calls {@code completeWakefulIntent()} to release the
 * wake lock.
 */
public class ConnectDaemonService extends Service
        implements TcpConnectDaemon.StatusChangeListener, SensorEventListener {

    //public static final int NOTIFICATION_ID = 1;
    public static int NOTIFICATION_ID;
    public static final String DAEMON_COMMAND = "COMMAND";
    public static final ReentrantLock fileLock = new ReentrantLock();
    public static Ringtone noise = null;
    private NotificationManager mNotificationManager;
    NotificationCompat.Builder builder;
    Logger log;

    public ConnectDaemonService() {
        super();
    }

    public static final String TAG = "EAS JOB";
    PendingIntent scheduleAlarm;
    AlarmManager alarmManager;
    //@Override
    // protected void onHandleIntent(Intent intent) {
    //onBind(intent);
    //Bundle extras = intent.getExtras();
    //GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
    // The getMessageType() intent parameter must be the intent you received
    // in your BroadcastReceiver.
    //String messageType = null;//gcm.getMessageType(intent);

    //if (!extras.isEmpty()) {  // has effect of unparcelling Bundle
    /*
     * Filter messages based on message type. Since it is likely that GCM will be
     * extended in the future with new message types, just ignore any message types you're
     * not interested in, or that you don't recognize.
        
    if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
        sendNotification("Send error: " + extras.toString());
    } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
        sendNotification("Deleted messages on server: " + extras.toString());
    // If it's a regular GCM message, do some work.
    } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
        // This loop represents the service doing some work.
        for (int i = 0; i < 5; i++) {
            Log.i(TAG, "Working... " + (i + 1)
                    + "/5 @ " + SystemClock.elapsedRealtime());
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            }
        }
        Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());
        // Post notification of received message.
        
    } */
    // sendNotification("Received: " + extras.toString());
    // Log.i(TAG, "Received: " + extras.toString());
    //}
    // Release the wake lock provided by the WakefulBroadcastReceiver.
    //EASBroadcastReceiver.completeWakefulIntent(intent);
    // }

    public static String ramFileName = MainActivity.package_name + ".profile";
    static TcpConnectDaemon mDaemon = null;
    ArrayBlockingQueue<String> outBoundMailBox;
    static ArrayList<String> urgentMailBox;
    final int mailBoxLimit = 200;
    Thread hourlyAlarm;
    boolean stopHourAlarm;

    @Override
    public void onCreate() {
        ramFileName = MainActivity.package_name + ".profile";
        log = Logger.getAnonymousLogger();
        log.info(getPackageName() + "Got Activated ");
        serverHeartBit = 60 * 1000;
        urgentMailBox = new ArrayList<String>();
        if (mDaemon == null || !mDaemon.isAlive())
            startDaemon();
        scheduleAlarm = null;
        alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        //startScheduledJobs();
        //new screen off handling
        /*
        bugPresent = true;
        screenIsOff = false;
        final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        screenOnOffReceiver = new ScreenReceiver();
        registerReceiver(screenOnOffReceiver, filter);
        powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        WakeLockManager.acquire(this, "screenBugPartial", PowerManager.PARTIAL_WAKE_LOCK);
        registerAccelerometerListener();
        */
        startScheduleAlarms();
    }

    public static final String SERVER_IP = "server_ip";
    public static final String SERVER_PORT = "server_port";
    int serverHeartBit;

    void startDaemon() {
        mDaemon = null;
        String mHost = getSharedPreferences(MainActivity.package_name + ".profile", MODE_PRIVATE)
                .getString(SERVER_IP, "220.134.85.189");
        //start a thread to talk to server every minute

        String mPort = getSharedPreferences(MainActivity.package_name + ".profile", MODE_PRIVATE)
                .getString(SERVER_PORT, "9696");
        //start a thread to talk to server every minute
        if (mHost.charAt(0) == '-') {
            mHost = getResources().getString(R.string.prod_server);
            mPort = getResources().getString(R.string.port);
        }
        mDaemon = TcpConnectDaemon.getInstance(mHost, Integer.parseInt(mPort));//
        //new TcpConnectDaemon(mHost, Integer.parseInt(mPort));
        if (mDaemon == null)
            return;
        mDaemon.setModeInterval(TcpConnectDaemon.MODE_REPEAT, serverHeartBit);

        if (outBoundMailBox == null)
            outBoundMailBox = new ArrayBlockingQueue<String>(mailBoxLimit);
        mDaemon.setOutBoundDataQ(outBoundMailBox);
        /* new change mailbox should be hold by me not the postman
        // so that the box is still there even the man quit
        Vector<String> keep=null;
        if (outBoundMailBox!= null && outBoundMailBox.size() > 0)
        {
        keep=new Vector<String>();
        while (outBoundMailBox.size()> 0)
        {
            try {
                keep.add(outBoundMailBox.take());
            } catch(InterruptedException e){}
        }
        }
        outBoundMailBox=mDaemon.getOutBoundDataQ();
        if (keep!=null && keep.size() > 0)
        {
        for (int i=0; i<keep.size(); i++){
            try {
                outBoundMailBox.put(keep.get(i));
            } catch(InterruptedException e){}
        }
        keep.clear();
        keep=null;
        }
        */
        mDaemon.attachToService(this);
        //mDaemon.setUrgentMailBox(urgentMailBox);
        mDaemon.addListener(this);
        mDaemon.start();
        // need start schedule too; MainActivity.N_BOOT_PARAMS, nBootParam); //HH:MM-on minutes-off minutes-cycle last for minutes
        // MainActivity.ONE_BOOT_PARAMS, bootParam); //  yy/mm/dd:hh:mm-last for minutes
    }

    public void onDaemonDying() {
        if (mDaemon != null && mDaemon.isAlive()) {
            try {
                mDaemon.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        startDaemon();
    }

    void confirmDaemonAlive() {
        if (mDaemon != null && mDaemon.isAlive()) {
            try {
                mDaemon.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        mDaemon = null;
        while (mDaemon == null) {
            startDaemon();
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        if (intent != null)
            confirmJob(intent, flags, startId);
        return START_STICKY;//mStartMode;
    }

    public class UrgentMailBinder extends Binder {

        ConnectDaemonService getService() {
            return ConnectDaemonService.this;
        }

        ArrayList<String> getUrgentMailBox() {
            // Return this instance of LocalService so clients can call public methods
            return urgentMailBox;
        }
    }

    public void sendCommand(String command) {
        if (command == null)
            return;

        if (command.charAt(0) == 'M') {
            long tm = new Date().getTime();

            if (command.length() > 2 && command.charAt(1) == '5') {

                if (tm - lastStartTime < 4 * 60 * 1000)
                    return;

                lastStartTime = tm;
            }
            Log.w("SERVICEDAEMON", "EXEC " + command + " at " + tm);
            putInDaemonOutboundQ(command);

            if (command.charAt(1) == '2' || command.charAt(1) == '3') {
                serverHeartBit = 15 * 1000;
                urgentMailBox.clear();
            }
        }

        if (command.indexOf("DISMISSED") >= 0) { //when no response after timeout
            serverHeartBit = 60 * 1000;
            //if (mDaemon.isAlive()) mDaemon.resetHeartBeatInterval(serverHeartBit);
            return;
        }
        if (command.indexOf("SCHEDULE") >= 0) {
            reStartScheduleAlarms();
            return;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return confirmJob(intent, 0, -1);
    }

    public static final String GET_BINDER = "GET_BINDER";
    public static final String SERVICE_TYPE = "9SERVICE_TYPE";
    public static final String URGENT = "0URGENT";
    public static final String ALARM_DONE = "alarm_done";

    private static long lastStartTime = 0;

    private IBinder confirmJob(Intent intent, int flags, int startId) {
        // A client is binding to the service with bindService()
        String command = intent.getExtras().getString(DAEMON_COMMAND);
        //Object obj1=intent.getExtras().getClassLoader();
        //confirmDaemonAlive();
        if (command != null) {
            if (command.length() < 3)
                return null;
            intent.putExtra(DAEMON_COMMAND, "EXECUTED");
            if (command.equalsIgnoreCase(GET_BINDER)) {
                String sType = intent.getExtras().getString(SERVICE_TYPE);
                if (sType != null && sType.equalsIgnoreCase(URGENT)) {
                    serverHeartBit = 10 * 1000;
                    urgentMailBox.clear();
                }
                return new UrgentMailBinder();
            }
            sendCommand(command);
            return null;
        }
        command = intent.getExtras().getString(ALARM_DONE);
        if (command == null)
            return null;
        PowerManager.WakeLock wlR = ((PowerManager) getSystemService(Context.POWER_SERVICE))
                .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "KEEP_THREAD_ALIVE");
        wlR.acquire();
        switch (command) {
        case ALARM_BIT:
            //mDaemon.hasCommand=true;
            //mDaemon.interrupt();
            confirmDaemonAlive();
            //startServerHearBeatAlarm();
            break;
        case ALARM_1BOOT:
            String param = intent.getExtras().getString(ALARM_1BOOT);
            long on_time = Long.parseLong(param);
            sendCommand("M5-" + new DecimalFormat("00").format(on_time / 60000));
            //startOneBootAlarm();
            break;
        case ALARM_NBOOT:
            Log.i("ALARM_SET", "got recurring start intent");
            GregorianCalendar gToday = new GregorianCalendar(
                    TimeZone.getTimeZone(getResources().getString(R.string.my_time_zone_en)));
            if (gToday.get(Calendar.HOUR_OF_DAY) >= 7 && gToday.get(Calendar.HOUR_OF_DAY) < 19)
                break;
            String params = intent.getExtras().getString(ALARM_NBOOT);
            int idx = params.indexOf("-");
            long last4 = Long.parseLong(params.substring(0, idx));
            sendCommand("M5-" + new DecimalFormat("00").format(last4 / 60000));
            long off_time = Long.parseLong(params.substring(idx + 1));
            setRecurringBootAlarm(last4, off_time);
            break;
        case ALARM_HOUR:
            //if (heartBitIntent==null) startServerHearBeatAlarm();
            if (oneBootIntent == null)
                startOneBootAlarm();
            if (recurringBootIntent == null)
                startRecurringBootAlarm();
            //reStartScheduleAlarms();
            startHourlyCheckAlarm();
            break;
        default:
            break;
        }
        wlR.release();

        return null;//mBinder;
    }

    boolean confirmHasMailBox() {
        if (outBoundMailBox == null) {
            outBoundMailBox = new ArrayBlockingQueue<String>(mailBoxLimit);
            if (mDaemon != null)
                mDaemon.setOutBoundDataQ(outBoundMailBox);
        }
        //outBoundMailBox=mDaemon.getOutBoundDataQ();
        return true;
    }

    public void putInDaemonOutboundQ(String msg) {
        if (!confirmHasMailBox())
            return;
        final String outMsg = msg;
        final TcpConnectDaemon toWakeUp = mDaemon;

        new Thread(new Runnable() {
            public void run() {
                if (outBoundMailBox.size() == TcpConnectDaemon.Q_SIZE) {
                    log.warning("Warning : too many msg in my Q");
                    return;
                }
                try {
                    outBoundMailBox.put(outMsg);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                //toWakeUp.hasCommand=true;
                //toWakeUp.interrupt();
                confirmDaemonAlive();
            }
        }).start();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()

        return false;//mAllowRebind;
    }

    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }

    public interface UrgentMailListener {
        public void processMail(String msg);
    }

    public static class UrgentMailRegister {
        private static int instances = 0;
        private static UrgentMailListener myUrgentMailListener = null;

        private UrgentMailRegister() {
        };

        public static boolean register(UrgentMailListener aL) {
            if (instances > 0)
                return false;
            myUrgentMailListener = aL;
            instances = 1;
            return true;
        }

        public static boolean unRegister(UrgentMailListener aL) {
            if (instances < 1)
                return false;
            if (myUrgentMailListener != aL)
                return false;
            myUrgentMailListener = null;
            instances = 0;

            return true;
        }

        public static UrgentMailListener getMyUrgentMailListener() {
            return myUrgentMailListener;
        }
    }

    public void processUrgentMsg(String msg) {

        urgentMailBox.add(msg);

        serverHeartBit = 60 * 1000;
    }

    public void processUrgentMsgOld(String msg) {
        final UrgentMailListener aL = UrgentMailRegister.getMyUrgentMailListener();
        if (aL == null)
            return;
        final String data = msg;
        new Thread(new Runnable() {
            @Override
            public void run() {
                aL.processMail(data);
            }
        }).start();
        serverHeartBit = 60 * 1000;
    }

    static int alarmRequestId = 0;
    static int heartBitRequestId = 1000; //range set between 1000 ~ 1099
    static PendingIntent heartBitIntent;
    public static final String ALARM_BIT = "alarm_heart_bit";

    public void startServerHearBeatAlarm() {
        if (heartBitIntent != null) {
            alarmManager.cancel(heartBitIntent);
            //return;
        }
        heartBitIntent = null;
        //serverHeartBit=60*1000;
        //if (!mDaemon.notUrgent) serverHeartBit=10*1000;
        Intent jIntent = new Intent(this, ConnectDaemonService.class);
        //M1-00 (cool) or M1-01 (warm)
        jIntent.putExtra(ConnectDaemonService.ALARM_DONE, ALARM_BIT);
        heartBitIntent = PendingIntent.getService(this, ++heartBitRequestId % 100 + 1000, jIntent,
                PendingIntent.FLAG_ONE_SHOT);
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + serverHeartBit, heartBitIntent);
        Log.i("ALARM_SET", "restart new alarm set for " + serverHeartBit / 1000 + " seconds");
        //mDaemon.hasCommand=true;
        //mDaemon.interrupt();
    }

    static int boot1AlarmRequestId = 0; //range set between 150 ~ 159
    static PendingIntent oneBootIntent;
    public static final String ALARM_1BOOT = "ALARM_1BOOT";

    void startOneBootAlarm() {
        if (oneBootIntent != null) {
            alarmManager.cancel(oneBootIntent);
            //return;
        }
        oneBootIntent = null;
        String bootParameter = readBootParameter(1);
        Log.i("ALARM_SET", "got 1 boot parameters " + (bootParameter == null ? "nothing" : bootParameter));
        if (bootParameter == null)
            return;
        int idx = bootParameter.indexOf("-");
        if (idx < 0)
            return;
        long init_wait = Long.parseLong(bootParameter.substring(0, idx));
        if (init_wait < 10000) {
            long on_time = Long.parseLong(bootParameter.substring(idx + 1));
            sendCommand("M5-" + new DecimalFormat("00").format(on_time / 60000));
            return;
        }
        Intent jIntent = new Intent(this, ConnectDaemonService.class);
        //M1-00 (cool) or M1-01 (warm)
        jIntent.setAction(ALARM_1BOOT);
        jIntent.putExtra(ConnectDaemonService.ALARM_DONE, ALARM_1BOOT);
        jIntent.putExtra(ConnectDaemonService.ALARM_1BOOT, bootParameter.substring(idx + 1));
        oneBootIntent = PendingIntent.getService(this, ++boot1AlarmRequestId % 10 + 150, jIntent,
                PendingIntent.FLAG_ONE_SHOT);
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + init_wait, oneBootIntent);
        Log.i("ALARM_SET", "to start one boot in " + init_wait / 60000);
        //startScheduledJobs();
    }

    static int nBootAlarmRequestId = 1000; //range set between 200 ~ 299
    static PendingIntent recurringBootIntent;
    public static final String ALARM_NBOOT = "ALARM_NBOOT";

    void startRecurringBootAlarm() {
        if (recurringBootIntent != null) {
            alarmManager.cancel(recurringBootIntent);
            //return;
        }
        recurringBootIntent = null;
        GregorianCalendar gToday = new GregorianCalendar(
                TimeZone.getTimeZone(getResources().getString(R.string.my_time_zone_en)));
        if (gToday.get(Calendar.HOUR_OF_DAY) >= 7 && gToday.get(Calendar.HOUR_OF_DAY) < 19)
            return;
        String bootParameter = readBootParameter(99);
        Log.i("ALARM_SET", "got n boot parameters " + (bootParameter == null ? "nothing" : bootParameter));
        if (bootParameter == null)
            return;
        int idx = bootParameter.indexOf("-");
        if (idx < 0)
            return;
        long init_wait = Long.parseLong(bootParameter.substring(0, idx));
        if (init_wait < 2000) //init_wait=2000;
        {
            int ixx = bootParameter.indexOf("-", idx + 1);
            long on_time = Long.parseLong(bootParameter.substring(idx + 1, ixx));
            sendCommand("M5-" + new DecimalFormat("00").format(on_time / 60000));

            long off_time = Long.parseLong(bootParameter.substring(ixx + 1));
            setRecurringBootAlarm(on_time, off_time);
            return;
        }
        Intent jIntent = new Intent(this, ConnectDaemonService.class);
        //M1-00 (cool) or M1-01 (warm)
        jIntent.setAction(ALARM_NBOOT);
        jIntent.putExtra(ConnectDaemonService.ALARM_DONE, ALARM_NBOOT);
        jIntent.putExtra(ConnectDaemonService.ALARM_NBOOT, bootParameter.substring(idx + 1));
        recurringBootIntent = PendingIntent.getService(this, ++nBootAlarmRequestId % 100 + 200, jIntent,
                PendingIntent.FLAG_ONE_SHOT);
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + init_wait, recurringBootIntent);
        //alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + init_wait,
        //on_time + off_time, recurringBootIntent);
        //Log.i("ALARM_SET", "to start recurring boot in " + init_wait/60000);//+" with interval "+(on_time+off_time)/60000);
        Log.i("ALARM_SET", "to start recurring boot in " + init_wait / 60000);
        //startScheduledJobs();
    }

    public static final String NBOOT_PARAM = "NBOOT_PARAM";

    void setRecurringBootAlarm(long on_time, long idle_interval) {
        if (recurringBootIntent != null) {
            alarmManager.cancel(recurringBootIntent);
            //return;
        }
        recurringBootIntent = null;
        GregorianCalendar gToday = new GregorianCalendar(
                TimeZone.getTimeZone(getResources().getString(R.string.my_time_zone_en)));
        if (gToday.get(Calendar.HOUR_OF_DAY) >= 7 && gToday.get(Calendar.HOUR_OF_DAY) < 21)
            return;
        long total_wait = idle_interval;//on_time+idle_interval;
        String bootParameter = "" + on_time + "-" + idle_interval;
        Intent jIntent = new Intent(this, ConnectDaemonService.class);
        //M1-00 (cool) or M1-01 (warm)
        jIntent.setAction(ALARM_NBOOT);
        jIntent.putExtra(ConnectDaemonService.ALARM_DONE, ALARM_NBOOT);
        jIntent.putExtra(ConnectDaemonService.ALARM_NBOOT, bootParameter);
        recurringBootIntent = PendingIntent.getService(this, ++nBootAlarmRequestId % 100 + 300, jIntent,
                PendingIntent.FLAG_ONE_SHOT);
        alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + total_wait, recurringBootIntent);
        Log.i("ALARM_SET", "to start recurring boot in " + total_wait / 60000);
        //startScheduledJobs();
    }

    void reStartScheduleAlarms() {
        //startServerHearBeatAlarm();
        startOneBootAlarm();
        startRecurringBootAlarm();
    }

    void startScheduleAlarms() {
        //startServerHearBeatAlarm();
        startOneBootAlarm();
        startRecurringBootAlarm();
        startHourlyCheckAlarm();
    }

    public static final String ALARM_HOUR = "alarm_hour";

    void startHourlyCheckAlarm() {
        if (scheduleAlarm != null) {
            alarmManager.cancel(scheduleAlarm);
            //return;
        }
        Intent jIntent = new Intent(this, ConnectDaemonService.class);
        //M1-00 (cool) or M1-01 (warm)
        jIntent.putExtra(ConnectDaemonService.ALARM_DONE, ALARM_HOUR);
        jIntent.setAction(ALARM_HOUR);
        scheduleAlarm = PendingIntent.getService(this, ++alarmRequestId % 100 + 500, jIntent,
                PendingIntent.FLAG_ONE_SHOT);
        alarmManager.set(AlarmManager.RTC_WAKEUP, 1 * 60 * 60 * 1000 + System.currentTimeMillis(), scheduleAlarm);
        Log.i("ALARM_SET", "restart check alarm set for 1 hour");
        //startScheduledJobs();
    }

    void startScheduleAlarm() {
        if (scheduleAlarm != null) {
            alarmManager.cancel(scheduleAlarm);
            //return;
        }
        Intent jIntent = new Intent(this, ConnectDaemonService.class);
        //M1-00 (cool) or M1-01 (warm)
        jIntent.putExtra(ConnectDaemonService.ALARM_DONE, ALARM_DONE);
        scheduleAlarm = PendingIntent.getService(this, ++alarmRequestId, jIntent, PendingIntent.FLAG_ONE_SHOT);
        alarmManager.set(AlarmManager.RTC_WAKEUP, 1 * 60 * 60 * 1000 + System.currentTimeMillis(), scheduleAlarm);
        Log.i("ALARM_SET", "restart new alarm set for 1 hour");
        startScheduledJobs();
    }

    public String readBootParameter(int mode_1_n) {
        String retS = null;
        GregorianCalendar gToday = new GregorianCalendar(
                TimeZone.getTimeZone(getResources().getString(R.string.my_time_zone_en)));
        SharedPreferences sharedPref = getSharedPreferences(MainActivity.package_name + ".profile",
                Context.MODE_PRIVATE);
        String param = sharedPref.getString(MainActivity.ONE_BOOT_PARAMS, "--");
        String paramKey = MainActivity.SET_MULTIPLE_BOOT;
        if (mode_1_n == 1)
            paramKey = MainActivity.SET_ONE_BOOT;

        Set<String> aSet = sharedPref.getStringSet(paramKey, null);
        if (aSet == null) {
            return null;
        }
        String[] allData = new String[aSet.size()];
        allData = aSet.toArray(allData);
        String todayName = ScheduleActivity.weekDays[(gToday.get(Calendar.DAY_OF_WEEK) + 6) % 7];//ScheduleActivity.weekDays[gToday.get(Calendar.DAY_OF_WEEK)-1];
        String scheduleDay = todayName;
        param = null;
        for (int i = 0; i < aSet.size(); i++) {
            if (allData[i].indexOf(scheduleDay) < 0)
                continue;
            param = allData[i].replace('>', '-'); //saved data format change to weekdayName>HH:MM-last4
            //data has form hh:mm-active period
            break;
        }
        int hrNow = gToday.get(Calendar.HOUR_OF_DAY);
        if (param == null) {
            if (mode_1_n == 1 || hrNow > 7)
                return null;
        }
        if (mode_1_n != 1 && hrNow < 7) {
            if (param != null) {
                int idd = param.indexOf("-");
                int h0 = Integer.parseInt(param.substring(idd + 1, idd + 3));
                if (h0 > 7)
                    param = null;
            }

            scheduleDay = ScheduleActivity.weekDays[(gToday.get(Calendar.DAY_OF_WEEK) + 5) % 7]; //check if scheduled yesterday
            if (param == null) {
                for (int i = 0; i < aSet.size(); i++) {
                    if (allData[i].indexOf(scheduleDay) < 0)
                        continue;
                    param = allData[i].replace('>', '-');
                    break;
                }
                if (param == null) {
                    return null;
                }
                int idd = param.indexOf("-");
                int h0 = Integer.parseInt(param.substring(idd + 1, idd + 3));
                if (h0 < 21) {
                    return null;
                }
                hrNow += 24;
                //hrBase = 24;
            }
        }

        String[] terms = param.split("-");
        int icx = terms[1].indexOf(":");
        if (icx < 0) {
            Log.w("SCHEDULE_JOB", "!!! Bad formated start time " + param + " as new schedule");
            return null;
        }
        int hrStart = Integer.parseInt(terms[1].substring(0, icx)); //starting hour
        int minStart = Integer.parseInt(terms[1].substring(icx + 1));
        int minNow = gToday.get(Calendar.MINUTE);

        long init_wait = ((hrStart - hrNow) * 60 + (minStart - minNow)) * 60 * 1000;
        //in milli secs
        long on_time = 60 * 1000 * Integer.parseInt(terms[2]);
        //if (init_wait>0)
        if (mode_1_n == 1) {
            if (init_wait < -2 * 60 * 1000)
                return null;
            if (init_wait < 0)
                init_wait = 0;
            if (on_time < 1)
                return null;
            //if (init_wait >3605000) return null;
            retS = "" + init_wait + "-" + on_time;
            return retS;
        }

        long off_time = 1000 * 3600 * Integer.parseInt(terms[3]); //in milli secs

        while (init_wait < 0) {
            init_wait += off_time;//(on_time+off_time);
        }

        retS = "" + init_wait + "-" + on_time + "-" + off_time;
        return retS;
    }

    public static final String[] weekDays = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
            "Saturday" };
    boolean killScheduledJob;
    OneTimeScheduler oneBootJob;

    ContinueScheduler recurringJob;

    public void startScheduledJobs() {
        killScheduledJob = false;
        //startScheduleAlarm();
        if (oneBootJob == null || !oneBootJob.isAlive()) {
            oneBootJob = new OneTimeScheduler(this, mDaemon);
            oneBootJob.start();
        }
        if (recurringJob == null || !recurringJob.isAlive()) {
            recurringJob = new ContinueScheduler(this, mDaemon);
            recurringJob.start();
        }
    }

    public void stopScheduledJobs() {
        killScheduledJob = true;
        if (oneBootJob != null && oneBootJob.isAlive())
            oneBootJob.killJob();
        if (recurringJob != null && recurringJob.isAlive())
            recurringJob.killJob();
        try {
            oneBootJob.join();
            recurringJob.join();
            Log.i("SCHEDULE_JOB", "STOPPed");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void resetScheduledJobs() {
        if (oneBootJob != null && oneBootJob.isAlive())
            oneBootJob.killJob();
        if (recurringJob != null && recurringJob.isAlive())
            recurringJob.killJob();

        new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    //Thread.sleep(10000L);
                    recurringJob.join();
                    oneBootJob.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                startScheduledJobs();
            }
        }).start();
    }

    int saveData(String tblName, String fixLine) {
        String fileName = "notification" + tblName;
        int iPending = 0;
        Set<String> nullSet = null;
        synchronized (fileLock) {
            SharedPreferences sharedPref = getSharedPreferences(fileName, Context.MODE_PRIVATE);
            Set<String> pendingData = sharedPref.getStringSet("notification", nullSet);
            if (pendingData == null)
                pendingData = new HashSet<String>();
            pendingData.add(fixLine);
            SharedPreferences.Editor adder = sharedPref.edit();
            adder.putStringSet("notification", pendingData);
            adder.commit();
            iPending = pendingData.size();
        }
        return iPending;
    }

    public static class MyTime {
        int year;
        int month;
        int day;
        int hour;
        int minute;

        public MyTime(GregorianCalendar gc) {
            year = gc.get(Calendar.YEAR);
            month = gc.get(Calendar.MONTH) + 1;
            day = gc.get(Calendar.DAY_OF_MONTH);
            hour = gc.get(Calendar.HOUR_OF_DAY);
            minute = gc.get(Calendar.MINUTE);
        }

        public MyTime() {
            GregorianCalendar gc = new GregorianCalendar();
            year = gc.get(Calendar.YEAR);
            month = gc.get(Calendar.MONTH) + 1;
            day = gc.get(Calendar.DAY_OF_MONTH);
            hour = gc.get(Calendar.HOUR_OF_DAY);
            minute = gc.get(Calendar.MINUTE);
        }
    }

    boolean car_theft;

    void makeNoise() {
        if (car_theft) {
            noise = RingtoneManager.getRingtone(this, Settings.System.DEFAULT_RINGTONE_URI);
            noise.play();
            return;
        }

        boolean toRing = false;
        //String fileName=MainActivity.getFileHeader()+ProfilePage.getTableName();
        String fileName = MainActivity.package_name + ".profile";
        SharedPreferences mem = getSharedPreferences(fileName, Context.MODE_PRIVATE);
        String sRing = mem.getString(PickActivity.CURRENT_RINGTON, "--");//, String);
        if (sRing.charAt(0) == '-')
            return;
        Uri ringUri = Uri.parse(sRing);//, String);
        String t0 = mem.getString(PickActivity.NO_NOISE_START, "--");//, noNoiseStart);
        String t1 = mem.getString(PickActivity.NO_NOISE_END, "--");//, noNoiseEnd);
        String[] sT0 = t0.split(":");
        int h0 = Integer.parseInt(sT0[0]);
        int m0 = Integer.parseInt(sT0[1]);
        sT0 = t1.split(":");
        int h1 = Integer.parseInt(sT0[0]);
        int m1 = Integer.parseInt(sT0[1]);
        MyTime tm = new MyTime(
                new GregorianCalendar(TimeZone.getTimeZone(getResources().getString(R.string.my_time_zone_en))));
        int iNow = tm.hour * 60 + tm.minute;
        int iU = h1 * 60 + m1;
        int iL = h0 * 60 + m0;
        if (h1 < h0) {
            toRing = (iNow > iU && iNow < iL);
        } else
            toRing = (iNow > iU || iNow < iL);
        //android.os.Debug.waitForDebugger();
        if (toRing) {
            noise = RingtoneManager.getRingtone(getApplicationContext(), ringUri);
            noise.play();
        } else
            noise = null;
    }
    // Put the message into a notification and post it.

    private static HashMap<String, String> mcuDictionary;

    static public HashMap<String, String> getMcuCodeDictionary() {

        if (mcuDictionary == null)
            buildCodeDictionary();
        return mcuDictionary;
    }

    public static String getChinese(String code) {
        String retS = "";
        if (mcuDictionary == null)
            buildCodeDictionary();
        return retS + mcuDictionary.get(code);
    }

    private static void buildCodeDictionary() {
        mcuDictionary = new HashMap<String, String>();
        mcuDictionary.put("M1-00", "?");
        mcuDictionary.put("M1-01", "?");
        mcuDictionary.put("M2", "??");
        mcuDictionary.put("M3", "?");
        mcuDictionary.put("M4-00", "?");
        mcuDictionary.put("M4-01", "?");
        mcuDictionary.put("M5", "??");
        //mcuDictionary.put("M5","??");

        mcuDictionary.put("S110", "?");

        mcuDictionary.put("S111", "");

        mcuDictionary.put("S100", "?");

        mcuDictionary.put("S101", "");

        mcuDictionary.put("S200", "??");

        mcuDictionary.put("S201", "?");

        mcuDictionary.put("S300", "???");

        mcuDictionary.put("S301", "??");

        mcuDictionary.put("S400", "");

        mcuDictionary.put("S401", "?,?");

        mcuDictionary.put("S410", "");

        mcuDictionary.put("S411", "");

        mcuDictionary.put("S500", "?");

        mcuDictionary.put("S501", "?");

        mcuDictionary.put("S502", "??");

        mcuDictionary.put("S503", "?");

        mcuDictionary.put("S504", "");

        mcuDictionary.put("S505", "");

        mcuDictionary.put("S999", "???");
    }

    //static //String header=MainActivity.getFileHeader();

    public void sendNotification(String msg) {
        mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

        car_theft = false;
        if (msg.indexOf("505") > 0)
            car_theft = true;
        makeNoise();
        String msgShow = msg;
        //msg :   msg in SXX@time<sender> format
        //SXX need translation from code to simplified chinese

        int i0 = msg.indexOf("@");
        int idx = msg.indexOf("<");
        if (i0 > 0)
            msgShow = msg.substring(0, i0);
        else if (idx > 0)
            msgShow = msg.substring(0, idx);
        String chinese = getChinese(msgShow);
        if (chinese == null)
            chinese = "DAEMON STATUS";
        if (msg.toLowerCase().indexOf("finish") > 0) {
            startDaemon();
        }

        Intent jobIntent = null;//=new Intent(this, MainActivity.class);

        jobIntent = new Intent(this, MainActivity.class);//main will invoke other activities
        String tblName = "";
        int iPending = 1;

        jobIntent.putExtra("MCU_RESP", "EAS>>" + chinese);

        String header = "EAS";//getResources().getString(R.string.candidate_name);
        String MSGs = "EAS";//getResources().getString(R.string.msg_for_you);

        //DisplayMetrics metrics = new DisplayMetrics();
        //((WindowManager)this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
                //.setLargeIcon(Bitmap.createBitmap(metrics,80, 80, Bitmap.Config.ARGB_4444))//
                .setSmallIcon(R.drawable.engine_auto_start).setContentTitle(header + "(" + iPending + ")")
                .setStyle(new NotificationCompat.BigTextStyle().bigText(msgShow)).setContentText(chinese)
                .setLights(0xFF0000, 2000, 5000).setAutoCancel(true);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0, jobIntent,
                PendingIntent.FLAG_UPDATE_CURRENT); //the intent to open when clicked

        mBuilder.setContentIntent(contentIntent); //so MainActivity will be opened when notification is clicked
        mNotificationManager.notify(getPackageName().hashCode(), mBuilder.build());

        if (noise != null) {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            noise.stop();
            noise = null;
        }
    }

    public void localNotification(String msg) {
        sendNotification(msg);
    }

    private final class ScreenReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(final Context context, final Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                serviceHandler.postDelayed(setScreenIsOffRunnable, 6666);
                serviceHandler.postDelayed(turnScreenOnFallbackRunnable, 10000);
            }
        }
    }

    public static final String BUG_NOT_PRESENT = "BUG_NOT_PRESENT";

    public static final String BUG_PRESENT = "BUG_PRESENT";

    private boolean bugPresent = true;
    boolean didNotTurnScreenOn = true;
    private PowerManager powerManager;
    private boolean screenIsOff = false;

    private ScreenReceiver screenOnOffReceiver;
    Handler serviceHandler = new Handler();

    Runnable setScreenIsOffRunnable = new Runnable() {
        @Override
        public void run() {
            screenIsOff = true;
        }
    };

    Runnable turnScreenOnFallbackRunnable = new Runnable() {
        @Override
        public void run() {
            if (bugPresent) {
                //CheckForScreenBugActivity.BUG_PRESENT_INTENT = new Intent(BUG_PRESENT);
            }
            turnScreenOn();
        }
    };

    @Override
    public void onAccuracyChanged(final Sensor sensor, final int accuracy) {
        // Not used.
    }

    @Override
    public void onDestroy() {

        unregisterAccelerometerListener();

        unregisterReceiver(screenOnOffReceiver);

        serviceHandler.removeCallbacks(setScreenIsOffRunnable);
        serviceHandler.removeCallbacks(turnScreenOnFallbackRunnable);

        // check here so that certain devices keep their screen on for at least
        // 5 seconds (from turnScreenOn)
        if (didNotTurnScreenOn) {
            WakeLockManager.release("screenBugPartial");
            WakeLockManager.release("screenBugDim");
        }
        super.onDestroy();
    }

    @Override
    public void onSensorChanged(final SensorEvent event) {
        if (!powerManager.isScreenOn() && screenIsOff && bugPresent) {
            //CheckForScreenBugActivity.BUG_PRESENT_INTENT = new Intent(BUG_NOT_PRESENT);
            turnScreenOn();
        }
    }

    private void registerAccelerometerListener() {
        final SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

        sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                SensorManager.SENSOR_DELAY_FASTEST);
    }

    private void turnScreenOn() {
        didNotTurnScreenOn = false;
        WakeLockManager.acquire(this, "screenBugDim", PowerManager.SCREEN_DIM_WAKE_LOCK
                | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, 5000);
        //stopSelf();
    }

    private void unregisterAccelerometerListener() {
        final SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensorManager.unregisterListener(this);
    }

    Handler myHandler;

    long onTime;
    long idleInterval;
    long initWaitTime;
    static final DecimalFormat dF = new DecimalFormat("00");

    Runnable startOneTime = new Runnable() {
        final long last4 = onTime;

        @Override
        public void run() {
            sendCommand("M5-" + dF.format(last4));
            myHandler.removeCallbacks(this);
        }
    };

    Runnable startNTime = new Runnable() {
        final long last4 = onTime;
        final long idleTime = idleInterval;

        @Override
        public void run() {
            sendCommand("M5-" + dF.format(last4));
            myHandler.postDelayed(this, last4 + idleTime);
        }
    };

    void postOneBoot() {
        myHandler.removeCallbacks(startOneTime);
        String oneBootParameters = readBootParameter(1);
        String[] params = oneBootParameters.split("-");
        initWaitTime = Long.parseLong(params[0]);
        if (initWaitTime > 3600 * 1000)
            return;
        onTime = Long.parseLong(params[1]);
        myHandler.postDelayed(startOneTime, initWaitTime);
    }

    void postNBoots() {
        myHandler.removeCallbacks(startNTime);
        GregorianCalendar gToday = new GregorianCalendar(
                TimeZone.getTimeZone(getResources().getString(R.string.my_time_zone_en)));
        if (gToday.get(Calendar.HOUR_OF_DAY) > 7 && gToday.get(Calendar.HOUR_OF_DAY) < 19)
            return;
        String bootParameters = readBootParameter(99);
        String[] params = bootParameters.split("-");
        initWaitTime = Long.parseLong(params[0]);
        if (initWaitTime > 3610 * 1000)
            return;
        onTime = Long.parseLong(params[1]);
        idleInterval = Long.parseLong(params[2]);
        myHandler.postDelayed(startNTime, initWaitTime);
    }

    void rePostSchedule() {
        postOneBoot();
        postNBoots();
    }
}

class OneTimeScheduler extends JobScheduler {
    // MainActivity.ONE_BOOT_PARAMS, bootParam); //  yyyy/mm/dd-hh:mm-last for minutes
    public OneTimeScheduler(ConnectDaemonService cs, TcpConnectDaemon dm) {
        super(cs, dm);
    }

    @Override
    protected void readParameter() {
        GregorianCalendar gToday = new GregorianCalendar(
                TimeZone.getTimeZone(mContext.getResources().getString(R.string.my_time_zone_en)));
        SharedPreferences sharedPref = mContext.getSharedPreferences(MainActivity.package_name + ".profile",
                Context.MODE_PRIVATE);
        String param = sharedPref.getString(MainActivity.ONE_BOOT_PARAMS, "--");
        Set<String> aSet = sharedPref.getStringSet(MainActivity.SET_ONE_BOOT, null);
        if (aSet == null) {
            last4 = -1;
            return;
        }
        String[] allData = new String[aSet.size()];
        allData = aSet.toArray(allData);
        String todayName = ScheduleActivity.weekDays[(gToday.get(Calendar.DAY_OF_WEEK) + 6) % 7];//ScheduleActivity.weekDays[gToday.get(Calendar.DAY_OF_WEEK)-1];
        param = null;
        for (int i = 0; i < aSet.size(); i++) {
            if (allData[i].indexOf(todayName) < 0)
                continue;
            param = allData[i].replace('>', '-'); //saved data format change to weekdayName>HH:MM-last4
            //data has form hh:mm-active period
            break;
        }
        if (param == null) {
            last4 = -1;
            return;
        }
        String[] terms = param.split("-");

        int iH = Integer.parseInt(terms[1].substring(0, 2));
        int iM = Integer.parseInt(terms[1].substring(3));
        int iHr = gToday.get(Calendar.HOUR_OF_DAY);
        int iMin = gToday.get(Calendar.MINUTE);

        init_wait = ((iH - iHr) * 60 + (iM - iMin)) * 60 * 1000;
        //in milli secs
        on_time = 60 * 1000 * Integer.parseInt(terms[2]);
        //if (init_wait>0)
        last4 = on_time;
        if (init_wait < -1 * 60 * 1000)
            on_time = -1;

        //in milli secs
        //last4=init_wait+end_time;
    }

    public String readBootParameter() {
        String retS = null;
        readParameter();
        if ((on_time < 1 || init_wait < 0))
            return null;
        if (init_wait > 3660000)
            return null;
        retS = "" + init_wait + "-" + on_time;
        return retS;
    }

    public void setResetStatus(boolean ya) {
        isWakenByReset = ya;
    }

    public void run() {
        boolean okStart = false;
        boolean iWasReset = true;
        if (wlR.isHeld())
            wlR.release();
        try {
            readParameter();
            //iWasReset=false;
            if (on_time < 1 || init_wait < 0) {
                Log.i("SCHEDULE_JOB", "One Time Start not schedule " + on_time + " and " + init_wait + " !!!!");
                return;
            }
            if (init_wait > 3605000) {
                Log.i("SCHEDULE_JOB", "One Time Start one hour away, not scheduled " + init_wait + " !!!!");
                return;
            }
            if (init_wait > 0) {
                Log.i("SCHEDULE_JOB", getId() + " One Time Start sleep " + init_wait / 60000 + " mins. to Sent!");
                wlR.acquire(init_wait + 6000);
                sleep(init_wait);
                wlR.release();
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
            //if (!killScheduledJob)
            //((ConnectDaemonService)mContext).resetScheduledJobs();
            Log.i("SCHEDULE_JOB", "One Time schedule Cancelled !!!!");
            return;
        }

        sendStartCommand(on_time / 60000);
        Log.i("SCHEDULE_JOB", "command to start engine for " + on_time / 60000 + " mins. Sent!");
        /*
        try {
                sleep(on_time);
            } catch (InterruptedException e)
            {
                e.printStackTrace();
            
                //sendStopCommand();
                //if (!killScheduledJob)
                //((ConnectDaemonService)mContext).resetScheduledJobs();
                return;
            }
            //long next_time=start_time+on_time+off_time;
            //sendStopCommand();//in case it is still running
            */
    }
}

class ContinueScheduler extends JobScheduler {
    // need start schedule too; MainActivity.N_BOOT_PARAMS, nBootParam); //HH:MM-on minutes-off minutes-cycle last for minutes

    /*boolean isWakenByReset=false;
    public void refresh(){
        
    }
    long start_time;
    long on_time;
    long off_time;
    long end_time;
    */
    public ContinueScheduler(ConnectDaemonService cs, TcpConnectDaemon dm) {
        super(cs, dm);
    }

    GregorianCalendar gToday;

    @Override
    protected void readParameter() {
        GregorianCalendar gToday = new GregorianCalendar(
                TimeZone.getTimeZone(mContext.getResources().getString(R.string.my_time_zone_en)));
        SharedPreferences sharedPref = mContext.getSharedPreferences(MainActivity.package_name + ".profile",
                Context.MODE_PRIVATE);
        String param = sharedPref.getString(MainActivity.N_BOOT_PARAMS, "--");
        Set<String> aSet = sharedPref.getStringSet(MainActivity.SET_MULTIPLE_BOOT, null);
        if (aSet == null) {
            last4 = -1;
            return;
        }
        String[] allData = new String[aSet.size()];
        allData = aSet.toArray(allData);
        String todayName = ScheduleActivity.weekDays[(gToday.get(Calendar.DAY_OF_WEEK) + 6) % 7];
        String yesterday = ScheduleActivity.weekDays[(gToday.get(Calendar.DAY_OF_WEEK) + 5) % 7];
        int hrNow = gToday.get(Calendar.HOUR_OF_DAY);
        param = null;
        for (int i = 0; i < aSet.size(); i++) {
            if (allData[i].indexOf(todayName) < 0)
                continue;
            param = allData[i].replace('>', '-'); //saved data format change to weekdayName>HH:MM-last4
            //data has form hh:mm-active period
            break;
        }
        if (hrNow > 7 && param == null) {
            last4 = -1;
            return;
        }
        int hrBase = 0;
        String param0 = null;
        if (hrNow < 7) {
            if (param != null) {
                int idd = param.indexOf("-");
                int h0 = Integer.parseInt(param.substring(idd + 1, idd + 3));
                if (h0 > 7)
                    param = null;
            }
            if (param == null) {
                for (int i = 0; i < aSet.size(); i++) {
                    if (allData[i].indexOf(yesterday) < 0)
                        continue;
                    param = allData[i].replace('>', '-');
                    break;
                }
                if (param == null) {
                    last4 = -1;
                    return;
                }
                int idd = param.indexOf("-");
                int h0 = Integer.parseInt(param.substring(idd + 1, idd + 3));
                if (h0 < 21) {
                    last4 = -1;
                    return;
                }
                hrBase = 24;
            }
        }

        Log.i("SCHEDULE_JOB", "found parameters " + param + " as new schedule");
        String[] terms = param.split("-");
        int icx = terms[1].indexOf(":");
        if (icx < 0) {
            last4 = -1;
            return;
        }
        int hrStart = Integer.parseInt(terms[1].substring(0, icx)); //starting hour
        int minStart = Integer.parseInt(terms[1].substring(icx + 1));
        hrNow += hrBase;
        //int hrEnd=7+hrBase;

        int minNow = gToday.get(Calendar.MINUTE);

        on_time = 1000 * 60 * Integer.parseInt(terms[2]); //in milli secs
        off_time = 1000 * 3600 * Integer.parseInt(terms[3]); //in milli secs

        init_wait = ((hrStart - hrNow) * 60 + (minStart - minNow)) * 60 * 1000; //in milli secs
        while (init_wait < 0) {
            init_wait += (on_time + off_time);
        }
        //change the end time to 07:00AM
        //int endHr=7;
        // if (iH > 7) endHr=7+24;
        //end_time=((endHr-iH)*60+(0-iM))*60*1000;
        //end_time=1000*60*Integer.parseInt(terms[3]); //in milli secs
        //last4=init_wait+end_time;
        last4 = 1000;
    }

    public String readBootParameter() {
        String retS = null;
        readParameter();
        if (last4 < 0)
            return null;
        if ((on_time < 1 || init_wait < 0))
            return null;
        //if (init_wait >3605000) return null;
        retS = "" + init_wait + "-" + on_time + "-" + off_time;
        return retS;
    }

    public void setResetStatus(boolean ya) {
        isWakenByReset = ya;
    }

    public void run() {
        String jobReport = "";
        if (wlR.isHeld())
            wlR.release();
        gToday = new GregorianCalendar(
                TimeZone.getTimeZone(mContext.getResources().getString(R.string.my_time_zone_en)));
        int hrNow = gToday.get(Calendar.HOUR_OF_DAY);
        if (hrNow > 7 && hrNow < 19) {
            Log.i("SCHEDULE_JOB", "recurring not schedule !!!!");
            return;
        }
        boolean okStart = false;
        boolean iWasReset = true;
        try {
            readParameter();
            //iWasReset=false;
            if (last4 < 0) {
                Log.i("SCHEDULE_JOB", "recurring not schedule !!!!");
                return;
            }
            if (init_wait > 0) {
                Log.i("SCHEDULE_JOB", getId() + " sleep " + init_wait / 60000 + " mins. to Sent!");
                wlR.acquire();
                sleep(init_wait);
                wlR.release();
                iWasReset = false;
                //last4 -= init_wait;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            //if (!killScheduledJob)
            //((ConnectDaemonService)mContext).resetScheduledJobs();
            Log.i("SCHEDULE_JOB", "recurring schedule " + jobReport + " !!!!");
            return;
        }

        gToday = new GregorianCalendar(
                TimeZone.getTimeZone(mContext.getResources().getString(R.string.my_time_zone_en)));
        int thisHr = gToday.get(Calendar.HOUR_OF_DAY);
        int endHr = 7;
        if (thisHr > 7)
            endHr = 31;

        last4 = (endHr - thisHr) * 60 + (0 - gToday.get(Calendar.MINUTE));
        last4 *= 60000;

        start_time = new Date().getTime();
        end_time = start_time + last4;

        while (start_time < end_time) { /*pending*/
            sendStartCommand(on_time / 60000); //change to minute
            Log.i("SCHEDULE_JOB", "recurring command to start engine for " + on_time / 60000 + " mins. Sent!");
            try {
                sleep(on_time);
            } catch (InterruptedException e) {
                e.printStackTrace();
                jobReport = "CANCELLED";
                //sendStopCommand();
                //if (!killScheduledJob)
                //((ConnectDaemonService)mContext).resetScheduledJobs();
                Log.i("SCHEDULE_JOB", getId() + " recurring schedule " + jobReport + " !!!!");
                return;
            }
            //long next_time=start_time+on_time+off_time;
            //sendStopCommand();//in case it is still running
            try {
                Log.i("SCHEDULE_JOB",
                        getId() + " recurring command let engine idle for " + off_time / 60000 + " mins. Sent!");
                sleep(off_time);
            } catch (InterruptedException e) {
                e.printStackTrace();
                //if (!killScheduledJob)
                //((ConnectDaemonService)mContext).resetScheduledJobs();
                jobReport = "CANCELLED";
                Log.i("SCHEDULE_JOB", "recurring schedule " + jobReport + " !!!!");
                return;
            }
            start_time = new Date().getTime();
            jobReport = "FINISHED";
        }
        Log.i("SCHEDULE_JOB", "recurring schedule " + jobReport + " !!!!");
    }
}