package com.tofly.ghrq_route.base;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.location.Location;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.StrictMode;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;

import androidx.multidex.MultiDex;

import com.android.volley.DefaultRetryPolicy;
import com.android.volley.InternalUtils;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.toolbox.HurlStack;
import com.android.volley.toolbox.Volley;
import com.mgq.base.utils.encrypt.AESUtils;
import com.mgq.base.utils.net.NetworkStatus;
import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
import com.nostra13.universalimageloader.cache.memory.impl.UsingFreqLimitedMemoryCache;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import com.nostra13.universalimageloader.core.assist.ImageScaleType;
import com.nostra13.universalimageloader.core.assist.QueueProcessingType;
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
import com.nostra13.universalimageloader.core.display.RoundedBitmapDisplayer;
import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
import com.tofly.ghrq_route.R;
import com.tofly.ghrq_route.base.url.NetRequestURL;
import com.tofly.ghrq_route.module.download.service.DownloadService;
import com.tofly.ghrq_route.module.gps.AmapLocationUtils;
import com.tofly.ghrq_route.module.gps.GpsTool;
import com.tofly.ghrq_route.module.service.DeviceMonitorService;
import com.tofly.ghrq_route.module.service.OfflineWorkerService;
import com.tofly.ghrq_route.module.service.UploadGPSService;
import com.tofly.ghrq_route.module.sqlite.DBDaoHelper;
import com.tofly.ghrq_route.module.systemConfig.domain.ServerParamConfigBean;
import com.tofly.ghrq_route.module.systemConfig.domain.SystemConfigBean;
import com.tofly.ghrq_route.module.user.UserInfoTool;
import com.tofly.ghrq_route.module.user.domain.UserBean;
import com.tofly.ghrq_route.common.ui.dialog.ConnectHintDialog;
import com.tofly.ghrq_route.common.util.CheckUtil;
import com.tofly.ghrq_route.common.util.app.AppUtil;
import com.tofly.ghrq_route.common.util.crashHandler.CrashHandler;
import com.tofly.ghrq_route.common.util.net.volley.MultiPartStack;
import com.tofly.ghrq_route.common.util.sharedPreference.SharePreUtil;

import org.apache.commons.codec.CharEncoding;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;

/*import okhttp3.OkHttpClient;*/

/**
 * Created by zombiexq on 2016/6/13.
 */
public class BaseApp extends Application {

    private static final String TAG = BaseApp.class.getSimpleName();

    private static BaseApp singleton;
    private static Stack<Activity> activityStack;
    /*public LocationService locationService;*/
   /* public OkHttpClient okHttpClient;*/
    private UserBean loginUser = null;

    public OkHttpClient okHttpClient;

    private static RequestQueue mRequestQueue = null;
    private static RequestQueue mMultiStatckRequestQueue = null;
    private static RequestQueue mStreamRequestQueue = null;
//    超时设置
    /** The default socket timeout in milliseconds */
    public static final int DEFAULT_TIMEOUT_MS = 10000; //10s

    /** The default number of retries */
    public static final int DEFAULT_MAX_RETRIES = DefaultRetryPolicy.DEFAULT_MAX_RETRIES;    //重试1次

    /** The default number of retries for file/long request */
    public static final int DEFAULT_FILE_MAX_RETRIES = 1;

    public static final int UPLOAD_FILE_TIMEOUT_MS = 30 * 1000;

    public static final int UPLOAD_BATCH_TIMEOUT_MS = 60 * 1000;

    public static final int GPS_SAVED_DAY_MAX = 45;

    public static final int LOG_SAVED_DAY_MAX = 30;


    /** 当前设备分辨率 */
    private static float density;
    /** 当前设备宽度 */
    private static int deviceWidth;
    /** 当前设备高度*/
    private static int deviceHeight;
    /** 当前设备dpi */
    private static int deviceDpi;

    /** 当前设备IMEI */
    public static String imei;

    public static List<String> imeisList;

    public static String android_version;

    public static int app_version_code = 1;

    public static String app_version_name;

    public static final String AES_CODE_KEY = "tofly_route_android_key";

    private static boolean bHasAlertNoticeOff = false;

    public static String AESEncodeString(String input_string){
        AESUtils aesUtils = AESUtils.getInstance(AES_CODE_KEY.getBytes());
        return aesUtils.encryptStringToHex(input_string, CharEncoding.UTF_8);
    }

    public static String AESDecodeString(String input_string){
        AESUtils aesUtils = AESUtils.getInstance(AES_CODE_KEY.getBytes());
        return aesUtils.decryptHexToString(input_string, CharEncoding.UTF_8);
    }

    public static String SHA1EncodeString(String input_string){
        return InternalUtils.sha1LHash(input_string);
    }

    private ConnectHintDialog connectHintDialog;

    public ConnectHintDialog getConnectHintDialog(){
        return connectHintDialog;
    }

    private static final String CONFIG_IP_ADDR_ID = SystemConfigBean.SERVER_ADDR_KEY;
    private static final String CONFIG_IP_ADDR_DES = SystemConfigBean.SERVER_ADDR_DESC;

/*    private static final String CONFIG_IP_PORT_ID = SystemConfigBean.SERVER_PORT_KEY;
    private static final String CONFIG_IP_PORT_DES = SystemConfigBean.SERVER_PORT_DESC;*/

    private static final String CONFIG_UPRATE_ID = SystemConfigBean.SERVER_UPRATE_KEY;
    private static final String CONFIG_UPRATE_DES = SystemConfigBean.SERVER_UPRATE_DESC;

    private static final String CONFIG_REFRESH_ID = SystemConfigBean.SERVER_REFRESH_KEY;
    private static final String CONFIG_REFRESH_DES = SystemConfigBean.SERVER_REFRESH_DESC;

    private static final String CONFIG_RADIUS_ID = SystemConfigBean.SERVER_RADIUS_KEY;
    private static final String CONFIG_RADIUS_DES = SystemConfigBean.SERVER_RADIUS_DESC;

    private static final String CONFIG_RADIUS_DEVICE_ID = SystemConfigBean.SERVER_RADIUS_DEVICE_KEY;
    private static final String CONFIG_RADIUS_DEVICE_DES = SystemConfigBean.SERVER_RADIUS_DEVICE_DESC;

    private static final String CONFIG_UPRATE_CAR_ID = SystemConfigBean.SERVER_UPRATE_CAR_KEY;
    private static final String CONFIG_UPRATE_CAR_DES = SystemConfigBean.SERVER_UPRATE_CAR_DESC;

    private static final String CONFIG_RADIUS_CAR_ID = SystemConfigBean.SERVER_RADIUS_CAR_KEY;
    private static final String CONFIG_RADIUS_CAR_DES = SystemConfigBean.SERVER_RADIUS_CAR_DESC;

    private static final String CONFIG_BUILD_RANGE_ID = SystemConfigBean.SERVER_BUILD_RANGE_KEY;
    private static final String CONFIG_BUILD_RANGE_DES = SystemConfigBean.SERVER_BUILD_RANGE_DESC;

    private static final String CONFIG_MAX_SPEED_ID = SystemConfigBean.SERVER_MAX_SPEED_KEY;
    private static final String CONFIG_MAX_SPEED_DES = SystemConfigBean.SERVER_MAX_SPPED_DESC;

    private static final String CONFIG_MAX_SPEED_CAR_ID = SystemConfigBean.SERVER_MAX_SPEED_CAR_KEY;
    private static final String CONFIG_MAX_SPEED_CAR_DES = SystemConfigBean.SERVER_MAX_SPPED_CAR_DESC;

    private static final String CONFIG_MAX_GPS_PRECISION_ID = SystemConfigBean.SERVER_MAX_GPS_PRECISION_KEY;
    private static final String CONFIG_MAX_GPS_PRECISION_DES = SystemConfigBean.SERVER_MAX_GPS_PRECISION_DESC;

    private static final String CONFIG_MAX_GPS_SPEED_ID = SystemConfigBean.SERVER_MAX_GPS_SPEED_KEY;
    private static final String CONFIG_MAX_GPS_SPEED_DES = SystemConfigBean.SERVER_MAX_GPS_SPEED_DESC;

    public static final String CONFIG_PHOTO_WATERMARK_ID = SystemConfigBean.SERVER_PHOTO_WATERMARK_KEY;
    public static final String CONFIG_PHOTO_WATERMARK_DESC = SystemConfigBean.SERVER_PHOTO_WATERMARK_DESC;

    public static final String CONFIG_MAP_SERVER_ID = SystemConfigBean.SERVER_MAP_SERVER_KEY;
    public static final String CONFIG_MAP_SERVER_DESC = SystemConfigBean.SERVER_MAP_SERVER_DESC;

    private static SystemConfigBean systemConfigBean;           //系统使用的接口地址，可能是主系统IP也可能是灾备系统的IP地址
    private static SystemConfigBean systemConfigMapServer;      //系统使用的地图服务地址，可能是主系统的IP也可能是灾备系统的IP地址
    private static SystemConfigBean systemConfigUprate;
    private static SystemConfigBean systemConfigRefresh;        //实时监控刷新频率
    private static SystemConfigBean systemConfigRadius;         //到位半径
    private static SystemConfigBean systemConfigRadiusDevice;    //设备检修到位半径
    private static SystemConfigBean systemConfigUprateCar;
    private static SystemConfigBean systemConfigRadiusCar;
    private static SystemConfigBean systemConfigBuildRange;
    private static SystemConfigBean systemConfigMaxSpeed;
    private static SystemConfigBean systemConfigMaxSpeedCar;
    private static SystemConfigBean systemConfigMaxGpsPrecision;
    private static SystemConfigBean systemConfigMaxGpsSpeed;
    private static SystemConfigBean systemConfigPhotoWatermark;


    public static SystemConfigBean getSystemConfigBean() {
        return systemConfigBean;
    }

    public static SystemConfigBean getSystemConfigUprate() {
        return systemConfigUprate;
    }

    public static SystemConfigBean getSystemConfigRefresh() {
        return systemConfigRefresh;
    }

    public static SystemConfigBean getSystemConfigRadius() {
        return systemConfigRadius;
    }

    public static SystemConfigBean getSystemConfigRadiusDevice() {
        return systemConfigRadiusDevice;
    }

    public static SystemConfigBean getSystemConfigUprateCar() {
        return systemConfigUprateCar;
    }

    public static SystemConfigBean getSystemConfigRadiusCar() {
        return systemConfigRadiusCar;
    }

    public static SystemConfigBean getSystemConfigBuildRange() {
        return systemConfigBuildRange;
    }

    public static SystemConfigBean getSystemConfigMaxSpeed() {
        return systemConfigMaxSpeed;
    }

    public static SystemConfigBean getSystemConfigMaxSpeedCar() {
        return systemConfigMaxSpeedCar;
    }

    public static SystemConfigBean getSystemConfigMaxGpsPrecision() { return systemConfigMaxGpsPrecision; }

    public static SystemConfigBean getSystemConfigMaxGpsSpeed() { return systemConfigMaxGpsSpeed; }

    public static SystemConfigBean getSystemConfigPhotoWatermark() { return systemConfigPhotoWatermark; }

    public static SystemConfigBean getSystemConfigMapServer() { return systemConfigMapServer; }

    public static int getDeviceWidth() {
        return deviceWidth;
    }

    public static int getDeviceHeight() {
        return deviceHeight;
    }

    public static float getDensity() {
        return density;
    }

    public static int getDeviceDpi() {
        return deviceDpi;
    }

    public String getDevieImei() {
        if (imei == null || imei.isEmpty())
            getAndroidId();
        return imei;
    }

    public void setImei(String imei) {
        this.imei = imei;
        SharePreUtil.setIMEI(this, imei);
    }

    public static List<String> getImeisList(){
        return imeisList;
    }

    public static String getAndroid_version(){
        return android_version;
    }

    public static int getAppVersionCode() {
        return app_version_code;
    }

    public static String getAppVersionName() {
        return app_version_name;
    }

    public static boolean isAppMustUpdate() {
        return isAppMustUpdate;
    }

    public static void setIsAppMustUpdate(boolean isAppMustUpdate) {
        BaseApp.isAppMustUpdate = isAppMustUpdate;
    }

    public static int getSignState() {
        return mSignState;
    }

    public static void setSignState(int signState) {
        mSignState = signState;
    }

    public static boolean isHasAlertNoticeOff() {
        return bHasAlertNoticeOff;
    }

    public static void setHasAlertNoticeOff(boolean bHasAlertNoticeOff) {
        BaseApp.bHasAlertNoticeOff = bHasAlertNoticeOff;
    }

    public static boolean isNetworkConnected(){
        return NetworkStatus.isNetworkConnected(getInstance());
    }

    public static boolean isInternetReachable(){
        boolean isNetConnect = isNetworkConnected();
        if (isNetConnect){
            return NetworkStatus.isInternetReachable();
        }else
            return false;
    }

    public static Location mLocation;
    public static boolean isReady = true;

    private static boolean isAppMustUpdate = false;

    private static int mSignState = -1;

    private boolean carMode = false;

    private int gpsWakeTime = GPS_WAKE_TIME;

    private int gpsStatusTime = GPS_UPDATE_STATUS_TIME;

    private static final int GPS_WAKE_TIME = 10 * 1000; //唤醒时间间隔(ms)

    private static final int GPS_CAR_WAKE_TIME = 5 * 1000; //唤醒时间间隔(ms)

    private static final int GPS_UPDATE_STATUS_TIME = 60 * 1000; //唤醒时间间隔(ms)

    private static final int MONITOR_REFRESH_TIME = 20 * 1000; //实时监控刷新时间间隔(ms)

    private static final int POINT_CHECK_DEFAULT_RADIUS = 20; //到位检测半径 (m)

    private static final int POINT_CHECK_DEFAULT_RADIUS_DEVICE = 50; //设备到位检测半径 (m)

    private static final int POINT_CHECK_DEFAULT_RADIUS_CAR = 20; //到位检测半径 (m)

    private static final int POINT_CHECK_DEFAULT_SPEED = 10; //人巡最高时速 (km/h)

    private static final int POINT_CHECK_DEFAULT_SPEED_CAR = 40; //车巡最高时速 (km/h)

    private static final int POINT_CHECK_DEFAULT_BUILD_RANGE = 50; //工地监护检测半径 (m)

    private static final int POINT_CHECK_DEFAULT_GPS_PRECISION = 200; //轨迹最大精度 (m)

    private static final int POINT_CHECK_MAX_GPS_SPEED = 100;    //判断漂移点的最大时速 （km/h）

    private int monitorRefreshTime = MONITOR_REFRESH_TIME;

    private int pointCheckRadius = POINT_CHECK_DEFAULT_RADIUS;

    private int pointCheckRadiusDevice = POINT_CHECK_DEFAULT_RADIUS_DEVICE;

    private int pointCheckRadiusCar = POINT_CHECK_DEFAULT_RADIUS_CAR;

    private int buildRangeRadius = POINT_CHECK_DEFAULT_BUILD_RANGE;

    private int pointMaxSpeed = POINT_CHECK_DEFAULT_SPEED;

    private int pointMaxSpeedCar = POINT_CHECK_DEFAULT_SPEED_CAR;

    private int pointCheckPrecison = POINT_CHECK_DEFAULT_GPS_PRECISION;

    private int pointMaxGpsSpeed = POINT_CHECK_MAX_GPS_SPEED;

    private int isPhotoWatermark = 1;       //图片水印(0:是,1:否)

    private static final float DEFAULT_SYSTEM_FONT_SCALE_BIG = 1.12f;

    private boolean bUseBigFont = false;

    private boolean bGpsNotifyOpen = false;

    private boolean bGpsVibrateOn = false;

    private boolean bKeepScreenOn = false;

    private boolean bKeepScreenWakeup = false;

    private int iKeepScreenWakeupTime = 0;

    private int iGpsVibratePeriodTime = 0;

    private boolean bPlanLineRenderAll = true;

    public static void setIpAddrFromConfig(){
        String ipAddr = NetRequestURL.SERVER_ADDR_EXTERNAL;
        String mapAddr = NetRequestURL.SERVER_ADDR_EXTERNAL;
        if (systemConfigBean != null)
            ipAddr = systemConfigBean.getValue();

        if (systemConfigMapServer != null)
            mapAddr = systemConfigMapServer.getValue();

        NetRequestURL.HTTPHEAD = ipAddr;
        NetRequestURL.HTTP_MAP = mapAddr;
    }

    public static void setIpAddrToConfig(String ipAddr, String map_addr, String back_api){
        systemConfigBean.setCode(CONFIG_IP_ADDR_ID);
        systemConfigBean.setDesc(CONFIG_IP_ADDR_DES);
        systemConfigBean.setValue(ipAddr);

        DBDaoHelper dbDaoHelper = DBDaoHelper.getInstance();
        dbDaoHelper.insertOrUpdateSysConfig(systemConfigBean);

        systemConfigMapServer.setCode(CONFIG_MAP_SERVER_ID);
        systemConfigMapServer.setDesc(CONFIG_MAP_SERVER_DESC);
        systemConfigMapServer.setValue(map_addr);

        dbDaoHelper.insertOrUpdateSysConfig(systemConfigMapServer);

        setIpAddrFromConfig();
    }

    public void setUprateRaidusToConfig(ServerParamConfigBean paramConfigBean){
        if (paramConfigBean == null)
            return;

        DBDaoHelper dbDaoHelper = DBDaoHelper.getInstance();
        String serverIp = paramConfigBean.getServerIp();
        if (serverIp != null && !serverIp.isEmpty()){
            systemConfigBean.setCode(CONFIG_IP_ADDR_ID);
            systemConfigBean.setDesc(CONFIG_IP_ADDR_DES);
            systemConfigBean.setValue(serverIp);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigBean);
        }

        String uprate = paramConfigBean.getUploadRate();
        if (uprate != null && !uprate.isEmpty()){
            systemConfigUprate.setCode(CONFIG_UPRATE_ID);
            systemConfigUprate.setDesc(CONFIG_UPRATE_DES);
            systemConfigUprate.setValue(uprate);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigUprate);
        }

        String refresh = paramConfigBean.getRefreshInternal();
        if (refresh != null && !refresh.isEmpty()){
            systemConfigRefresh.setCode(CONFIG_REFRESH_ID);
            systemConfigRefresh.setDesc(CONFIG_REFRESH_DES);
            systemConfigRefresh.setValue(refresh);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigRefresh);
        }

        String radius = paramConfigBean.getMinDistanceInPlace();
        if (radius != null && !radius.isEmpty()){
            systemConfigRadius.setCode(CONFIG_RADIUS_ID);
            systemConfigRadius.setDesc(CONFIG_RADIUS_DES);
            systemConfigRadius.setValue(radius);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigRadius);
        }

        String radius_device = paramConfigBean.getMinDistanceInDevice();
        if (radius_device != null && !radius_device.isEmpty()){
            systemConfigRadiusDevice.setCode(CONFIG_RADIUS_DEVICE_ID);
            systemConfigRadiusDevice.setDesc(CONFIG_RADIUS_DEVICE_DES);
            systemConfigRadiusDevice.setValue(radius_device);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigRadiusDevice);
        }

        String uprate_car = paramConfigBean.getCarRefreshInternal();
        if (uprate_car != null && !uprate_car.isEmpty()){
            systemConfigUprateCar.setCode(CONFIG_UPRATE_CAR_ID);
            systemConfigUprateCar.setDesc(CONFIG_UPRATE_CAR_DES);
            systemConfigUprateCar.setValue(uprate_car);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigUprateCar);
        }

        String radius_car = paramConfigBean.getCarMinDistanceInPlace();
        if (radius_car != null && !radius_car.isEmpty()){
            systemConfigRadiusCar.setCode(CONFIG_RADIUS_CAR_ID);
            systemConfigRadiusCar.setDesc(CONFIG_RADIUS_CAR_DES);
            systemConfigRadiusCar.setValue(radius_car);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigRadiusCar);
        }

        String speed = paramConfigBean.getMaxSpeed();
        if (speed != null && !speed.isEmpty()){
            systemConfigMaxSpeed.setCode(CONFIG_MAX_SPEED_ID);
            systemConfigMaxSpeed.setDesc(CONFIG_MAX_SPEED_DES);
            systemConfigMaxSpeed.setValue(speed);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMaxSpeed);
        }

        String car_speed = paramConfigBean.getCarMaxSpeed();
        if (car_speed != null && !car_speed.isEmpty()){
            systemConfigMaxSpeedCar.setCode(CONFIG_MAX_SPEED_CAR_ID);
            systemConfigMaxSpeedCar.setDesc(CONFIG_MAX_SPEED_CAR_DES);
            systemConfigMaxSpeedCar.setValue(car_speed);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMaxSpeedCar);
        }

//        String build_range = paramConfigBean.getBuildRange();
//        if (build_range != null && !build_range.isEmpty()){
//            systemConfigBuildRange.setCode(CONFIG_BUILD_RANGE_ID);
//            systemConfigBuildRange.setDesc(CONFIG_BUILD_RANGE_DES);
//            systemConfigBuildRange.setValue(build_range);
//
//            dbDaoHelper.insertOrUpdateSysConfig(systemConfigBuildRange);
//        }

        String precision = paramConfigBean.getTrackMaxAccuracy();
        if (precision != null && !precision.isEmpty()){
            systemConfigMaxGpsPrecision.setCode(CONFIG_MAX_GPS_PRECISION_ID);
            systemConfigMaxGpsPrecision.setDesc(CONFIG_MAX_GPS_PRECISION_DES);
            systemConfigMaxGpsPrecision.setValue(precision);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMaxGpsPrecision);
        }

        String max_speed = paramConfigBean.getTrackMaxSpeed();
        if (max_speed != null && !max_speed.isEmpty()){
            systemConfigMaxGpsSpeed.setCode(CONFIG_MAX_GPS_SPEED_ID);
            systemConfigMaxGpsSpeed.setDesc(CONFIG_MAX_GPS_SPEED_DES);
            systemConfigMaxGpsSpeed.setValue(max_speed);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMaxGpsSpeed);
        }

        String watermark = paramConfigBean.getImageWatermark();
        if (watermark != null && !watermark.isEmpty()){
            systemConfigPhotoWatermark.setCode(CONFIG_PHOTO_WATERMARK_ID);
            systemConfigPhotoWatermark.setDesc(CONFIG_PHOTO_WATERMARK_DESC);
            systemConfigPhotoWatermark.setValue(watermark);

            dbDaoHelper.insertOrUpdateSysConfig(systemConfigPhotoWatermark);
        }

        setUprateRaidusFromConfig();
    }

    public void setUprateRaidusFromConfig(){
        int wakeTime = GPS_WAKE_TIME;
        int refreshTime = MONITOR_REFRESH_TIME;
        int checkRadius = POINT_CHECK_DEFAULT_RADIUS;
        int checkRadiusDevice = POINT_CHECK_DEFAULT_RADIUS_DEVICE;
        int checkRadiusCar = POINT_CHECK_DEFAULT_RADIUS_CAR;
        int buildRange = POINT_CHECK_DEFAULT_BUILD_RANGE;
        int maxSpeed = POINT_CHECK_DEFAULT_SPEED;
        int maxSpeedCar = POINT_CHECK_DEFAULT_SPEED_CAR;
        int maxPrecision = POINT_CHECK_DEFAULT_GPS_PRECISION;
        int maxGpsSpeed = POINT_CHECK_MAX_GPS_SPEED;
        int photoWatermark = 1;
        boolean isCarMode = BaseApp.getInstance().isCarMode();
        if (isCarMode){
            wakeTime = GPS_CAR_WAKE_TIME;
            if (systemConfigUprateCar != null){
                String strWakeTime = systemConfigUprateCar.getValue();
                if (strWakeTime != null && !strWakeTime.isEmpty()){
                    wakeTime = Integer.parseInt(strWakeTime) * 1000;
                }
            }
        }else{
            if (systemConfigUprate != null){
                String strWakeTime = systemConfigUprate.getValue();
                if (strWakeTime != null && !strWakeTime.isEmpty()){
                    wakeTime = Integer.parseInt(strWakeTime) * 1000;
                }
            }
        }

        if (systemConfigRefresh != null){
            String strRefresh = systemConfigRefresh.getValue();
            if (strRefresh != null && !strRefresh.isEmpty()){
                refreshTime = Integer.parseInt(strRefresh) * 1000;
            }
        }

        if (systemConfigRadius != null){
            String strRadius = systemConfigRadius.getValue();
            if (strRadius != null && !strRadius.isEmpty()){
                checkRadius = Integer.parseInt(strRadius);
            }
        }

        if (systemConfigRadiusDevice != null) {
            String strRadius = systemConfigRadiusDevice.getValue();
            if (strRadius != null && !strRadius.isEmpty()){
                checkRadiusDevice = Integer.parseInt(strRadius);
            }
        }

        if (systemConfigMaxSpeed != null){
            String strSpeed = systemConfigMaxSpeed.getValue();
            if (strSpeed != null && !strSpeed.isEmpty()){
                maxSpeed = Integer.parseInt(strSpeed);
            }
        }

        if (systemConfigRadiusCar != null){
            String strRadius = systemConfigRadiusCar.getValue();
            if (strRadius != null && !strRadius.isEmpty()){
                checkRadiusCar = Integer.parseInt(strRadius);
            }
        }

        if (systemConfigMaxSpeedCar != null){
            String strSpeed = systemConfigMaxSpeedCar.getValue();
            if (strSpeed != null && !strSpeed.isEmpty()){
                maxSpeedCar = Integer.parseInt(strSpeed);
            }
        }

        if (systemConfigBuildRange != null){
            String strRadius = systemConfigBuildRange.getValue();
            if (strRadius != null && !strRadius.isEmpty()){
                buildRange = Integer.parseInt(strRadius);
            }
        }

        if (systemConfigMaxGpsPrecision != null){
            String strPrecision = systemConfigMaxGpsPrecision.getValue();
            if (strPrecision != null && !strPrecision.isEmpty()){
                maxPrecision = Integer.parseInt(strPrecision);
            }
        }

        if (systemConfigMaxGpsSpeed != null){
            String strGpsSpeed = systemConfigMaxGpsSpeed.getValue();
            if (strGpsSpeed != null && !strGpsSpeed.isEmpty()){
                maxGpsSpeed = Integer.parseInt(strGpsSpeed);
            }
        }

        if (systemConfigPhotoWatermark != null){
            String strWatermark = systemConfigPhotoWatermark.getValue();
            if (strWatermark != null && !strWatermark.isEmpty()){
                photoWatermark = Integer.parseInt(strWatermark);
            }
        }

        gpsWakeTime = wakeTime;
        monitorRefreshTime = refreshTime;
        pointCheckRadius = checkRadius;
        pointCheckRadiusDevice = checkRadiusDevice;
        pointMaxSpeed = maxSpeed;
        pointCheckRadiusCar = checkRadiusCar;
        pointMaxSpeedCar = maxSpeedCar;
        buildRangeRadius = buildRange;
        pointCheckPrecison = maxPrecision;
        pointMaxGpsSpeed = maxGpsSpeed;
        isPhotoWatermark = photoWatermark;

        GpsTool.getInstance().updateCheckScale();
    }

    public static int dip2px(float dipValue) {
        final float scale = density;
        return (int) (dipValue * scale + 0.5f);
    }

    public static int px2dip(float pxValue) {
        final float scale = density;
        return (int) (pxValue / scale + 0.5f);
    }

    public static synchronized RequestQueue getRequestQueue(){
        if (mRequestQueue == null)
            mRequestQueue = Volley.newRequestQueue(getInstance().getApplicationContext());
        return mRequestQueue;
    }

    public static  <T> void addRequest(String tag, Request<T> request){
        RequestQueue requestQueue = getRequestQueue();
        request.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        request.setRetryPolicy(new DefaultRetryPolicy(DEFAULT_TIMEOUT_MS,
                DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        requestQueue.add(request);
        Log.d(tag, request.getUrl());
    }

    public static  <T> void addRequest(String tag, Request<T> request, int timeout, int retry, float blackoff){
        RequestQueue requestQueue = getRequestQueue();
        request.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        request.setRetryPolicy(new DefaultRetryPolicy(timeout, retry, blackoff));
        requestQueue.add(request);
        Log.d(tag, request.getUrl());
    }

    public static void cancelRequest(String tag){
        if (mRequestQueue != null)
            mRequestQueue.cancelAll(tag);
    }

    public static synchronized RequestQueue getMultiStatckRequestQueue(){
        if (mMultiStatckRequestQueue == null)
            mMultiStatckRequestQueue = Volley.newRequestQueue(getInstance().getApplicationContext(), new MultiPartStack());
        return mMultiStatckRequestQueue;
    }

    public static <T> void addMultiStatckRequest(String tag, Request<T> request){
        RequestQueue requestQueue = getMultiStatckRequestQueue();
        request.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        request.setRetryPolicy(new DefaultRetryPolicy(UPLOAD_FILE_TIMEOUT_MS,
                DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        requestQueue.add(request);
        Log.d(tag, request.getUrl());
    }

    public static <T> void addMultiStatckRequest(String tag, Request<T> request, int timeout, int retry, float blackoff){
        RequestQueue requestQueue = getMultiStatckRequestQueue();
        request.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        request.setRetryPolicy(new DefaultRetryPolicy(timeout, retry, blackoff));
        requestQueue.add(request);
        Log.d(tag, request.getUrl());
    }

    public static void cancelMultiRequest(String tag){
        if (mMultiStatckRequestQueue != null){
            mMultiStatckRequestQueue.cancelAll(tag);
        }
    }

    public static synchronized RequestQueue getStreamRequestQueue(){
        if (mStreamRequestQueue == null)
            mStreamRequestQueue = Volley.newRequestQueue(getInstance().getApplicationContext(), new HurlStack());
        return mStreamRequestQueue;
    }

    public static <T> void addStreamRequest(String tag, Request<T> request){
        RequestQueue requestQueue = getStreamRequestQueue();
        request.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        request.setRetryPolicy(new DefaultRetryPolicy(UPLOAD_FILE_TIMEOUT_MS,
                DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
        requestQueue.add(request);
        Log.d(tag, request.getUrl());
    }

    public static <T> void addStreamRequest(String tag, Request<T> request, int timeout, int retry, float blackoff){
        RequestQueue requestQueue = getStreamRequestQueue();
        request.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
        request.setRetryPolicy(new DefaultRetryPolicy(timeout, retry, blackoff));
        requestQueue.add(request);
    }

    public static void cancelStreamRequest(String tag){
        if (mStreamRequestQueue != null){
            mStreamRequestQueue.cancelAll(tag);
        }
    }

    public static void cancelAllRequest(String tag){
        cancelRequest(tag);
        cancelMultiRequest(tag);
        cancelStreamRequest(tag);
    }

    public boolean isCarMode() {
        return carMode;
    }

    public void setCarMode(boolean carMode) {
        this.carMode = carMode;
        SharePreUtil.setCarMode(this, carMode);
        setUprateRaidusFromConfig();
        //restartGpsService();
        restartAmapService();
    }

    public String getCarNo(){
        return SharePreUtil.getCarNo(this);
    }

    public void setCarNo(String carNo){
        SharePreUtil.setCarNo(this, carNo);
    }

    public boolean isUseBigFont(){
        return bUseBigFont;
    }

    public static final int DELAYED_EXIT_SECOND = 2000;
    public void setUseBigFont(boolean use){
        bUseBigFont = use;
        SharePreUtil.setBigFont(this, use);
        exitAppDelayed(DELAYED_EXIT_SECOND);
        //restartAppDelayed(DELAYED_EXIT_SECOND);
/*        // 退出程序
        restartApp();*/
    }

    public boolean isGpsNotifyOpen() {
        return bGpsNotifyOpen;
    }

    public void setGpsNotifyOpen(boolean open) {
        this.bGpsNotifyOpen = open;
        SharePreUtil.setGpsNotifyOpen(this, open);
    }

    public void getGpsNotifyOpen(){
        bGpsNotifyOpen = SharePreUtil.getGpsNotifyOpen(this);
    }

    public boolean isGpsVibrateOn() {
        return bGpsVibrateOn;
    }

    public void setGpsVibrateOn(boolean on, int times) {
        this.bGpsVibrateOn = on;
        SharePreUtil.setGpsVibrateOn(this, on, times);
        if (on){
            iGpsVibratePeriodTime = times;
            GpsTool.getInstance().updateVibratePeriod();
        }
    }

    public int getiGpsVibratePeriodTime() { return iGpsVibratePeriodTime; }

    public void getGpsVibrateOn(){
        bGpsVibrateOn = SharePreUtil.getGpsVibrateOn(this);
        iGpsVibratePeriodTime = SharePreUtil.getGpsVibratePeriod(this);
    }

    public boolean isbKeepScreenOn() {
        return bKeepScreenOn;
    }

    public boolean isbKeepScreenWakeup() { return  bKeepScreenWakeup; }

    public int getKeepScreenWakeupTime() { return  iKeepScreenWakeupTime; }

    public void setKeepScreenOnMode(boolean on) {
        SharePreUtil.setKeepScreenOnMode(this, on);
        if (bKeepScreenOn != on){
            //restartGpsService();
            restartAmapService();
        }
        this.bKeepScreenOn = on;
    }

    public void getKeepScreenOnMode(){
        bKeepScreenOn = SharePreUtil.getKeepScreenOnMode(this);
    }

    public void setKeepScreenWakeupMode(boolean on, int time) {
        SharePreUtil.setKeepScreenWakeupMode(this, on, time);
        if (on){
            iKeepScreenWakeupTime = time;
        }
        if (bKeepScreenWakeup!= on){
            //restartGpsService();
            restartAmapService();
        }
        this.bKeepScreenWakeup = on;
    }

    public void getKeepScreenWakeup(){
        bKeepScreenWakeup = SharePreUtil.getKeepScreenWakeupMode(this);
        iKeepScreenWakeupTime = SharePreUtil.getKeepScreenWakeupTime(this);
    }

    public boolean isPlanLineRenderAll() {
        return bPlanLineRenderAll;
    }

    public void setPlanLineRenderAll(boolean all) {
        this.bPlanLineRenderAll = all;
        SharePreUtil.setPlanLineRenderAll(this, all);
    }

    public void getPlanLineRenderAll(){
        this.bPlanLineRenderAll = SharePreUtil.getPlanLineRenderAll(this);
    }

    public void getSharedPreConfig(){
        /*获取车载模式的本地配置：是否开启车载*/
        getSavedCarMode();

        /*获取gps通知的本地配置：是否实时在页面上显示gps坐标*/
        getGpsNotifyOpen();

        /*是否开启GPS轨迹提示震动*/
        getGpsVibrateOn();

        /*获取巡检线是否渲染所有，包括完成和未完成*/
        getPlanLineRenderAll();

        /*获取常亮屏的本地配置：是否开启常亮屏模式，默认为是*/
        getKeepScreenOnMode();

        /*获取屏幕唤醒的本地配置：是否开启唤醒模式，默认为否*/
        getKeepScreenWakeup();
    }

    private void getSHA1Info(){
        String sha1 = sHA1(this);
        Log.e(TAG, "获取到SHA1:" + sha1 + " .\n");
    }

    /**
    * Android 7.0 系统解决拍照的问题
    * */
    private void setFileExposure() {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
            StrictMode.setVmPolicy(builder.build());
            builder.detectFileUriExposure();
        }
    }

    /*删除之前下载的安装包*/
    private void removeApkPackage(){
        boolean isRemove = SharePreUtil.getRemoveApkPackage(this);
        if (isRemove){
            String apkPath = SharePreUtil.getApkPackagePath(this);
            if (apkPath != null && !apkPath.isEmpty()){
                File apkFile = new File(apkPath);
                if (apkFile != null && apkFile.exists() && apkFile.isFile()) {
                    apkFile.delete();
                }
            }
        }
    }

    public static class ConnectType{
        public static final int CONNECT_NETWORK_CONNECTED = 0;
        public static final int CONNECT_NETWORK_DISCONNECTED = 1;
        public static final int CONNECT_SERVER_CONNECTED = 2;
        public static final int CONNECT_SERVER_DISCONNECTED = 3;
    }

    private void initConnectHintDialog(Context context){
        connectHintDialog = new ConnectHintDialog(context);
    }

    public void showConnectHintDialog(Context context, int connectType){
        initConnectHintDialog(context);

        if (CheckUtil.isForeground(this, getPackageName())){
            switch (connectType){
                case ConnectType.CONNECT_NETWORK_CONNECTED:
                    connectHintDialog.showNetworkConnected();
                    break;
                case ConnectType.CONNECT_NETWORK_DISCONNECTED:
                    connectHintDialog.showNetworkDisconnected();
                    break;
                case ConnectType.CONNECT_SERVER_CONNECTED:
                    connectHintDialog.showServerConnected();
                    break;
                case ConnectType.CONNECT_SERVER_DISCONNECTED:
                    connectHintDialog.showServerDisconnected();
                    break;
            }
        }
    }

    public boolean isAppForeground(){
        return CheckUtil.isForeground(this, getPackageName());
    }

    public int getGpsWakeTime(){
        return gpsWakeTime;
    }

    /*public void setGpsWakeTime(){
        if (carMode){
            gpsWakeTime = GPS_CAR_WAKE_TIME;
        }else {
            gpsWakeTime = GPS_WAKE_TIME;
        }
    }*/

    public int getGpsSatusTime(){
        return gpsStatusTime;
    }

    public int getRefreshInterval() {
        return monitorRefreshTime;
    }

    public int getPointCheckRadius(){
        return pointCheckRadius;
    }

    public int getPointCheckRadiusDevice(){
        return pointCheckRadiusDevice;
    }

    public int getPointCheckRadiusCar(){
        return pointCheckRadiusCar;
    }

    public int getBuildCheckRadius(){
        return buildRangeRadius;
    }

    public int getPointMaxSpeed() {
        return pointMaxSpeed;
    }

    public int getPointMaxSpeedCar() {
        return pointMaxSpeedCar;
    }

    public int getPointCheckPrecison() { return pointCheckPrecison; }

    public int getPointMaxGpsSpeed() { return pointMaxGpsSpeed; }

    public int getIsPhotoWatermark() { return isPhotoWatermark; }

    public void forceRestartApp(){
        SharePreUtil.setAppForceRestart(this, true);
        SharePreUtil.setLastSignState(this, mSignState);
        restartAppDelayed(DELAYED_EXIT_SECOND);
    }

/*    public void startBackgroundBaiduService(Context context) {
        boolean isServiceStarted = BaiduLocationUtils.getInstance().isLocationClientStarted();
        //boolean isServiceStarted = AppUtil.isServiceStarted(context, C.BAIDU_SERVICE_NAME);
        if (!isServiceStarted) {
            BaiduLocationUtils baiduLocUtils = BaiduLocationUtils.getInstance();
            baiduLocUtils.startBaiduService();
        }
    }

    public void stopBackgroundBaiduService(Context context) {
        boolean isServiceStarted = BaiduLocationUtils.getInstance().isLocationClientStarted();
        //boolean isServiceStarted =  CheckUtil.isServiceWorked(context, C.BAIDU_SERVICE_NAME);
        if (isServiceStarted){
            BaiduLocationUtils baiduLocUtils = BaiduLocationUtils.getInstance();
            baiduLocUtils.stopBDService(context);
        }

        *//*isServiceStarted = AppUtil.isServiceStarted(context, DService.class.getName());
        if (isServiceStarted) {
            Intent stopIntent = new Intent(context, DService.class);
            context.stopService(stopIntent);
        }*//*
    }*/

    public void startBackgroundAmapService(Context context) {
        boolean isServiceStarted = AmapLocationUtils.getInstance().isLocationClientStarted();
        //boolean isServiceStarted = AppUtil.isServiceStarted(context, C.AMAP_SERVICE_NAME);
        if (!isServiceStarted) {
            AmapLocationUtils amapLocationUtils = AmapLocationUtils.getInstance();
            amapLocationUtils.startAmapLocService();
        }
    }

    public void stopBackgroundAmapService(Context context) {
        boolean isServiceStarted = AmapLocationUtils.getInstance().isLocationClientStarted();
        //boolean isServiceStarted =  CheckUtil.isServiceWorked(context, C.AMAP_SERVICE_NAME);
        if (isServiceStarted){
            AmapLocationUtils amapLocationUtils = AmapLocationUtils.getInstance();
            amapLocationUtils.stopAmapLocService();
        }
    }

    public void startBackgroundAmapServiceForOnce(Context context) {
        //boolean isServiceStarted = AppUtil.isServiceStarted(context, C.AMAP_SERVICE_NAME);
        AmapLocationUtils amapLocationUtils = AmapLocationUtils.getInstance();
        amapLocationUtils.startAmapLocServiceForOnce();
    }

    public void stopBackgroundAmapServiceForOnce(Context context) {
        //boolean isServiceStarted = AppUtil.isServiceStarted(context, C.AMAP_SERVICE_NAME);
        AmapLocationUtils amapLocationUtils = AmapLocationUtils.getInstance();
        amapLocationUtils.stopAmapLocServiceForOnce();
    }


    public void startBackgroundOfflineWorkService(Context context) {
        boolean isServiceStarted = AppUtil.isServiceStarted(context, OfflineWorkerService.class.getName());
        if (!isServiceStarted) {
            Intent startIntent = new Intent(context, OfflineWorkerService.class);
            startService(startIntent);
        }
    }

    public void stopBackgroundOfflineWorkService(Context context) {
        boolean isServiceStarted =  AppUtil.isServiceStarted(context, OfflineWorkerService.class.getName());
        if (isServiceStarted){
            Intent stopIntent = new Intent(context, OfflineWorkerService.class);
            stopService(stopIntent);
        }
    }

    public void startAllBackgroundService(Context context) {
        /*boolean isServiceStarted = AppUtil.isServiceStarted(context, UploadGPSService.class.getName());
        if (!isServiceStarted) {
            Intent startIntent = new Intent(context, UploadGPSService.class);
            startService(startIntent);
        }*/
        stopBackgroundAmapServiceForOnce(context);

        boolean isServiceStarted = AppUtil.isServiceStarted(context, DeviceMonitorService.class.getName());
        if (!isServiceStarted) {
            Intent startIntent = new Intent(context, DeviceMonitorService.class);
            startService(startIntent);
        }

        if (C.bLogMapToolLocForBaiduArcgis_debug){
            startBackgroundAmapService(context);
            //startBackgroundBaiduService(context);
        }

        startBackgroundOfflineWorkService(context);
    }

    public void stopBackgroundService(Context context) {
        /*boolean isServiceStarted = AppUtil.isServiceStarted(context, UploadGPSService.class.getName());
        if (isServiceStarted) {
            Intent stopIntent = new Intent(context, UploadGPSService.class);
            stopService(stopIntent);
        }*/

        boolean isServiceStarted = AppUtil.isServiceStarted(context, DeviceMonitorService.class.getName());
        if (isServiceStarted) {
            Intent stopIntent = new Intent(context, DeviceMonitorService.class);
            stopService(stopIntent);
        }

        if (C.bLogMapToolLocForBaiduArcgis_debug){
            stopBackgroundAmapService(context);
            //stopBackgroundBaiduService(context);
        }
    }

    public void stopAllBackgroundService(Context context) {
        stopBackgroundService(context);
        stopBackgroundOfflineWorkService(context);
    }

    private void restartAmapService(){
        stopBackgroundAmapService(this);
        Handler handler = new Handler();
        handler.postDelayed(() -> startBackgroundAmapService(BaseApp.this), 1000);
    }

    private void restartGpsService(){
        boolean isServiceStarted = AppUtil.isServiceStarted(this, UploadGPSService.class.getName());
        if (isServiceStarted){
            final Intent startIntent = new Intent(this, UploadGPSService.class);
            stopService(startIntent);
            Handler handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    startService(startIntent);
                }
            }, 1000);
        }
    }

    public static String formatErrorMessage(int errorCode, String errMsg){
        String err = URLResponseCode.ErrorCode.getErrorMessage(errorCode);
        if (err == null || err.isEmpty()){
            err = errMsg;
        }
        return  err;
    }

    @Override
    protected void attachBaseContext(Context base) {
        super.attachBaseContext(base);
        MultiDex.install(this);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        singleton = this;

        //此处可初始化CrashHanlder:截获未处理异常日志，上传自己服务器
        CrashHandler crashHandler = CrashHandler.getInstance();
        //注册crashHandler
        crashHandler.init(getApplicationContext());

        // 获得当前设备的屏幕参数
        getDisplayParameters();

        // 获取当前设备的信息
        getSysInfo();

        // 获得当前手机的IMEI数据
//        getIMEIData();

        /*初始化数据*/
        init();
    }

    @Override
    public Resources getResources() {
        Resources resources = super.getResources();
        if (resources != null) {
            setUiBigFont(resources);
        }
        return resources;
    }

    private void init(){
        /*init location service*/
        /*locationService = new LocationService(getApplicationContext());
        SDKInitializer.initialize(getApplicationContext());//百度地图sdk初始化*/

        /*init ImageLoader*/
        initImageLoader();

        /*init OkHttpClient*/
        initOkHttpClient();

        /*设置闹铃用于Gps后台服务的唤醒操作*/
        //setAlarmForGpsService();
        /*读取本地配置信息*/
        getSharedPreConfig();

        /*删除之前下载的安装包*/
        removeApkPackage();

        /*初始化数据库*/
        initDataBase();

        getSHA1Info();

        setFileExposure();
    }

    private void initImageLoader(){
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
                this)
                /*.memoryCacheExtraOptions(300, 300)
                // max width, max height，即保存的每个缓存文件的最大长宽
                .discCacheExtraOptions(300, 300, null)*/
                // Can slow ImageLoader, use it carefully (Better don't use
                // it)/设置缓存的详细信息，最好不要设置这个
                .threadPoolSize(3)
                // 线程池内加载的数量
                .threadPriority(Thread.NORM_PRIORITY - 2)
                .denyCacheImageMultipleSizesInMemory()
                .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024))
                // You can pass your own memory cache
                // implementation/你可以通过自己的内存缓存实现
                .memoryCacheSize(2 * 1024 * 1024)
                .discCacheSize(50 * 1024 * 1024)
                .discCacheFileNameGenerator(new Md5FileNameGenerator())
                // 将保存的时候的URI名称用MD5 加密
                .tasksProcessingOrder(QueueProcessingType.LIFO)
                .discCacheFileCount(100)
                // 缓存的文件数量
                .discCache(
                        new UnlimitedDiscCache(new File(Environment
                                .getExternalStorageDirectory()
                                + "/route/images")))
                // 自定义缓存路径
                .defaultDisplayImageOptions(getDisplayOptions())
                .imageDownloader(
                        new BaseImageDownloader(this, 5 * 1000, 30 * 1000))
                .writeDebugLogs() // Remove for release app
                .build();// 开始构建
        ImageLoader.getInstance().init(config);
    }

    private DisplayImageOptions getDisplayOptions() {
        DisplayImageOptions options;
        options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.mipmap.transparent_bg) // 设置图片在下载期间显示的图片
                .showImageForEmptyUri(R.mipmap.transparent_bg)// 设置图片Uri为空或是错误的时候显示的图片
                .showImageOnFail(R.mipmap.transparent_bg) // 设置图片加载/解码过程中错误时候显示的图片
                .cacheInMemory(true)// 设置下载的图片是否缓存在内存中
                .cacheOnDisc(true)// 设置下载的图片是否缓存在SD卡中
                .considerExifParams(true) // 是否考虑JPEG图像EXIF参数（旋转，翻转）
                .imageScaleType(ImageScaleType.NONE)// 设置图片以如何的编码方式显示
                .bitmapConfig(Bitmap.Config.ARGB_8888)// 设置图片的解码类型//
                        // .delayBeforeLoading(int delayInMillis)//int
                        // delayInMillis为你设置的下载前的延迟时间
                        // 设置图片加入缓存前，对bitmap进行设置
                        // .preProcessor(BitmapProcessor preProcessor)
                .resetViewBeforeLoading(true)// 设置图片在下载前是否重置，复位
                .displayer(new RoundedBitmapDisplayer(20))// 是否设置为圆角，弧度为多少
                .displayer(new FadeInBitmapDisplayer(100))// 是否图片加载好后渐入的动画时间
                .build();// 构建完成
        return options;
    }

    public static DisplayImageOptions getDefaultDisplayOptions() {
        DisplayImageOptions.Builder builder = new DisplayImageOptions.Builder()
                .cacheInMemory(true)// 设置下载的图片是否缓存在内存中
                .cacheOnDisk(true)// 设置下载的图片是否缓存在SD卡中
                .considerExifParams(true) // 是否考虑JPEG图像EXIF参数（旋转，翻转）
                .bitmapConfig(Bitmap.Config.RGB_565)
                .imageScaleType(ImageScaleType.EXACTLY_STRETCHED);
        return builder.build();
    }

    public static DisplayImageOptions.Builder getDefaultDisplayOptionsBuilder() {
        DisplayImageOptions.Builder builder = new DisplayImageOptions.Builder()
                .cacheInMemory(true)// 设置下载的图片是否缓存在内存中
                .cacheOnDisk(true)// 设置下载的图片是否缓存在SD卡中
                .considerExifParams(true) // 是否考虑JPEG图像EXIF参数（旋转，翻转）
                .bitmapConfig(Bitmap.Config.RGB_565)
                .imageScaleType(ImageScaleType.EXACTLY_STRETCHED);
        return builder;
    }

    private void initOkHttpClient(){
        okHttpClient = new OkHttpClient.Builder().
                readTimeout(10, TimeUnit.SECONDS).
                writeTimeout(10, TimeUnit.SECONDS).
                connectTimeout(10, TimeUnit.SECONDS).
                build();
    }

    private void getDisplayParameters(){
        // 获得当前设备的屏幕参数
        DisplayMetrics dm = new DisplayMetrics();
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        wm.getDefaultDisplay().getMetrics(dm);
        int screenWidth = dm.widthPixels;
        int screenHeight = dm.heightPixels;
        deviceWidth = screenWidth;
        deviceHeight = screenHeight;
        density = dm.density;
        deviceDpi = dm.densityDpi;
    }

    private void setUiBigFont(Resources resources){
        // 获得当前设备的屏幕参数
        DisplayMetrics dm = new DisplayMetrics();
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        wm.getDefaultDisplay().getMetrics(dm);

        bUseBigFont = SharePreUtil.getBigFont(this);
        if (bUseBigFont){
            Configuration configuration = resources.getConfiguration();
            configuration.fontScale = DEFAULT_SYSTEM_FONT_SCALE_BIG;
            resources.updateConfiguration(configuration, dm);
        }
    }

    private void getSysInfo(){
        android_version = Build.VERSION.RELEASE;
        app_version_code = AppUtil.getLocalVersionCode(this);
        app_version_name = AppUtil.getLocalVersionName(this);
    }

    public void getAndroidId() {
        String android_id = Settings.System.getString(
                getContentResolver(), Settings.Secure.ANDROID_ID);
        imei = android_id;
    }

    @SuppressLint("MissingPermission")
    private void getIMEIData() {
        TelephonyManager manager = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE));
        String imei = manager.getDeviceId();
        if (imei == null || imei.isEmpty()) {
            imei = getImeiNew();
            BaseApp.imei = imei;
        }else {
            BaseApp.imei = imei;
        }

        //如果获取不到，最后再尝试从Shared Preference中读取
        if (imei == null || imei.isEmpty()) {
            imei = SharePreUtil.getIMEI(this);
            BaseApp.imei = imei;
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
            return;
        }

        int count = manager.getPhoneCount();
        if (imeisList == null) {
            imeisList = new ArrayList<>();
        }else {
            imeisList.clear();
        }
        if (count > 1){
            Class clazz = manager.getClass();
            try {
                Method getImei = clazz.getDeclaredMethod("getImei", int.class);
                String imei1 = (String) getImei.invoke(manager, 0);
                imeisList.add(imei1);
                String imei2 = (String) getImei.invoke(manager, 1);
                imeisList.add(imei2);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    @SuppressLint("MissingPermission")
    private String getImeiNew() {
        String imei = "";
        try {
            TelephonyManager manager = ((TelephonyManager) getSystemService(TELEPHONY_SERVICE));
            if (Build.VERSION.SDK_INT >= 26) {
                try {
                    Method method = manager.getClass().getMethod("getImei", new Class[0]);
                    method.setAccessible(true);
                    imei = (String) method.invoke(manager, new Object[0]);
                } catch (Exception e) {

                }
                if (imei.isEmpty()) {
                    imei = manager.getDeviceId();
                }
            }else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                imei = manager.getDeviceId(0);
            } else {
                imei = manager.getDeviceId();
            }
        }catch (Exception e) {

        }
        return imei;
    }

    public void initDataBase(){
        DBDaoHelper dbDaoHelper = DBDaoHelper.getInstance();
        dbDaoHelper.setupDatabase(this);

        systemConfigBean = dbDaoHelper.getSysConfigValue(CONFIG_IP_ADDR_ID);
        if (systemConfigBean == null){
            systemConfigBean = new SystemConfigBean();
            systemConfigBean.setCode(CONFIG_IP_ADDR_ID);
            systemConfigBean.setDesc(CONFIG_IP_ADDR_DES);
            systemConfigBean.setValue(NetRequestURL.SERVER_ADDR_EXTERNAL);
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigBean);
        }

        systemConfigMapServer = dbDaoHelper.getSysConfigValue(CONFIG_MAP_SERVER_ID);
        if (systemConfigMapServer == null){
            systemConfigMapServer = new SystemConfigBean();
            systemConfigMapServer.setCode(CONFIG_MAP_SERVER_ID);
            systemConfigMapServer.setDesc(CONFIG_MAP_SERVER_DESC);
            systemConfigMapServer.setValue(NetRequestURL.SERVER_ADDR_EXTERNAL);
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMapServer);
        }

        setIpAddrFromConfig();

        systemConfigUprate = dbDaoHelper.getSysConfigValue(CONFIG_UPRATE_ID);
        if (systemConfigUprate == null){
            systemConfigUprate = new SystemConfigBean();
            systemConfigUprate.setCode(CONFIG_UPRATE_ID);
            systemConfigUprate.setDesc(CONFIG_UPRATE_DES);
            systemConfigUprate.setValue(GPS_WAKE_TIME / 1000 + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigUprate);
        }

        systemConfigRefresh = dbDaoHelper.getSysConfigValue(CONFIG_REFRESH_ID);
        if (systemConfigRefresh == null){
            systemConfigRefresh = new SystemConfigBean();
            systemConfigRefresh.setCode(CONFIG_REFRESH_ID);
            systemConfigRefresh.setDesc(CONFIG_REFRESH_DES);
            systemConfigRefresh.setValue(MONITOR_REFRESH_TIME / 1000 + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigRefresh);
        }

        systemConfigRadius = dbDaoHelper.getSysConfigValue(CONFIG_RADIUS_ID);
        if (systemConfigRadius == null){
            systemConfigRadius = new SystemConfigBean();
            systemConfigRadius.setCode(CONFIG_RADIUS_ID);
            systemConfigRadius.setDesc(CONFIG_RADIUS_DES);
            systemConfigRadius.setValue(POINT_CHECK_DEFAULT_RADIUS + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigRadius);
        }

        systemConfigRadiusDevice = dbDaoHelper.getSysConfigValue(CONFIG_RADIUS_DEVICE_ID);
        if (systemConfigRadiusDevice == null){
            systemConfigRadiusDevice = new SystemConfigBean();
            systemConfigRadiusDevice.setCode(CONFIG_RADIUS_DEVICE_ID);
            systemConfigRadiusDevice.setDesc(CONFIG_RADIUS_DEVICE_DES);
            systemConfigRadiusDevice.setValue(POINT_CHECK_DEFAULT_RADIUS_DEVICE + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigRadiusDevice);
        }

        systemConfigUprateCar = dbDaoHelper.getSysConfigValue(CONFIG_UPRATE_CAR_ID);
        if (systemConfigUprateCar == null){
            systemConfigUprateCar = new SystemConfigBean();
            systemConfigUprateCar.setCode(CONFIG_UPRATE_CAR_ID);
            systemConfigUprateCar.setDesc(CONFIG_UPRATE_CAR_DES);
            systemConfigUprateCar.setValue(GPS_CAR_WAKE_TIME / 1000 + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigUprateCar);
        }

        systemConfigRadiusCar = dbDaoHelper.getSysConfigValue(CONFIG_RADIUS_CAR_ID);
        if (systemConfigRadiusCar == null){
            systemConfigRadiusCar = new SystemConfigBean();
            systemConfigRadiusCar.setCode(CONFIG_RADIUS_CAR_ID);
            systemConfigRadiusCar.setDesc(CONFIG_RADIUS_CAR_DES);
            systemConfigRadiusCar.setValue(POINT_CHECK_DEFAULT_RADIUS_CAR + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigRadiusCar);
        }

        systemConfigMaxSpeed = dbDaoHelper.getSysConfigValue(CONFIG_MAX_SPEED_ID);
        if (systemConfigMaxSpeed == null){
            systemConfigMaxSpeed = new SystemConfigBean();
            systemConfigMaxSpeed.setCode(CONFIG_MAX_SPEED_ID);
            systemConfigMaxSpeed.setDesc(CONFIG_MAX_SPEED_DES);
            systemConfigMaxSpeed.setValue(POINT_CHECK_DEFAULT_SPEED + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMaxSpeed);
        }

        systemConfigMaxSpeedCar = dbDaoHelper.getSysConfigValue(CONFIG_MAX_SPEED_CAR_ID);
        if (systemConfigMaxSpeedCar == null){
            systemConfigMaxSpeedCar = new SystemConfigBean();
            systemConfigMaxSpeedCar.setCode(CONFIG_MAX_SPEED_CAR_ID);
            systemConfigMaxSpeedCar.setDesc(CONFIG_MAX_SPEED_CAR_DES);
            systemConfigMaxSpeedCar.setValue(POINT_CHECK_DEFAULT_SPEED_CAR + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMaxSpeedCar);
        }

        systemConfigBuildRange = dbDaoHelper.getSysConfigValue(CONFIG_BUILD_RANGE_ID);
        if (systemConfigBuildRange == null){
            systemConfigBuildRange = new SystemConfigBean();
            systemConfigBuildRange.setCode(CONFIG_BUILD_RANGE_ID);
            systemConfigBuildRange.setDesc(CONFIG_BUILD_RANGE_DES);
            systemConfigBuildRange.setValue(POINT_CHECK_DEFAULT_BUILD_RANGE + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigBuildRange);
        }

        systemConfigMaxGpsPrecision = dbDaoHelper.getSysConfigValue(CONFIG_MAX_GPS_PRECISION_ID);
        if (systemConfigMaxGpsPrecision == null){
            systemConfigMaxGpsPrecision = new SystemConfigBean();
            systemConfigMaxGpsPrecision.setCode(CONFIG_MAX_GPS_PRECISION_ID);
            systemConfigMaxGpsPrecision.setDesc(CONFIG_MAX_GPS_PRECISION_DES);
            systemConfigMaxGpsPrecision.setValue(POINT_CHECK_DEFAULT_GPS_PRECISION + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMaxGpsPrecision);
        }

        systemConfigMaxGpsSpeed = dbDaoHelper.getSysConfigValue(CONFIG_MAX_GPS_SPEED_ID);
        if (systemConfigMaxGpsSpeed == null){
            systemConfigMaxGpsSpeed = new SystemConfigBean();
            systemConfigMaxGpsSpeed.setCode(CONFIG_MAX_GPS_SPEED_ID);
            systemConfigMaxGpsSpeed.setDesc(CONFIG_MAX_GPS_SPEED_DES);
            systemConfigMaxGpsSpeed.setValue(POINT_CHECK_MAX_GPS_SPEED + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigMaxGpsSpeed);
        }

        systemConfigPhotoWatermark = dbDaoHelper.getSysConfigValue(CONFIG_PHOTO_WATERMARK_ID);
        if (systemConfigPhotoWatermark == null){
            systemConfigPhotoWatermark = new SystemConfigBean();
            systemConfigPhotoWatermark.setCode(CONFIG_PHOTO_WATERMARK_ID);
            systemConfigPhotoWatermark.setDesc(CONFIG_PHOTO_WATERMARK_DESC);
            systemConfigPhotoWatermark.setValue(0 + "");
            dbDaoHelper.insertOrUpdateSysConfig(systemConfigPhotoWatermark);
        }

        setUprateRaidusFromConfig();
    }

    public void getSavedCarMode(){
        carMode = SharePreUtil.getCarMode(this);
    }

    public static BaseApp getInstance() {
        return singleton;
    }

    public UserBean getLoginUser() {
        if (loginUser == null){
            UserInfoTool userInfoTool = UserInfoTool.getInstance();
            userInfoTool.checkLogin(this);
        }
        return loginUser;
    }

    public void setLoginUser(UserBean loginUser) {
        this.loginUser = loginUser;
    }

    public String getToken() {
        UserBean userBean = getLoginUser();
        if (userBean != null && userBean.getToken() != null) {
            return userBean.getToken();
        }
        return "";
    }

    public String getUserId() {
        UserBean userBean = getLoginUser();
        if (userBean != null && userBean.getUserid() != null) {
            return userBean.getUserid();
        }
        return "";
    }

    public int getBatteryUsage(){
        int batteryHealth = 0;
        Intent intent = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
        if (intent != null){
            int level = intent.getIntExtra("level", 0);
            int scale = intent.getIntExtra("scale", 100);
            batteryHealth = level * 100 / scale;
        }
        return batteryHealth;
    }

    public static String sHA1(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(
                    context.getPackageName(), PackageManager.GET_SIGNATURES);
            byte[] cert = info.signatures[0].toByteArray();
            MessageDigest md = MessageDigest.getInstance("SHA1");
            byte[] publicKey = md.digest(cert);
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < publicKey.length; i++) {
                String appendString = Integer.toHexString(0xFF & publicKey[i])
                        .toUpperCase(Locale.US);
                if (appendString.length() == 1)
                    hexString.append("0");
                hexString.append(appendString);
                hexString.append(":");
            }
            String result = hexString.toString();
            return result.substring(0, result.length()-1);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * add Activity 添加Activity到栈
     */
    public void addActivity(Activity activity){
        if(activityStack ==null){
            activityStack =new Stack<Activity>();
        }
        activityStack.add(activity);
    }
    /**
     * get current Activity 获取当前Activity（栈中最后一个压入的）
     */
    public Activity currentActivity() {
        Activity activity = activityStack.lastElement();
        return activity;
    }
    /**
     * 结束当前Activity（栈中最后一个压入的）
     */
    public void finishActivity() {
        Activity activity = activityStack.lastElement();
        finishActivity(activity);
    }

    /**
     * 结束指定的Activity
     */
    public void finishActivity(Activity activity) {
        if (activity != null) {
            activityStack.remove(activity);
            activity.finish();
            activity = null;
        }
    }

    /**
     * 结束指定类名的Activity
     */
    public void finishActivity(Class<?> cls) {
        for (Activity activity : activityStack) {
            if (activity.getClass().equals(cls)) {
                finishActivity(activity);
            }
        }
    }

    /**
     * 结束所有Activity
     *
     */

    public void finishAllActivity() {
        for (int i = 0, size = activityStack.size(); i < size; i++) {
            if (null != activityStack.get(i)) {
                activityStack.get(i).finish();
            }
        }
        activityStack.clear();
    }

    /**
     * 退出应用程序
     */
    public void appExit() {
        if (AppUtil.isServiceStarted(BaseApp.getInstance(), DownloadService.class.getName())){
            stopService(new Intent(BaseApp.getInstance(), DownloadService.class));
        }
        try {
            finishAllActivity();
        } catch (Exception e) {
        }
    }

    public void exitApp() {
        // 停止后台服务
        stopAllBackgroundService(this);
        // 退出程序
        android.os.Process.killProcess(android.os.Process.myPid());
        System.exit(1);
    }

    public void exitAppDelayed(int delayed){
        // 停止后台服务
        stopAllBackgroundService(this);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                // 退出程序
                android.os.Process.killProcess(android.os.Process.myPid());
                System.exit(1);
            }
        }, delayed);
    }

    public void restartAppDelayed(int delay){
        Handler handler = new Handler(getMainLooper());
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                restartApp();
            }
        }, delay);
        exitApp();
    }

    public void restartApp(){
        Intent lauch = getBaseContext().getPackageManager().
                getLaunchIntentForPackage(getBaseContext().getPackageName());
        lauch.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(lauch);
    }
}
