package com.xypower.mpmaster;

import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationChannel;
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.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.PowerManager;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

import androidx.core.app.NotificationCompat;

import com.dev.devapi.api.SysApi;
import com.xypower.common.FileDownloader;
import com.xypower.common.JSONUtils;
import com.xypower.common.MicroPhotoContext;
import com.xypower.mpmaster.sms.SimUtil;
import com.xypower.mpmaster.sms.SmsSendReceiver;

import org.json.JSONObject;

import java.io.File;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MpMasterService extends Service {
    static {
        System.loadLibrary("mpmaster");
    }

    public static final String TAG = "MPMST";

    public Logger logger;

    public static final int NOTIFICATION_ID_FOREGROUND_SERVICE = 8466503;
    public static final String ACTION_MSG_BROADCAST = "ACT_MSG_BROADCAST";

    public static final String ACTION_START = "com.xypower.mpmaster.ACT_START";
    public static final String ACTION_STOP = "com.xypower.mpmaster.ACT_STOP";
    public static final String ACTION_MAIN = "com.xypower.mpmaster.ACT_MAIN";

    public static final String ACTION_UPD_OTA = SysApi.OTA_RESULT_ACTION;
    public static final String ACTION_INSTALL_RESULT = SysApi.INSTALL_RESULT_ACTION;
    public static final String ACTION_UNINSTALL_RESULT = SysApi.UNINSTALL_RESULT_ACTION;

    private static final String ACTION_UPDATE_CONFIGS = "com.xypower.mpmaster.ACT_UPD_CFG";

    private static final String ACTION_HEARTBEAT = "com.xypower.mpmaster.ACT_HB";
    private static final String ACTION_TAKE_PHOTO = "com.xypower.mpapp.ACT_TP";

    public static final String ACTION_IMP_PUBKRY = "com.xypower.mpapp.ACT_IMP_PUBKEY";

    private static final String EXTRA_PARAM_SCHEDULES = "Schedules";
    private static final String EXTRA_PARAM_SCHEDULE = "Schedule_";
    private static final String EXTRA_PARAM_TIME = "Time";
    private static final String FOREGROUND_CHANNEL_ID = "foreground_channel_id";
    private SmsSendReceiver mSmsSnedReceiver;

    public static class STATE_SERVICE {
        public static final int CONNECTED = 10;
        public static final int NOT_CONNECTED = 0;
    }

    private static int mStateService = STATE_SERVICE.NOT_CONNECTED;

    private boolean mMntnMode = false;
    private boolean mQuickHbMode = false;
    private boolean mUsingAbsHbTime = false;
    private String mCmdid = "";
    private NotificationManager mNotificationManager;
    private int mQuickHeartbeatDuration = 60; // 1m = 60 s
    private int mHeartbeatDuration = 600; // 10m = 10 * 60s

    private AlarmReceiver mAlarmReceiver = null;
    private ScreenActionReceiver mScreenaAtionReceiver = null;
    private UpdateReceiver mUpdateReceiver = null;

    private ServiceHandler mHander = null;

    private String mModelName = null;

    private static String mMpAppVersion = null;
    private static String mMpMasterVersion = null;

    private String mSerialNo = null;

    private long mTimeToStartMpApp = 0;
    private long mTimeOfMpAppAlive = 1800000; // 30minutes
    private int mAbsHeartbeatTimes[] = null;

    private boolean mSeparateNetwork = false;

    private PendingIntent mPreviousHB = null;
    private long mPreviousHeartbeatTime = 0;

    private long mPreviousMpHbTime = 0;

    private String mIccid1 = null;
    private String mIccid2 = null;

    public MpMasterService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

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

        loadConfig();
        loadIccid();

        logger = Logger.getLogger("com.xypower.mpmaster.logger");
        logger.setLevel(Level.ALL);
        // LogFormatter.installFormatter(logger);
        LogFormatter logFormatter = new LogFormatter();

        if (BuildConfig.DEBUG) {
            LogcatHandler logcatHandler = new LogcatHandler(TAG);
            logcatHandler.setFormatter(logFormatter);
            logger.addHandler(logcatHandler);
        }

        FileHandler fileHandler = null;
        try {
            String appPath = MicroPhotoContext.buildMasterAppDir(getApplicationContext());
            String logPath = appPath + "logs";
            File fi = new File(logPath);
            if (!fi.exists()) {
                fi.mkdirs();
            }

            File logFile = new File(fi, "log.%g.txt");
            int logFileLimit = BuildConfig.DEBUG ? (16 * 1024) : (2 * 1024 * 1024);
            int logFileCount = BuildConfig.DEBUG ? 4 : 128;

            fileHandler = new FileHandler(logFile.getAbsolutePath(), logFileLimit, logFileCount, true);

            fileHandler.setLevel(Level.ALL);//级别为ALL，记录所有消息
            // fileHandler.

            fileHandler.setFormatter(logFormatter);
            logger.addHandler(fileHandler);

        } catch (Throwable e) {
            System.out.println("Failed to create directory:" + e.getMessage());
        }

        try {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                mSerialNo = Build.getSerial();
            } else {
                mSerialNo = Build.SERIAL;
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        mMpMasterVersion = MicroPhotoContext.getVersionName(getApplicationContext());
        PackageManager packageManager = getPackageManager();
        PackageInfo packageInfo = null;
        try {
            packageInfo = packageManager.getPackageInfo(MicroPhotoContext.PACKAGE_NAME_MPAPP, 0);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        mMpAppVersion = packageInfo == null ? "" : packageInfo.versionName;

        logger.info("MpMaster started version=" + mMpMasterVersion);

        mHander = new ServiceHandler();

        mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        mStateService = STATE_SERVICE.NOT_CONNECTED;

        mScreenaAtionReceiver = new ScreenActionReceiver();

        // 注册广播接受者
        {
            mAlarmReceiver = new AlarmReceiver(this);
            IntentFilter intentFilter = new IntentFilter(ACTION_HEARTBEAT);
            // intentFilter.addAction(ACTION_TAKE_PHOTO);
            // intentFilter.addAction(ACTION_TIMEOUT);
            // intentFilter.addAction(ACTION_TAKE_PHOTO_MANUALLY);
            intentFilter.addAction(ACTION_MSG_BROADCAST);
            intentFilter.addAction(ACTION_UPDATE_CONFIGS);
            intentFilter.addAction(ACTION_UPD_OTA);
            intentFilter.addAction(ACTION_INSTALL_RESULT);
            intentFilter.addAction(ACTION_UNINSTALL_RESULT);
            intentFilter.addAction(MicroPhotoContext.ACTION_HEARTBEAT_MP);

            registerReceiver(mAlarmReceiver, intentFilter);
        }

        {
            mUpdateReceiver = new UpdateReceiver();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
            intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
            intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
            intentFilter.addDataScheme("package");
            registerReceiver(mUpdateReceiver, intentFilter);
        }

        //自定义发送短信广播接收器
        mSmsSnedReceiver = new SmsSendReceiver();
        IntentFilter intentFilter;
        intentFilter = new IntentFilter(SimUtil.SMS_SEND_ACTION);
        registerReceiver(mSmsSnedReceiver, intentFilter);
    }

    public String getIccid(int number) {
        if (number == 1) {
            return mIccid1 == null ? "" : mIccid1;
        } else {
            return mIccid2 == null ? "" : mIccid2;
        }
    }

    @Override
    public void onDestroy() {

        mStateService = STATE_SERVICE.NOT_CONNECTED;

        logger.warning("MicroPhotoService::onDestroy called");

        unregisterReceiver(mAlarmReceiver);
        unregisterReceiver(mScreenaAtionReceiver);
        unregisterReceiver(mUpdateReceiver);
        unregisterReceiver(mSmsSnedReceiver);

        for (java.util.logging.Handler h : logger.getHandlers()) {
            try {
                h.close();
            } catch (Exception ex) {
            }
        }

        super.onDestroy();
    }

    public static class ServiceHandler extends Handler {
        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);
            // Log.i("life", "MyHandler----dispatchMessage");
            // Log.i("life", Thread.currentThread().getName());
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            // Log.i("life", "MyHandler----handleMessage");
        }
    }

    protected void loadConfig() {
        MicroPhotoContext.MasterConfig masterConfig = MicroPhotoContext.getMasterConfig(getApplicationContext());
        mMntnMode = masterConfig.mntnMode != 0;
        mQuickHbMode = masterConfig.quickHbMode != 0;
        mUsingAbsHbTime = masterConfig.usingAbsHbTime != 0;
        mHeartbeatDuration = masterConfig.heartbeat * 60;   // minute to second
        mAbsHeartbeatTimes = masterConfig.absHeartbeats;
        if (mAbsHeartbeatTimes != null && mAbsHeartbeatTimes.length > 0) {
            Arrays.sort(mAbsHeartbeatTimes);
        }
        mSeparateNetwork = masterConfig.separateNetwork != 0;
        mTimeOfMpAppAlive = masterConfig.mpappMonitorTimeout;
    }

    private void loadIccid() {
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
            try {
                SubscriptionManager sm = SubscriptionManager.from(this);
                List<SubscriptionInfo> sis = sm.getActiveSubscriptionInfoList();
                if (sis.size() >= 1) {
                    SubscriptionInfo si1 = sis.get(0);
                    mIccid1 = si1.getIccId();
                    // String phoneNum1 = si1.getNumber();
                }
                if (sis.size() >= 2) {
                    SubscriptionInfo si2 = sis.get(1);
                    mIccid2 = si2.getIccId();
                    // String phoneNum2 = si2.getNumber();
                }
                // int count = sm.getActiveSubscriptionInfoCount();// real cards
                // int max   = sm.getActiveSubscriptionInfoCountMax();// Slot number

            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    // public boolean useSeparater
    public String getCmdid() {
        return mCmdid;
    }

    public boolean isSeparateNetwork() {
        return mSeparateNetwork;
    }

    public boolean isMntnMode() {
        return mMntnMode;
    }

    public void startMpApp() {
        try {
            final Context context = getApplicationContext();

            if (MicroPhotoContext.isAppAlive(context, MicroPhotoContext.PACKAGE_NAME_MPAPP)) {
                return;
            }

            String appPath = MicroPhotoContext.buildMpAppDir(context);
            long ts = System.currentTimeMillis();
            if (ts - mTimeToStartMpApp < 30000) {
                return;
            }

            File mpappHb = new File(appPath + "data/alive/hb");
            long modifiedTimeOfHb = getFileModificationTime(appPath + "data/alive/hb");
            long modifiedTimeOfPhoto = getFileModificationTime(appPath + "data/alive/taking");
            long modifiedTimeOfUpload = getFileModificationTime(appPath + "data/alive/upload");

            if (((ts - modifiedTimeOfHb) > mTimeOfMpAppAlive) ||
                    ((ts - modifiedTimeOfPhoto) > mTimeOfMpAppAlive * 4) ||
                    ((ts - modifiedTimeOfUpload) > mTimeOfMpAppAlive * 4)) {
                // greater than 30m
                logger.warning("Restart MpAPP as it is NOT Running");
                MicroPhotoContext.restartMpApp(context);
                mTimeToStartMpApp = ts;
            }
        } catch (Exception ex) {

        }
    }

    long getFileModificationTime(String path) {
        File file = new File(path);
        long mt = 0;
        if (file.exists()) {
            mt = file.lastModified();
        }

        return mt;
    }

    public String getMpAppVersion() {
        if (TextUtils.isEmpty(mMpAppVersion)) {
            PackageManager packageManager = getPackageManager();
            PackageInfo packageInfo = null;
            try {
                packageInfo = packageManager.getPackageInfo(MicroPhotoContext.PACKAGE_NAME_MPAPP, 0);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            mMpAppVersion = packageInfo == null ? "" : packageInfo.versionName;
        }
        return mMpAppVersion;
    }

    public static void resetVersions() {
        mMpAppVersion = null;
        mMpMasterVersion = null;
    }

    public String getMasterAppVersion() {
        if (TextUtils.isEmpty(mMpMasterVersion)) {
            mMpMasterVersion = MicroPhotoContext.getVersionName(getApplicationContext());
        }
        return mMpMasterVersion;
    }

    public String getSerialNo() {
        return mSerialNo;
    }

    static String convertSwitch(boolean swtch) {
        return swtch ? "ON" : "OFF";
    }

    public void setMntnMode(boolean mntnMode, boolean quickHbMode) {
        boolean oldMntnMode = mMntnMode;
        boolean oldQuickHbMode = mQuickHbMode;

        mMntnMode = mntnMode;
        mQuickHbMode = quickHbMode;

        if (oldMntnMode != mntnMode || oldQuickHbMode != quickHbMode) {
            MicroPhotoContext.MasterConfig masterConfig = MicroPhotoContext.getMasterConfig(getApplicationContext());

            masterConfig.mntnMode = mntnMode ? 1 : 0;
            masterConfig.quickHbMode = quickHbMode ? 1 : 0;

            MicroPhotoContext.saveMasterConfig(getApplicationContext(), masterConfig);

            logger.warning("MNTN Mode Changed from " + convertSwitch(oldMntnMode) + " to " + convertSwitch(mntnMode)
                    + " Quick Heartbeat from " + convertSwitch(oldQuickHbMode) + " to " + convertSwitch(quickHbMode));
        }

        if (oldQuickHbMode != quickHbMode) {
            // Cancel cuurent job first

            if (quickHbMode) {
                registerHeartbeatTimer();
            }
        }
    }

    private void startMaster(boolean bundleWithMpApp) {
        String masterUrl = MicroPhotoContext.DEFAULT_MASTER_URL;

        MicroPhotoContext.MasterConfig masterConfig = MicroPhotoContext.getMasterConfig(getApplicationContext());
        String url = masterConfig.getUrl();
        if (!TextUtils.isEmpty(url)) {
            masterUrl = url;
        }

        MicroPhotoContext.AppConfig appConfig = MicroPhotoContext.getMpAppConfig(getApplicationContext());

        logger.warning("Start Mntn report:" + masterUrl + " Mntn Mode=" + Boolean.toString(mMntnMode) + " QuickHB=" + Boolean.toString(mQuickHbMode));

        AppMaster appMaster = new AppMaster(this, masterUrl, appConfig.cmdid, bundleWithMpApp);
        appMaster.start();
    }

    public static class AlarmReceiver extends BroadcastReceiver {
        private MpMasterService mService;
        public AlarmReceiver() {
            mService = null;
        }
        public AlarmReceiver(MpMasterService service) {
            mService = service;
        }
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (TextUtils.equals(ACTION_HEARTBEAT, action)) {
                mService.logger.info("Heartbeat Timer Fired ACTION=" + action);

                mService.mPreviousHB = null;
                mService.registerHeartbeatTimer();

                mService.startMaster(false);
                mService.startMpApp();

            } else if (TextUtils.equals(MicroPhotoContext.ACTION_HEARTBEAT_MP, action)) {
                mService.mPreviousMpHbTime = System.currentTimeMillis();

                if (!mService.mSeparateNetwork || (mService.mMntnMode || mService.mQuickHbMode)) {
                    mService.logger.info("Heartbeat Timer Fired By MpAPP ACTION=" + action);

                    long ts = System.currentTimeMillis();
                    if (mService.mPreviousHeartbeatTime - ts < mService.mHeartbeatDuration * 1000) {
                        mService.registerHeartbeatTimer(mService.mPreviousHeartbeatTime + mService.mHeartbeatDuration * 1000);
                    }

                    mService.startMaster(true);
                    mService.startMpApp();
                }
            } else if (TextUtils.equals(ACTION_UPDATE_CONFIGS, action)) {
                int restart = intent.getIntExtra("restart", 0);
                mService.logger.info("Update Config Fired ACTION=" + action + " restart=" + restart);
                if (restart != 0) {
                    mService.restartApp(context, context.getPackageName());
                } else {
                    mService.loadConfig();
                    mService.registerHeartbeatTimer();
                }
            } else if (TextUtils.equals(ACTION_UPD_OTA, action)) {

                String cmd = intent.getStringExtra("cmd");
                String msg = intent.getStringExtra("msg");
                // Log.e("_otg_","cmd="+cmd);
                if("write".equals(cmd))
                {
                    // int progress = Integer.parseInt(msg);
                }
                else if("update".equals(cmd))
                {
                    // int progress = Integer.parseInt(msg);
                }
                else if("info".equals(cmd))
                {

                }
                else if("error".equals(cmd))
                {
                    mService.logger.warning("UPD OTA Failed");
                }
                else if("success".equals(cmd))
                {
                    //confirm to reboot device ??
                    mService.logger.warning("UPD OTA Succeeded, will RESET dev");
                    Handler handler = new Handler();
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            SysApi.reboot(context);
                        }
                    }, 1000);
                }
            } else if (TextUtils.equals(ACTION_INSTALL_RESULT, action)) {
                boolean bSucc = intent.getBooleanExtra("succ", false);
                String pkname = intent.getStringExtra("pkname");
                String msg = intent.getStringExtra("msg");
                // Log.e("_otg_","install result bsuc="+bSucc+",pkname="+pkname+",msg="+msg);
                mService.logger.warning("INSTALL APP result =" + bSucc + ",pkname=" + pkname + ",msg=" + msg);
            } else if (TextUtils.equals(ACTION_UNINSTALL_RESULT, action)) {
                boolean bSucc = intent.getBooleanExtra("succ", false);
                String pkname = intent.getStringExtra("pkname");
                String msg = intent.getStringExtra("msg");
                mService.logger.warning("UNINSTALL APP result =" + bSucc + ",pkname=" + pkname + ",msg=" + msg);
            }
        }
    }

    private void registerHeartbeatTimer() {

        long timeout = mHeartbeatDuration;
        if (mMntnMode) {
            if (mQuickHbMode) {
                timeout = mQuickHeartbeatDuration;
            }
            registerHeartbeatTimer(System.currentTimeMillis() + timeout * 1000);
        } else {
            long closestTime = -1;
            if (mUsingAbsHbTime) {
                Date dt = new Date();
                long ts = dt.getTime();
                ts -= ts % 1000;

                dt.setHours(0);
                dt.setMinutes(0);
                dt.setSeconds(0);

                long zeroPoint = dt.getTime();
                zeroPoint -= zeroPoint % 1000;
                long offsetTs = (ts - zeroPoint) / 1000;

                if (mAbsHeartbeatTimes != null && mAbsHeartbeatTimes.length > 0) {

                    for (int i = 0; i < mAbsHeartbeatTimes.length; i++) {
                        if (mAbsHeartbeatTimes[i] > offsetTs) {
                            closestTime = mAbsHeartbeatTimes[i];
                            break;
                        }
                    }

                    if (closestTime == -1) {
                        // next day
                        closestTime = mAbsHeartbeatTimes[0] + 86400;
                    }
                } else {
                    closestTime = 9 * 3600 + 13 * 60;
                    if (offsetTs > closestTime) {
                        closestTime += 86400;
                    }
                }

                registerHeartbeatTimer(zeroPoint + closestTime * 1000);
            } else {
                registerHeartbeatTimer(System.currentTimeMillis() + timeout * 1000);
            }
        }
    }

    private void registerHeartbeatTimer(long triggerTime) {

        AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
        if (mPreviousHB != null) {
            try {
                alarmManager.cancel(mPreviousHB);
                mPreviousHB = null;
            } catch (Exception ex) {
            }
            mPreviousHeartbeatTime = 0;
        }
        Intent alarmIntent = new Intent();
        alarmIntent.setAction(ACTION_HEARTBEAT);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);

        Date dt = new Date(triggerTime);
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        logger.info(String.format("Register HB:" + format.format(dt)));
        mPreviousHB = pendingIntent;
        mPreviousHeartbeatTime = triggerTime;
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        if (intent == null) {
            stopForeground(true);
            stopSelf();
            return START_NOT_STICKY;
        }

        // if user starts the service
        switch (intent.getAction()) {
            case ACTION_START:
                Log.d(TAG, "Received user starts foreground intent");
                startForeground(NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification());

                connect();

                registerReceiver(mScreenaAtionReceiver, mScreenaAtionReceiver.getFilter());

                String appPath = MicroPhotoContext.buildAppDir(this.getApplicationContext());

                String cmdid = intent.getStringExtra("cmdid");
                if (TextUtils.isEmpty(cmdid)) {
                    mCmdid = SysApi.getSerialNo(getApplicationContext());
                } else {
                    mCmdid = cmdid;
                }

                logger.info("AppPath=" + appPath + " cmdid=" + cmdid);

                // startMaster(false);
                mHander.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        startMpApp();
                    }
                }, 5000);

                // Reset Data Network
                // logger.info("Switch to Simcard 1");
                // SysApi.selectSimCard4Data(getApplicationContext(), 1);

                registerHeartbeatTimer();

                startMaster(false);

                break;
            case ACTION_STOP:
                unregisterReceiver(mScreenaAtionReceiver);

                stopForeground(true);
                stopSelf();
                break;
            default:
                stopForeground(true);
                stopSelf();
        }

        return START_NOT_STICKY;
    }

    private void connect() {
        // after 10 seconds its connected
        mHander.postDelayed(
                new Runnable() {
                    public void run() {
                        // Log.d(TAG, "Bluetooth Low Energy device is connected!!");
                        Toast.makeText(getApplicationContext(), "Connected!", Toast.LENGTH_SHORT).show();
                        mStateService = STATE_SERVICE.CONNECTED;
                        startForeground(NOTIFICATION_ID_FOREGROUND_SERVICE, prepareNotification());
                    }
                }, 10000);

    }

    private Notification prepareNotification() {
        // handle build version above android oreo
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O &&
                mNotificationManager.getNotificationChannel(FOREGROUND_CHANNEL_ID) == null) {
            CharSequence name = getString(R.string.text_name_notification);
            int importance = NotificationManager.IMPORTANCE_DEFAULT;
            NotificationChannel channel = new NotificationChannel(FOREGROUND_CHANNEL_ID, name, importance);
            channel.enableVibration(false);
            mNotificationManager.createNotificationChannel(channel);
        }

        Intent notificationIntent = new Intent(this, MainActivity.class);
        notificationIntent.setAction(ACTION_MAIN);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

        // if min sdk goes below honeycomb
        /*if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
            notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
        } else {
            notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }*/

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        // make a stop intent
        Intent stopIntent = new Intent(this, MpMasterService.class);
        stopIntent.setAction(ACTION_STOP);
        PendingIntent pendingStopIntent = PendingIntent.getService(this, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.notification);
        remoteViews.setOnClickPendingIntent(R.id.btn_stop, pendingStopIntent);

        // if it is connected
        switch (mStateService) {
            case STATE_SERVICE.NOT_CONNECTED:
                remoteViews.setTextViewText(R.id.tv_state, "DISCONNECTED");
                break;
            case STATE_SERVICE.CONNECTED:
                remoteViews.setTextViewText(R.id.tv_state, "CONNECTED");
                break;
        }

        // notification builder
        NotificationCompat.Builder notificationBuilder;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            notificationBuilder = new NotificationCompat.Builder(this, FOREGROUND_CHANNEL_ID);
        } else {
            notificationBuilder = new NotificationCompat.Builder(this);
        }
        notificationBuilder
                .setContent(remoteViews)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setCategory(NotificationCompat.CATEGORY_SERVICE)
                .setOnlyAlertOnce(true)
                .setOngoing(true)
                .setAutoCancel(true)
                .setContentIntent(pendingIntent);

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            notificationBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
        }

        return notificationBuilder.build();
    }

    public String buildAppDir() {

        String path = Environment.getExternalStorageDirectory().getAbsolutePath();
        if (!path.endsWith(File.separator)) {
            path += File.separator;
        }
        path += getApplicationContext().getPackageName() + File.separator;
        File pathFile = new File(path);
        if (!pathFile.exists() && !pathFile.mkdirs()) {
            return null;
        }

        return path;
    }

    public boolean updateMntn(String url) {
        if (TextUtils.isEmpty(url)) {
            return false;
        }
        String path = buildAppDir();
        path += "data/Master.json";
        JSONObject jsonObject = JSONUtils.loadJson(path);

        String oldUrl = null;
        try {
            oldUrl = jsonObject.getString("url");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        if (TextUtils.equals(url, oldUrl)) {
            return true;
        }

        try {
            jsonObject.put("url", url);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        return JSONUtils.saveJson(path, jsonObject);
    }

    public boolean updateTime(long timeInMillis) {
        try {
            SysApi.setSystemTime(getApplicationContext(), timeInMillis);
        } catch (Exception ex) {
        }
        return true;
    }

    public static int getSignalLevel(int num) {
        String result = getSystemProperty("vendor.ril.nw.signalstrength.lte." + Integer.toString(num));
        if (TextUtils.isEmpty(result)) {
            return 0;
        }
        String[] items = result.split(",");
        int rsrp = -140;

        if (items != null && items.length > 0) {
            try {
                rsrp = Integer.parseInt(items[0]);
            } catch (Exception ex) {
            }
        }
        int signalLevel = 0;
        if (rsrp >= -97) {
            signalLevel = 4;
        } else if (rsrp >= -107) {
            signalLevel = 3;
        } else if (rsrp >= -117) {
            signalLevel = 2;
        } else if (rsrp >= -125) {
            signalLevel = 1;
        } else if (rsrp >= -140) {
            signalLevel = 0;
        }

        return signalLevel;
    }

    public void downloadAndInstall(final String url) {

        final Context context = getApplicationContext();
        final String tempPath = MicroPhotoContext.buildAppDir(context) + File.separator + "tmp";
        File file = new File(tempPath);
        file.mkdirs();
        final String filePath = tempPath + File.separator + "mp.apk";
        Thread th =new Thread(new Runnable() {
            @Override
            public void run() {

                PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
                PowerManager.WakeLock wl = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "com.xinyingpower.microphoto:Upgrader");

                FileDownloader fd = new FileDownloader();
                fd.download(url, filePath);

                SysApi.installApk(context, filePath, context.getPackageName(), true);

                try {
                    wl.setReferenceCounted(false);
                    wl.release();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
        th.start();
    }

    public void reboot(final int rebootType) {

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                if (rebootType == 0) {
                    logger.warning("Recv REBOOT MpMst APP cmd");
                    Context context = MpMasterService.this.getApplicationContext();
                    restartApp(context, context.getPackageName());

                } else {
                    logger.warning("Recv RESET cmd");
                    SysApi.reboot(MpMasterService.this.getApplicationContext());
                }
            }
        };
        mHander.postDelayed(runnable, 1000);
    }

    public static void restartApp(Context context, String packageName) {
        /*
        Context context = MicroPhotoService.this.getApplicationContext();
        Intent intent = getPackageManager().getLaunchIntentForPackage(context.getPackageName());

        int noDelay = 1;
        intent.putExtra("noDelay", noDelay);
        PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent, 0);
        AlarmManager mgr = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
        mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用
        System.exit(0);

                     */

        Intent LaunchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
        LaunchIntent.putExtra("noDelay", 1);
        LaunchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        context.startActivity(LaunchIntent);
    }

    public void selectSimCard(int num) {
        logger.info("Try to Switch To SimCard: " + Integer.toString(num));

        Context context = getApplicationContext();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {

            SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
            int activeSubId = SubscriptionManager.getActiveDataSubscriptionId();
            int activeSlotIdx = SubscriptionManager.getSlotIndex(activeSubId);
            if (activeSlotIdx == (num - 1)) {
                logger.info("Active SimCard is already " + Integer.toString(num));
            } else {
                int subIds[] = subscriptionManager.getSubscriptionIds(num - 1);
                if (subIds != null && subIds.length > 0) {
                    setDefaultDataSubId(subIds[0]);
                    logger.info("Switched To SimCard: " + Integer.toString(num));
                }
            }
        } else {
            SysApi.selectSimCard4Data(context, num);
        }
    }

    private void setDefaultDataSubId(int subId) {
        SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        try {

            Method method = subscriptionManager.getClass().getDeclaredMethod("setDefaultDataSubId", int.class);
            method.invoke(subscriptionManager, subId);
            TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
            telephonyManager.setDataEnabled(true);
            Method method1 = telephonyManager.getClass().getDeclaredMethod("setDataEnabled", boolean.class);
            method1.invoke(telephonyManager, true);
        } catch (Exception e) {
            // Log.e(TAG, "wjz debug setDefaultDataSubId: error is " + e.getMessage());
            e.printStackTrace();
        }
    }

    private int getDefaultDataSubId() {
        SubscriptionManager subscriptionManager = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        try {
            Method method = subscriptionManager.getClass().getDeclaredMethod("getDefaultDataSubscriptionId");
            return (int) method.invoke(subscriptionManager);
        } catch (Exception e) {
            Log.e(TAG, "wjz debug getDefaultDataSubId: error is " + e.getMessage());
        }
        return 0;
    }

    public native static int getInt(int cmd);
    public native static int[] getStats(long ts);
    public native static String getSystemProperty(String key);


    ////////////////////////GPS////////////////////
    
}