package xn.update.service; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.Service; import android.content.Intent; import android.content.IntentFilter; import android.os.Build; import android.os.CountDownTimer; import android.os.IBinder; import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.NotificationCompat; import androidx.core.util.Pair; import androidx.work.ExistingPeriodicWorkPolicy; import androidx.work.PeriodicWorkRequest; import androidx.work.WorkManager; import com.blankj.utilcode.util.ActivityUtils; import com.blankj.utilcode.util.AppUtils; import com.blankj.utilcode.util.FileUtils; import com.blankj.utilcode.util.LogUtils; import com.blankj.utilcode.util.NetworkUtils; import com.blankj.utilcode.util.SPUtils; import com.blankj.utilcode.util.ThreadUtils; import com.hikvision.dmb.EthernetConfig; import com.hikvision.dmb.LauncherInfo; import com.hikvision.dmb.MemoryInfo; import com.hikvision.dmb.TimeSwitchConfig; import com.hikvision.dmb.display.InfoDisplayApi; import com.hikvision.dmb.network.InfoNetworkApi; import com.hikvision.dmb.system.InfoSystemApi; import com.hikvision.dmb.time.InfoTimeApi; import com.hikvision.dmb.util.InfoUtilApi; import com.hjq.permissions.OnPermissionCallback; import com.hjq.permissions.Permission; import com.hjq.permissions.XXPermissions; import com.lxj.xpopup.XPopup; import org.greenrobot.eventbus.EventBus; import org.json.JSONObject; import java.io.File; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import okhttp3.Response; import xn.update.R; import xn.update.Tool; import xn.update.constant.AppConstant; import xn.update.evnet.UpdateUiEvent; import xn.update.http.HttpTool; import xn.update.receiver.TimeTickReceiver; import xn.update.works.TaskWork; public class TaskService extends Service { private TimeTickReceiver timeTickReceiver; private final AtomicBoolean isUploading = new AtomicBoolean(false); private ScheduledExecutorService scheduler; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); scheduler = Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleWithFixedDelay(new Runnable() { @Override public void run() { if (!isUploading.compareAndSet(false, true)) { return; } ThreadUtils.executeByCached(new ThreadUtils.SimpleTask() { @Override public Object doInBackground() throws Throwable { Response response = HttpTool.INSTANCE.heartbeat(); LogUtils.d("发送心跳"); return null; } @Override public void onSuccess(Object result) { isUploading.set(false); } }); } }, 0, 2, TimeUnit.SECONDS); // 卸载老旧app Tool.INSTANCE.cmd("pm uninstall com.dlc.xn.eboard"); // 启动保活worker PeriodicWorkRequest taskRequest = new PeriodicWorkRequest.Builder(TaskWork.class, 15, TimeUnit.MINUTES).build(); WorkManager.getInstance(getApplicationContext()).enqueueUniquePeriodicWork("Task", ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE, taskRequest); // 自动更新应用 SPUtils.getInstance().put(AppConstant.AUTO_UPDATE, true); // 自动拉起主应用 SPUtils.getInstance().put(AppConstant.AUTO_MASTER, true); InfoSystemApi.openAdb(); InfoDisplayApi.setStatusBarEnable(false); InfoDisplayApi.setNavigationBarEnable(false); SPUtils.getInstance().put("isRoot", 0 == InfoUtilApi.getRoot()); SPUtils.getInstance().put("IP", InfoNetworkApi.getEthernetConfig().ipAddress); InfoUtilApi.enableProtection(AppUtils.getAppPackageName(), false); InfoSystemApi.setLauncherForced(AppUtils.getAppPackageName()); createNotificationChannel(); timeTickReceiver = new TimeTickReceiver(); // 监听分钟广播 registerReceiver(timeTickReceiver, new IntentFilter(Intent.ACTION_TIME_TICK)); Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.READ_EXTERNAL_STORAGE"); Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.WRITE_EXTERNAL_STORAGE"); Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.NOTIFICATION_SERVICE"); ThreadUtils.executeByCachedAtFixRate(new ThreadUtils.SimpleTask() { @Override public Boolean doInBackground() throws Throwable { if (null == ActivityUtils.getTopActivity()) { Tool.INSTANCE.stopApp(AppUtils.getAppPackageName()); Tool.INSTANCE.openApp(AppUtils.getAppPackageName()); } else { if (!XXPermissions.isGranted(ActivityUtils.getTopActivity(), Permission.READ_EXTERNAL_STORAGE) || !XXPermissions.isGranted(ActivityUtils.getTopActivity(), Permission.WRITE_EXTERNAL_STORAGE) || !XXPermissions.isGranted(ActivityUtils.getTopActivity(), Permission.NOTIFICATION_SERVICE) ) { Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.READ_EXTERNAL_STORAGE"); Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.WRITE_EXTERNAL_STORAGE"); Tool.INSTANCE.cmd("pm grant " + AppUtils.getAppPackageName() + " android.permission.NOTIFICATION_SERVICE"); } else { return true; } } return false; } @Override public void onSuccess(Boolean result) { requestPermission(); cancel(); } }, 1, 1, TimeUnit.SECONDS); } @Override public int onStartCommand(Intent intent, int flags, int startId) { LogUtils.d(getClass().getName(), "onStartCommand"); Notification notification = createNotification(); startForeground(1, notification); return START_REDELIVER_INTENT; } @Override public void onTaskRemoved(Intent rootIntent) { super.onTaskRemoved(rootIntent); LogUtils.d(getClass().getName(), "onTaskRemoved"); stopSelf(); } @Override public void onDestroy() { super.onDestroy(); if (null != scheduler) { scheduler.shutdown(); } if (null != timeTickReceiver) { unregisterReceiver(timeTickReceiver); timeTickReceiver = null; } LogUtils.d(getClass().getName(), "onDestroy"); } private void createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { int importance = NotificationManager.IMPORTANCE_DEFAULT; NotificationChannel channel = new NotificationChannel("task", "task", importance); NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } } private Notification createNotification() { NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "task") .setContentTitle("Task") .setContentText("Task is running") .setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(null) .setSilent(true) .setPriority(NotificationCompat.PRIORITY_DEFAULT); return builder.build(); } private void requestPermission() { // 全量权限申请 XXPermissions.with(ActivityUtils.getTopActivity()) .permission(Permission.READ_EXTERNAL_STORAGE) .permission(Permission.WRITE_EXTERNAL_STORAGE) .permission(Permission.NOTIFICATION_SERVICE) .request(new OnPermissionCallback() { @Override public void onGranted(@NonNull List permissions, boolean allGranted) { if (allGranted) { terminalAuth(); } else { new XPopup.Builder(TaskService.this) .dismissOnBackPressed(false) .dismissOnTouchOutside(false) .asConfirm("Tips", "您必须同意所有权限才可以继续使用", () -> requestPermission()) .show(); } } @Override public void onDenied(@NonNull List permissions, boolean doNotAskAgain) { OnPermissionCallback.super.onDenied(permissions, doNotAskAgain); if (doNotAskAgain) { new XPopup.Builder(TaskService.this) .dismissOnBackPressed(false) .dismissOnTouchOutside(false) .asConfirm("Tips", "您必须同意所有权限才可以继续使用", () -> XXPermissions.startPermissionActivity(TaskService.this, permissions)) .show(); } else { new XPopup.Builder(TaskService.this) .dismissOnBackPressed(false) .dismissOnTouchOutside(false) .asConfirm("Tips", "您必须同意所有权限才可以继续使用", () -> requestPermission()) .show(); } } }); } ThreadUtils.SimpleTask simpleTask = new ThreadUtils.SimpleTask() { @Override public Boolean doInBackground() throws Throwable { return NetworkUtils.isAvailableByPing(Tool.INSTANCE.getBaseUrl().host()); } @Override public void onSuccess(Boolean result) { if (result) { EventBus.getDefault().post(new UpdateUiEvent("鉴权中...")); ThreadUtils.executeByCached(new ThreadUtils.SimpleTask>() { @Override public Pair doInBackground() throws Throwable { try { SPUtils.getInstance().put("TerminalAuth", ""); Response response = HttpTool.INSTANCE.terminalAuth(); if (response.isSuccessful()) { String json = response.body().string(); JSONObject jsonObject = new JSONObject(json); int code = jsonObject.getInt("code"); if (200 == code) { String data = jsonObject.getString("data"); SPUtils.getInstance().put("TerminalAuth", TextUtils.isEmpty(data) ? "" : data); return Pair.create(true, ""); } else { return Pair.create(false, jsonObject.getString("message")); } } } catch (Exception e) { LogUtils.e(Log.getStackTraceString(e)); } return Pair.create(false, "鉴权异常,请联系管理员!"); } @Override public void onSuccess(Pair result) { if (result.first) { // // 状态栏是否开启 // boolean isStatusBarEnable = InfoDisplayApi.getStatusBarEnable(); // // 导航栏是否开启 // boolean isNavBarEnable = InfoDisplayApi.getNavigationBarEnable(); // // EthernetConfig ethernetConfig = InfoNetworkApi.getEthernetConfig(); // // Ip // String ip = ethernetConfig.getIpAddress(); // // dhcp // int dhcp = ethernetConfig.getDhcp(); // // dns1 // String dns1 = ethernetConfig.getDns1Address(); // // dns2 // String dns2 = ethernetConfig.getDns2Address(); // // mac // String mac = ethernetConfig.getMacAddress(); // // route // String route = ethernetConfig.getRouteAddress(); // // subnetMask // String subnetMask = ethernetConfig.getSubnetMask(); // // 最优Ip地址 以太网>无线网>3、4G // String optimalIp = InfoNetworkApi.getOptimalIp(); // // 设备型号 // String deviceType = InfoSystemApi.getDeviceType(); // // 设备序列号 // String sn = InfoSystemApi.getSerialNumber(); // // adb状态 // int adbStatus = InfoSystemApi.getAdbStatus(); // // 设备箱体温度 // String temperature = InfoSystemApi.getTemperature(); // // 系统编译版本号 V2.0.0 build 171226 // String buildDesc = InfoSystemApi.getBuildDesc(); // // 系统MCU版本号 V1.0.0 build 171226 // String mcuVersion = InfoSystemApi.getMcuVersion(); // // CPU使用率 当前 Cpu 的使用率,百分比,获取失败时返回”-1.00”字符串 // String cpuUsageRate = InfoSystemApi.getCpuUsageRate(); // // GPU使用率 当前 Gpu 的使用率,百分比,获取失败时返回”-1.00”字符串 // String gpuUsageRate = InfoSystemApi.getGpuUsageRate(); // // 获取内存使用情况 // MemoryInfo memoryInfo = InfoSystemApi.getMemoryUsage(); // // MemoryInfo .used 已使用内存大小(单位 MB) // int used = memoryInfo.used; // // MemoryInfo.total 总内存大小(MB) // int total = memoryInfo.total; // // MemoryInfo.describe 583.00MB/1.96GB // String describe = memoryInfo.describe; // int describeContents = memoryInfo.describeContents(); // // 获取SDK版本 返回 SDK 版本号,获取失败返回”none”字符串 // String sdkVersion = InfoSystemApi.getSdkVersion(); // // 如果系统不支持该接口,则 currentLauncherName 和 preferredLauncherName 的值均为空字符串(“”)。 // // 关于“默认“一词,默认 Launcher 即多个 Launcher 应用中优先级最高的,默认启动的。 // LauncherInfo launcherInfo = InfoSystemApi.getLauncherName(); // // 为当前生效的默认 Launcher 应用包名,默认(始终)Launcher 应用修改后该值即时更新。如果当前系统未设置默认(始终)Launcher,则该值为空字符串(“”)。 // String currentLauncherName = launcherInfo.getCurrentLauncherName(); // // 为持久化文件中保存的默认 Launcher 应用包名,默认 Launcher 应用修改后约 10 秒后该值才会更新,该值仅当系统内存在 2 个及以上Launcher 应用时才会存在,否则为空字符串(“”)。 // String preferredLauncherName = launcherInfo.getPreferredLauncherName(); // // 获取定时开关机计划 // TimeSwitchConfig timeSwitchConfig = InfoTimeApi.getTimeSwitch(); // // 开机时间 默认-1 // long onTime = timeSwitchConfig.setOnTime; // // 关机时间 默认-1 // long offTime = timeSwitchConfig.setOffTime; // // 门禁点锁状态1 true-当前锁处于上电锁门状态 // // false-当前锁处于断电开门状态或参数错误 // boolean electricLock1 = InfoUtilApi.getElectricLock(1); // // 门禁点锁状态2 // boolean electricLock2 = InfoUtilApi.getElectricLock(2); EventBus.getDefault().post(new UpdateUiEvent(result.second)); ThreadUtils.cancel(simpleTask); } else { EventBus.getDefault().post(new UpdateUiEvent(result.second)); } } }); } else { EventBus.getDefault().post(new UpdateUiEvent("无法连接到服务器,请联系管理员!")); } } }; private void terminalAuth() { ThreadUtils.executeByCachedAtFixRate(simpleTask, ThreadLocalRandom.current().nextInt(10, 20), TimeUnit.SECONDS); // 清理一个月前的log ThreadUtils.executeByCached(new ThreadUtils.SimpleTask() { @Override public Object doInBackground() throws Throwable { List fileList = FileUtils.listFilesInDir("/sdcard/logs/"); for (int i = 0; i < fileList.size(); i++) { File file = fileList.get(i); long oneMonth = 30 * 86400 * 1000L; if ((System.currentTimeMillis() - file.lastModified()) > oneMonth) { LogUtils.d("删除日志文件", file); FileUtils.delete(file); } } return null; } @Override public void onSuccess(Object result) { } }); } }