Commit 9dbbee47 by pye52

Merge branch 'develop' into uat

parents cb24790b 0b51e3c7
...@@ -13,6 +13,7 @@ android { ...@@ -13,6 +13,7 @@ android {
versionCode 13 versionCode 13
versionName "1.3.3" // test分支 versionName "1.3.3" // test分支
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
buildConfigField "int", "DaemonVersion", String.valueOf(rootProject.ext.daemon_verson_code)
} }
buildTypes { buildTypes {
release { release {
...@@ -47,15 +48,14 @@ android { ...@@ -47,15 +48,14 @@ android {
// but continue the build even when errors are found: // but continue the build even when errors are found:
abortOnError false abortOnError false
} }
// 命名生成的apk
applicationVariants.all { variant -> applicationVariants.all { variant ->
if (variant.buildType.name != "debug") { if (variant.buildType.name != "debug") {
variant.getPackageApplicationProvider().get().outputDirectory = new File(project.rootDir.absolutePath + "/apk") variant.getPackageApplicationProvider()
variant.getPackageApplicationProvider().get().outputScope.apkDatas.forEach { apkData -> .get()
apkData.outputFileName = "SmartCanteen" + .outputScope
"_" + variant.buildType.name + .apkDatas
"_v" + variant.versionName + ".apk" .forEach { apkData -> apkData.outputFileName = "SmartCanteen" + "_v" + variant.versionName + ".apk" }
}
} }
} }
compileOptions { compileOptions {
......
...@@ -3,6 +3,7 @@ package com.bgycc.smartcanteen.action ...@@ -3,6 +3,7 @@ package com.bgycc.smartcanteen.action
import com.bgycc.smartcanteen.BuildConfig import com.bgycc.smartcanteen.BuildConfig
import com.bgycc.smartcanteen.event.SettingStateEvent import com.bgycc.smartcanteen.event.SettingStateEvent
import com.bgycc.smartcanteen.helper.TimerHelper import com.bgycc.smartcanteen.helper.TimerHelper
import com.bgycc.smartcanteen.util.DeviceProxy
import com.blankj.utilcode.util.* import com.blankj.utilcode.util.*
import okhttp3.Call import okhttp3.Call
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
...@@ -88,7 +89,7 @@ class UpdateAction private constructor() : Action(ActionEnum.CONFIG_UPDATE.name) ...@@ -88,7 +89,7 @@ class UpdateAction private constructor() : Action(ActionEnum.CONFIG_UPDATE.name)
EventBus.getDefault().post(SettingStateEvent(99, "不允许安装低版本")) EventBus.getDefault().post(SettingStateEvent(99, "不允许安装低版本"))
} else { } else {
EventBus.getDefault().post(SettingStateEvent(99, "安装更新包")) EventBus.getDefault().post(SettingStateEvent(99, "安装更新包"))
AppUtils.installApp(FILE_UPDATE_APK) DeviceProxy.updateApp(FILE_UPDATE_APK)
} }
finish() finish()
return return
......
...@@ -121,14 +121,16 @@ class MainActivity : BaseActivity() { ...@@ -121,14 +121,16 @@ class MainActivity : BaseActivity() {
Log.i(TAG, "keyCode: $keyCode") Log.i(TAG, "keyCode: $keyCode")
// ToastUtils.showLong("keyCode: $keyCode") // ToastUtils.showLong("keyCode: $keyCode")
when(keyCode) { when(keyCode) {
KeyEvent.KEYCODE_PAGE_UP -> { KeyEvent.KEYCODE_PAGE_UP,
KeyEvent.KEYCODE_NUMPAD_ADD -> {
mAudioManager!!.adjustStreamVolume( mAudioManager!!.adjustStreamVolume(
AudioManager.STREAM_SYSTEM, AudioManager.STREAM_SYSTEM,
AudioManager.ADJUST_RAISE, AudioManager.ADJUST_RAISE,
AudioManager.FLAG_SHOW_UI AudioManager.FLAG_SHOW_UI
) )
} }
KeyEvent.KEYCODE_PAGE_DOWN -> { KeyEvent.KEYCODE_PAGE_DOWN,
KeyEvent.KEYCODE_NUMPAD_SUBTRACT -> {
mAudioManager!!.adjustStreamVolume( mAudioManager!!.adjustStreamVolume(
AudioManager.STREAM_SYSTEM, AudioManager.STREAM_SYSTEM,
AudioManager.ADJUST_LOWER, AudioManager.ADJUST_LOWER,
......
...@@ -8,9 +8,9 @@ import com.bgycc.smartcanteen.event.LogEvent; ...@@ -8,9 +8,9 @@ import com.bgycc.smartcanteen.event.LogEvent;
import com.bgycc.smartcanteen.event.QRCodeInvalidEvent; import com.bgycc.smartcanteen.event.QRCodeInvalidEvent;
import com.bgycc.smartcanteen.helper.TimerHelper; import com.bgycc.smartcanteen.helper.TimerHelper;
import com.bgycc.smartcanteen.qrcode.IQRCodeScan; import com.bgycc.smartcanteen.qrcode.IQRCodeScan;
import com.bgycc.smartcanteen.qrcode.QRCodeScanFactory;
import com.bgycc.smartcanteen.server.websocket.MainWebSocket; import com.bgycc.smartcanteen.server.websocket.MainWebSocket;
import com.bgycc.smartcanteen.util.ByteUtil; import com.bgycc.smartcanteen.util.ByteUtil;
import com.bgycc.smartcanteen.util.DeviceProxy;
import com.blankj.utilcode.util.LogUtils; import com.blankj.utilcode.util.LogUtils;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
...@@ -53,7 +53,7 @@ public class QRCodeTask { ...@@ -53,7 +53,7 @@ public class QRCodeTask {
if (mScanAsyncTask == null) { if (mScanAsyncTask == null) {
try { try {
serial = QRCodeScanFactory.create(); serial = DeviceProxy.createQRCodeScan();
} catch (Exception e) { } catch (Exception e) {
LogUtils.file("串口初始化失败"); LogUtils.file("串口初始化失败");
} }
......
package com.bgycc.smartcanteen.util;
import com.bgycc.smartcanteen.qrcode.IQRCodeScan;
import com.bgycc.smartcanteen.qrcode.QRCodeScanFactory;
import java.io.File;
/**
* 多设备相关方案的代理类 <br/>
* 设计该代理类目的是为了增加设备时,务必在下面所有方法的实际执行里进行适配
*/
public class DeviceProxy {
public static final String DEVICE_MODEL_TPS = "TPS";
public static final String DEVICE_MODEL_QUAD = "QUAD";
public static IQRCodeScan createQRCodeScan() throws Exception {
return QRCodeScanFactory.create();
}
public static boolean updateApp(File updateApk) {
return InstallManager.install(updateApk);
}
}
package com.bgycc.smartcanteen.util;
import android.content.ComponentName;
import android.content.Intent;
import android.os.Build;
import com.bgycc.smartcanteen.BuildConfig;
import com.bgycc.smartcanteen.activity.MainActivity;
import com.blankj.utilcode.util.AppUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.PathUtils;
import com.blankj.utilcode.util.Utils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class InstallManager {
private static final String TAG = "InstallManager";
private static final String ARG_PATH = "arg_path";
private static final String ARG_COMPONENT = "arg_package";
// assets文件夹中守护进程apk名称
private static final String DAEMON_APK_NAME = "Daemon.apk";
// 守护package name
private static final String DAEMON_PACKAGE_NAME = "com.bgycc.smartcanteen.daemon";
// 守护服务类名称
private static final String DAEMON_SERVICE_NAME = "com.bgycc.smartcanteen.daemon.DaemonService";
public static boolean install(File updateApk) {
String model = Build.MODEL;
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
// 6.0以下安装包需要修改权限才能安装
try {
Process p = Runtime.getRuntime().exec("chmod 755 " + updateApk);
p.waitFor();
LogUtils.d(TAG, "安装文件权限修改成功");
} catch (Exception e) {
LogUtils.e(TAG, "安装文件权限修改失败");
return false;
}
}
if (model.contains(DeviceProxy.DEVICE_MODEL_TPS)) {
// 检查守护进程的安装情况,及其安装版本
if (!AppUtils.isAppInstalled(DAEMON_PACKAGE_NAME)) {
LogUtils.d(TAG, "守护app未安装,从assets复制并进行安装");
if (installDaemonFromAssets(false)) {
return DangerousUtils.installAppSilent(updateApk);
}
} else {
// 若已安装,则检查是否需要更新
AppUtils.AppInfo daemonAppInfo = AppUtils.getAppInfo(DAEMON_PACKAGE_NAME);
if (daemonAppInfo.getVersionCode() < BuildConfig.DaemonVersion) {
LogUtils.d(TAG, "当前守护app版本: " + daemonAppInfo.getVersionCode() + ", 最新版本: " + BuildConfig.DaemonVersion);
if (installDaemonFromAssets(true)) {
return DangerousUtils.installAppSilent(updateApk);
}
}
}
startDaemonForInstall(updateApk);
return true;
} else if (model.contains(DeviceProxy.DEVICE_MODEL_QUAD)) {
AppUtils.installApp(updateApk);
return true;
} else {
throw new RuntimeException("不明设备型号: " + model);
}
}
private static void copyDaemonApkToTarget(File daemonApk) throws IOException {
InputStream is = Utils.getApp().getAssets().open(DAEMON_APK_NAME);
FileOutputStream fos = new FileOutputStream(daemonApk);
byte[] buffer = new byte[1024];
int byteCount;
while ((byteCount = is.read(buffer)) != -1) {
fos.write(buffer, 0, byteCount);
}
fos.flush();
is.close();
fos.close();
}
private static boolean installDaemonFromAssets(boolean update) {
File daemonApk = new File(PathUtils.getExternalStoragePath(), DAEMON_APK_NAME);
try {
copyDaemonApkToTarget(daemonApk);
boolean result = DangerousUtils.installAppSilent(daemonApk);
LogUtils.d(TAG, "守护app安装结果: " + result);
if (!result) {
LogUtils.d(TAG, "守护app" + (update ? "更新" : "安装") + "失败,启动静默安装");
return true;
}
} catch (IOException e) {
LogUtils.d(TAG, update ? "assets文件夹中未找到守护apk,或守护app复制失败,启动静默安装" : "新版app复制失败,启动静默安装", e);
return true;
} finally {
FileUtils.delete(daemonApk);
}
return false;
}
private static void startDaemonForInstall(File updateApk) {
LogUtils.d(TAG, "启动守护app进行更新操作");
ComponentName componentName = new ComponentName(DAEMON_PACKAGE_NAME, DAEMON_SERVICE_NAME);
Intent intent = new Intent();
intent.putExtra(ARG_PATH, updateApk.getAbsolutePath());
intent.putExtra(ARG_COMPONENT, BuildConfig.APPLICATION_ID + File.separator + MainActivity.class.getName());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(componentName);
Utils.getApp().startService(intent);
}
}
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.3.61' ext {
kotlin_version = '1.3.61'
daemon_verson_code = 10
daemon_verson_name = "1.0"
}
repositories { repositories {
jcenter()
google() google()
jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.6.1' classpath 'com.android.tools.build:gradle:3.6.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
} }
} }
allprojects { allprojects {
repositories { repositories {
jcenter()
google() google()
jcenter()
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
} }
} }
// 保证daemon会先打包到app的assets文件夹内
task clean(type: Delete) { task clean(type: Delete) {
delete rootProject.buildDir delete rootProject.buildDir
Task appPreBuildTask;
Task daemonBuildTask;
subprojects.forEach { project ->
if (project.name == "app") {
Set<Task> appPreBuildTasks = project.getTasksByName("preBuild", false)
if (!appPreBuildTasks.isEmpty()) {
appPreBuildTask = appPreBuildTasks[0]
}
} else if (project.name == "daemon") {
Set<Task> daemonAssembleReleaseTasks = project.getTasksByName("assembleRelease", false)
if (!daemonAssembleReleaseTasks.isEmpty()) {
daemonBuildTask = daemonAssembleReleaseTasks[0]
}
}
}
if (appPreBuildTask != null && daemonBuildTask != null) {
appPreBuildTask.dependsOn(daemonBuildTask)
}
} }
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.bgycc.smartcanteen.daemon"
minSdkVersion 21
targetSdkVersion 22
versionCode rootProject.ext.daemon_verson_code
versionName rootProject.ext.daemon_verson_name
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
postprocessing {
removeUnusedCode true
removeUnusedResources true
obfuscate false
optimizeCode true
proguardFiles 'proguard-rules.pro'
}
zipAlignEnabled true
}
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
// daemon输出到app模块的assets目录中
applicationVariants.all { variant ->
if (variant.buildType.name != "debug") {
String targetDir = findAppAssetsDir()
if (!targetDir.isEmpty()) {
variant.getPackageApplicationProvider()
.get()
.outputDirectory = new File(targetDir)
}
variant.getPackageApplicationProvider()
.get()
.outputScope
.apkDatas
.forEach { apkData -> apkData.outputFileName = "Daemon.apk" }
}
}
}
// 在打包完成后删除生成的output.json文件
tasks.whenTaskAdded { task ->
if (task.name == 'assembleRelease') {
task.doLast {
String targetDir = findAppAssetsDir()
if (targetDir.isEmpty()) {
return
}
File outputJsonFile = new File(targetDir, "output.json")
if (outputJsonFile.exists()) {
outputJsonFile.delete()
}
}
}
}
private String findAppAssetsDir() {
for (Project p : rootProject.subprojects) {
if (p.name == "app") {
return "${p.projectDir}${File.separator}src${File.separator}main${File.separator}assets${File.separator}"
}
}
return ""
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.blankj:utilcode:1.26.0'
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# -----------------------------基本 -----------------------------
#
# 指定代码的压缩级别 0 - 7(指定代码进行迭代优化的次数,在Android里面默认是5,这条指令也只有在可以优化时起作用。)
-optimizationpasses 5
# 混淆时不会产生形形色色的类名(混淆时不使用大小写混合类名)
-dontusemixedcaseclassnames
# 指定不去忽略非公共的库类(不跳过library中的非public的类)
-dontskipnonpubliclibraryclasses
# 指定不去忽略包可见的库类的成员
-dontskipnonpubliclibraryclassmembers
#不进行优化,建议使用此选项,
-dontoptimize
# 不进行预校验,Android不需要,可加快混淆速度。
-dontpreverify
# 屏蔽警告
-ignorewarnings
# 指定混淆是采用的算法,后面的参数是一个过滤器
# 这个过滤器是谷歌推荐的算法,一般不做更改
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# 保护代码中的Annotation不被混淆
-keepattributes *Annotation*
# 避免混淆泛型, 这在JSON实体映射时非常重要
-keepattributes Signature
# 抛出异常时保留代码行号
-keepattributes SourceFile,LineNumberTable
#优化时允许访问并修改有修饰符的类和类的成员,这可以提高优化步骤的结果。
# 比如,当内联一个公共的getter方法时,这也可能需要外地公共访问。
# 虽然java二进制规范不需要这个,要不然有的虚拟机处理这些代码会有问题。当有优化和使用-repackageclasses时才适用。
#指示语:不能用这个指令处理库中的代码,因为有的类和类成员没有设计成public ,而在api中可能变成public
-allowaccessmodification
#当有优化和使用-repackageclasses时才适用。
-repackageclasses
# 混淆时记录日志(打印混淆的详细信息)
# 这句话能够使我们的项目混淆后产生映射文件
# 包含有类名->混淆后类名的映射关系
-verbose
#
# ----------------------------- 默认保留 -----------------------------
#
#----------------------------------------------------
# 保持哪些类不被混淆
#继承activity,application,service,broadcastReceiver,contentprovider....不进行混淆
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.support.multidex.MultiDexApplication
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class * extends android.view.View
-keep class android.support.** {*;}## 保留support下的所有类及其内部类
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
#表示不混淆上面声明的类,最后这两个类我们基本也用不上,是接入Google原生的一些服务时使用的。
#----------------------------------------------------
# 保留继承的
-keep public class * extends android.support.v4.**
-keep public class * extends android.support.v7.**
-keep public class * extends android.support.annotation.**
#表示不混淆任何包含native方法的类的类名以及native方法名,这个和我们刚才验证的结果是一致
-keepclasseswithmembernames class * {
native <methods>;
}
#这个主要是在layout 中写的onclick方法android:onclick="onClick",不进行混淆
#表示不混淆Activity中参数是View的方法,因为有这样一种用法,在XML中配置android:onClick=”buttonClick”属性,
#当用户点击该按钮时就会调用Activity中的buttonClick(View view)方法,如果这个方法被混淆的话就找不到了
-keepclassmembers class * extends android.app.Activity{
public void *(android.view.View);
}
#表示不混淆枚举中的values()和valueOf()方法,枚举我用的非常少,这个就不评论了
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
#表示不混淆任何一个View中的setXxx()和getXxx()方法,
#因为属性动画需要有相应的setter和getter的方法实现,混淆了就无法工作了。
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#表示不混淆Parcelable实现类中的CREATOR字段,
#毫无疑问,CREATOR字段是绝对不能改变的,包括大小写都不能变,不然整个Parcelable工作机制都会失败。
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
# 这指定了继承Serizalizable的类的如下成员不被移除混淆
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# 保留R下面的资源
#-keep class **.R$* {
# *;
#}
#不混淆资源类下static的
-keepclassmembers class **.R$* {
public static <fields>;
}
# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆
-keepclassmembers class * {
void *(**On*Event);
void *(**On*Listener);
}
# 保留我们自定义控件(继承自View)不被混淆
-keep public class * extends android.view.View{
*** get*();
void set*(***);
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
}
#
# ----------------------------- 第三方 -----------------------------
#
#不混淆smartcanteen下的所有类
-keep class com.bgycc.smartcanteen.** { *; }
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.bgycc.smartcanteen.daemon">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name=".ServiceApplication"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" >
<service android:name=".DaemonService"
android:exported="true" />
</application>
</manifest>
package com.bgycc.smartcanteen.daemon;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.text.TextUtils;
import com.blankj.utilcode.util.FileUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.PathUtils;
import com.blankj.utilcode.util.ShellUtils;
import java.io.File;
public class DaemonService extends Service {
private static final String TAG = "DaemonService";
private static final String UPDATE_APK = "SmartCanteen-update.apk";
private static final String ARG_PATH = "arg_path";
private static final String ARG_COMPONENT = "arg_package";
// 主应用package name
private static final String MAIN_PACKAGE_NAME = "com.bgycc.smartcanteen";
// 主应用类名称
private static final String MAIN_ACTIVITY_NAME = "com.bgycc.smartcanteen.activity.MainActivity";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String path = intent.getStringExtra(ARG_PATH);
if (TextUtils.isEmpty(path)) {
path = PathUtils.getExternalStoragePath() + File.separator + UPDATE_APK;
LogUtils.d(TAG, "安装apk地址为空,使用默认地址: " + path);
}
String component = intent.getStringExtra(ARG_COMPONENT);
if (TextUtils.isEmpty(component)) {
component = MAIN_PACKAGE_NAME + File.separator + MAIN_ACTIVITY_NAME;
LogUtils.d(TAG, "安装完毕启动包名为空,使用默认包名: " + component);
}
String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install -r " + '"' + path + '"'
+ ";am start -W " + component;
LogUtils.d(TAG, "开始静默安装, path: " + path + ", component: " + command);
ShellUtils.CommandResult commandResult = ShellUtils.execCmd(command, isDeviceRooted());
LogUtils.d(TAG, "安装完毕, success: " + commandResult.successMsg +
", error: " + commandResult.errorMsg);
FileUtils.delete(path);
stopSelf(START_NOT_STICKY);
return START_NOT_STICKY ;
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
private static boolean isDeviceRooted() {
String su = "su";
String[] locations = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/",
"/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/",
"/system/sbin/", "/usr/bin/", "/vendor/bin/"};
for (String location : locations) {
if (new File(location + su).exists()) {
return true;
}
}
return false;
}
}
package com.bgycc.smartcanteen.daemon;
import android.app.Application;
import com.blankj.utilcode.util.CrashUtils;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.PathUtils;
import com.blankj.utilcode.util.Utils;
import java.io.File;
public class ServiceApplication extends Application {
private static final String LOG_PREFIX = "daemon";
private static final String LOG_DIR = "log";
@Override
public void onCreate() {
super.onCreate();
Utils.init(getApplicationContext());
CrashUtils.init();
String logDir = PathUtils.getExternalStoragePath() + File.separator + LOG_DIR;
CrashUtils.init(logDir);
LogUtils.getConfig()
.setDir(logDir)
.setLog2FileSwitch(true)
.setBorderSwitch(false)
.setFilePrefix(LOG_PREFIX);
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#6200EE</color>
<color name="colorPrimaryDark">#3700B3</color>
<color name="colorAccent">#03DAC5</color>
</resources>
<resources>
<string name="app_name">Daemon</string>
</resources>
include ':app' include ':app', ':daemon'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment