├── .gitattributes
├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── inspectionProfiles
│ └── Project_Default.xml
├── misc.xml
└── vcs.xml
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── kaly.jks
├── libs
│ ├── Xpopup-release.aar
│ ├── easyAdapter.jar
│ ├── glide.jar
│ └── overscroll-release-v1.1-20160904.jar
├── proguard-rules.pro
├── release_mini
│ └── output-metadata.json
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── pointer
│ │ └── wave
│ │ └── easyship
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── 7za
│ │ ├── magisk_library.sh
│ │ └── run.sh
│ ├── java
│ │ └── com
│ │ │ └── pointer
│ │ │ └── wave
│ │ │ └── easyship
│ │ │ ├── EasyShip.java
│ │ │ ├── FlashActivity.java
│ │ │ ├── MainActivity.kt
│ │ │ ├── android
│ │ │ ├── AutoCompletePanel.java
│ │ │ ├── ClipboardPanel.java
│ │ │ ├── FreeScrollingTextField.java
│ │ │ ├── KeysInterpreter.java
│ │ │ ├── OnSelectionChangedListener.java
│ │ │ ├── TextChangeListener.java
│ │ │ ├── TouchNavigationMethod.java
│ │ │ └── YoyoNavigationMethod.java
│ │ │ ├── base
│ │ │ └── BaseFragment.java
│ │ │ ├── common
│ │ │ ├── ColorScheme.java
│ │ │ ├── ColorSchemeDark.java
│ │ │ ├── ColorSchemeLight.java
│ │ │ ├── Document.java
│ │ │ ├── DocumentProvider.java
│ │ │ ├── Flag.java
│ │ │ ├── JavaLexer.java
│ │ │ ├── JavaTokenTypes.java
│ │ │ ├── Language.java
│ │ │ ├── LanguageCFamily.java
│ │ │ ├── LanguageJava.java
│ │ │ ├── LanguageNonProg.java
│ │ │ ├── Lexer.java
│ │ │ ├── LinearSearchStrategy.java
│ │ │ ├── Pair.java
│ │ │ ├── ProgressObserver.java
│ │ │ ├── ProgressSource.java
│ │ │ ├── ReadThread.java
│ │ │ ├── RowListener.java
│ │ │ ├── SearchStrategy.java
│ │ │ ├── TextBuffer.java
│ │ │ ├── TextBufferCache.java
│ │ │ ├── TextWarriorException.java
│ │ │ ├── UndoStack.java
│ │ │ ├── WriteThread.java
│ │ │ ├── activity
│ │ │ │ └── BaseActivity.java
│ │ │ └── crash
│ │ │ │ └── CrashHandler.java
│ │ │ ├── core
│ │ │ ├── CacheDao.java
│ │ │ ├── LoadShellUtil.java
│ │ │ ├── ROTAUpdateManager.java
│ │ │ ├── RealtimeProcess.java
│ │ │ ├── RunTimeUtils.java
│ │ │ ├── UpdateEngineCallback.java
│ │ │ ├── UpdateParser.java
│ │ │ └── ZoomInTransformer.kt
│ │ │ ├── editor
│ │ │ └── TextEditor.java
│ │ │ ├── fragments
│ │ │ ├── AboutFragment.java
│ │ │ └── HomeFragment.java
│ │ │ ├── interfaces
│ │ │ ├── OnNavigationStateListener.java
│ │ │ ├── OnProcessDestroyListener.java
│ │ │ ├── OnProcessErrorListener.java
│ │ │ ├── OnRunTimeListener.java
│ │ │ └── RealtimeProcessInterface.java
│ │ │ ├── ktx
│ │ │ ├── AppGlobalScope.kt
│ │ │ └── KoinKtx.kt
│ │ │ ├── net
│ │ │ ├── Api.kt
│ │ │ ├── LogInterceptor.kt
│ │ │ ├── NetModule.kt
│ │ │ └── repo
│ │ │ │ └── UpdateRepo.kt
│ │ │ ├── pojo
│ │ │ ├── TipsBen.java
│ │ │ ├── UpdateLogBen.java
│ │ │ └── VersionBen.java
│ │ │ ├── services
│ │ │ ├── ProcessService.java
│ │ │ └── RunTimeService.java
│ │ │ ├── utils
│ │ │ ├── AndroidInfo.java
│ │ │ ├── ColorChangeUtils.java
│ │ │ ├── DensityUtil.java
│ │ │ ├── FileInterface.java
│ │ │ ├── FileUtil.java
│ │ │ ├── HttpUtils.java
│ │ │ ├── JsonUtils.java
│ │ │ ├── KeepShell.kt
│ │ │ ├── KeepShellPublic.kt
│ │ │ ├── SAF.java
│ │ │ ├── ShellExecutor.java
│ │ │ ├── ShellUtil.java
│ │ │ └── ZipUtils.java
│ │ │ ├── view
│ │ │ └── SymbolView.java
│ │ │ └── widget
│ │ │ ├── HelpsDialog.java
│ │ │ ├── IOSOverScrollView.java
│ │ │ ├── MarqueeTextView.java
│ │ │ ├── NavigationBar.java
│ │ │ ├── OverRecyclerView.java
│ │ │ ├── OverScrollView.java
│ │ │ ├── PermissionsDialog.java
│ │ │ ├── TipsPagerAdapter.java
│ │ │ ├── UpdateLogDialog.java
│ │ │ ├── ViewPagerAdapterForView.java
│ │ │ ├── adapter
│ │ │ └── HelpsListAdapter.java
│ │ │ └── feedback
│ │ │ └── TouchFeedback.java
│ └── res
│ │ ├── animator
│ │ ├── fragment_slide_hide.xml
│ │ └── fragment_slide_show.xml
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── ic_content_copy_white_24dp.png
│ │ ├── ic_content_cut_white_24dp.png
│ │ ├── ic_content_paste_white_24dp.png
│ │ ├── ic_launcher_background.xml
│ │ ├── ic_select_all_white_24dp.png
│ │ ├── icon_method.png
│ │ ├── shape_editor.xml
│ │ ├── shape_flash_button.xml
│ │ ├── shape_indicator.xml
│ │ ├── shape_indicator_select.xml
│ │ └── shape_shadow_layout.xml
│ │ ├── layout
│ │ ├── activity_flash.xml
│ │ ├── activity_main.xml
│ │ ├── dialog_full_base.xml
│ │ ├── dialog_helps.xml
│ │ ├── dialog_permissin_write.xml
│ │ ├── dialog_update_log.xml
│ │ ├── fragment_about.xml
│ │ ├── fragment_home.xml
│ │ ├── fragment_navigation.xml
│ │ ├── item_auto_panel.xml
│ │ ├── item_help_layout.xml
│ │ ├── item_tips_viewpager.xml
│ │ ├── layout_navigation_item.xml
│ │ └── symbol_view.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_alipay.png
│ │ ├── ic_developer.png
│ │ ├── ic_download.png
│ │ ├── ic_es_logo.png
│ │ ├── ic_es_logo_round.png
│ │ ├── ic_file.png
│ │ ├── ic_folder.png
│ │ ├── ic_github.png
│ │ ├── ic_help.png
│ │ ├── ic_home.png
│ │ ├── ic_idea.png
│ │ ├── ic_launcher.webp
│ │ ├── ic_launcher_round.webp
│ │ ├── ic_log.png
│ │ ├── ic_logo_white_24dp.png
│ │ ├── ic_mail.png
│ │ ├── ic_notification.png
│ │ ├── ic_root.png
│ │ ├── ic_settings.png
│ │ ├── ic_start.png
│ │ ├── ic_sub_notification.png
│ │ ├── ic_tips.png
│ │ ├── ic_update.png
│ │ └── ic_waring.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values-night
│ │ ├── colors.xml
│ │ └── themes.xml
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── configs.xml
│ │ ├── dimens.xml
│ │ ├── strings.xml
│ │ └── themes.xml
│ │ └── xml
│ │ ├── network_security_config.xml
│ │ └── update_path.xml
│ └── test
│ └── java
│ └── com
│ └── pointer
│ └── wave
│ └── easyship
│ ├── ExampleUnitTest.kt
│ └── Test.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 | *.aab
5 |
6 | # Files for the ART/Dalvik VM
7 | *.dex
8 |
9 | # Java class files
10 | *.class
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 |
21 | # Local configuration file (sdk path, etc)
22 | local.properties
23 |
24 | # Proguard folder generated by Eclipse
25 | proguard/
26 |
27 | # Log Files
28 | *.log
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 |
33 | # Android Studio captures folder
34 | captures/
35 |
36 | # IntelliJ
37 | *.iml
38 | .idea/workspace.xml
39 | .idea/tasks.xml
40 | .idea/gradle.xml
41 | .idea/assetWizardSettings.xml
42 | .idea/dictionaries
43 | .idea/libraries
44 | .idea/caches
45 |
46 | # Keystore files
47 | # Uncomment the following lines if you do not want to check your keystore files in.
48 | #*.jks
49 | #*.keystore
50 |
51 | # External native build folder generated in Android Studio 2.2 and later
52 | .externalNativeBuild
53 |
54 | # Google Services (e.g. APIs or Firebase)
55 | google-services.json
56 |
57 | # Freeline
58 | freeline.py
59 | freeline/
60 | freeline_project_description.json
61 |
62 | # fastlane
63 | fastlane/report.xml
64 | fastlane/Preview.html
65 | fastlane/screenshots
66 | fastlane/test_output
67 | fastlane/readme.md
68 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 LumnyTool
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # EasyShip
2 | 一叶孤舟 · VAB设备系统更新
3 |
4 | 描述:一个用于绕过系统更新程序从而使用户进行自定义更新系统版本的APP
5 |
6 | 特性:
7 | 1. VAB检测
8 | 2. 更新进度可视化
9 | 3. 快速启动
10 | 4. 断点续更
11 | ......
12 |
13 | 目前还有诸多没有完善的地方,欢迎大家push~
14 |
15 | 企鹅交流群:1009818916
16 |
17 | EasyShip永久保持免费且开源,欢迎使用!
18 |
19 | # 一叶孤舟2发布!
20 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | android {
7 | compileSdk 31
8 |
9 | dataBinding {
10 | enabled = true
11 | }
12 |
13 | signingConfigs {
14 | ly_Signing {
15 | keyAlias 'kaly'
16 | keyPassword '0409kaly'
17 | storeFile file('./kaly.jks')
18 | storePassword '0409kaly'
19 | }
20 | }
21 |
22 | defaultConfig {
23 | applicationId "com.pointer.wave.easyship"
24 | minSdk 26
25 | targetSdk 32
26 | versionCode 22041122
27 | versionName "1.0"
28 |
29 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
30 |
31 | ndk {
32 | //abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64", "mips", "mips64"
33 | abiFilters "armeabi-v7a", "arm64-v8a"
34 | }
35 |
36 | renderscriptTargetApi 31
37 | renderscriptSupportModeEnabled true
38 | }
39 |
40 | buildTypes {
41 | release {
42 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
43 | zipAlignEnabled true
44 | debuggable false
45 | minifyEnabled = false
46 | signingConfig signingConfigs.ly_Signing
47 | }
48 | release_mini {
49 | shrinkResources true
50 | zipAlignEnabled true
51 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
52 | minifyEnabled true
53 | debuggable false
54 | }
55 | debug {
56 | signingConfig signingConfigs.ly_Signing
57 | minifyEnabled false
58 | }
59 | }
60 | compileOptions {
61 | sourceCompatibility JavaVersion.VERSION_1_8
62 | targetCompatibility JavaVersion.VERSION_1_8
63 | }
64 | kotlinOptions {
65 | jvmTarget = '1.8'
66 | }
67 | }
68 |
69 | dependencies {
70 |
71 | implementation fileTree(dir: "libs", include: ["*.jar","*.aar"])
72 | implementation 'androidx.core:core-ktx:1.7.0'
73 | implementation 'androidx.appcompat:appcompat:1.3.0'
74 | implementation 'com.google.android.material:material:1.4.0'
75 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
76 | testImplementation 'junit:junit:4.13.2'
77 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
78 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
79 |
80 | //全面屏适配
81 | implementation 'com.gyf.immersionbar:immersionbar:2.3.3'
82 | // fragment快速实现(可选)
83 | implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
84 | // kotlin扩展(可选)
85 | implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0'
86 |
87 | //高斯模糊控件
88 | implementation 'com.github.mmin18:realtimeblurview:1.2.1'
89 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
90 |
91 | // Retrofit 网络请求 https://github.com/square/retrofit
92 | implementation 'com.squareup.retrofit2:retrofit:2.9.0'
93 | implementation "com.squareup.okhttp3:logging-interceptor:4.9.2"
94 | implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
95 | implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
96 | implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
97 |
98 | //GSON
99 | implementation 'com.google.code.gson:gson:+'
100 |
101 | // Coroutine 协程 https://developer.android.google.cn/kotlin/coroutines
102 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2"
103 |
104 | // Koin 依赖注入 https://insert-koin.io
105 | implementation "io.insert-koin:koin-android:3.1.3"
106 |
107 | //WebSocket
108 | implementation 'org.java-websocket:Java-WebSocket:1.5.2'
109 |
110 | implementation 'me.itangqi.waveloadingview:library:0.3.5'
111 |
112 | implementation 'com.github.devlight:infinitecycleviewpager:1.0.2'
113 |
114 | implementation "androidx.viewpager2:viewpager2:1.0.0"
115 | }
--------------------------------------------------------------------------------
/app/kaly.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/kaly.jks
--------------------------------------------------------------------------------
/app/libs/Xpopup-release.aar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/libs/Xpopup-release.aar
--------------------------------------------------------------------------------
/app/libs/easyAdapter.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/libs/easyAdapter.jar
--------------------------------------------------------------------------------
/app/libs/glide.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/libs/glide.jar
--------------------------------------------------------------------------------
/app/libs/overscroll-release-v1.1-20160904.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/libs/overscroll-release-v1.1-20160904.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 | -keep class android.support.v8.renderscript.** { *; }
24 | -keep class androidx.renderscript.** { *; }
25 |
26 | -keep class androidx.recyclerview.widget.**{*;}
27 | -keep class androidx.viewpager2.widget.**{*;}
28 |
29 | -keep class com.pointer.wave.easyship.pojo.**{*;}
30 |
31 | -dontwarn com.lxj.xpopup.widget.**
32 | -keep class com.lxj.xpopup.widget.**{*;}
--------------------------------------------------------------------------------
/app/release_mini/output-metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 3,
3 | "artifactType": {
4 | "type": "APK",
5 | "kind": "Directory"
6 | },
7 | "applicationId": "com.pointer.wave.easyship",
8 | "variantName": "release_mini",
9 | "elements": [
10 | {
11 | "type": "SINGLE",
12 | "filters": [],
13 | "attributes": [],
14 | "versionCode": 22041122,
15 | "versionName": "1.0",
16 | "outputFile": "app-release_mini.apk"
17 | }
18 | ],
19 | "elementType": "File"
20 | }
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/pointer/wave/easyship/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.pointer.wave.easyship", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
11 |
13 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
70 |
71 |
75 |
76 |
77 |
78 |
79 |
80 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
97 |
98 |
103 |
104 |
109 |
112 |
113 |
114 |
117 |
118 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/app/src/main/assets/7za:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/assets/7za
--------------------------------------------------------------------------------
/app/src/main/assets/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | workdir=$(
3 | cd $(dirname $0)
4 | pwd
5 | )
6 | zipDir=$1
7 | rn=$2
8 |
9 | setprop persist.logd.size 8388608
10 |
11 | if [ ! -f "/data/7za" ]; then
12 | cp -r "$workdir"/7za /data
13 | chmod 777 /data/7za
14 | else
15 | chmod 777 /data/7za
16 | fi
17 |
18 | if [ ! -f "$zipDir"/update ]; then
19 | rm -rf "$zipDir"/update*
20 | fi
21 |
22 | echo "开始解析ROM"
23 | /data/7za x "$zipDir"/"$rn" -r -o"$zipDir"/update >/dev/null
24 | echo "解析完毕"
25 |
26 | if [ -f "$zipDir/update/payload.bin" ]; then
27 | echo "ROM核心文件校验成功"
28 | source "$zipDir"/update/payload_properties.txt
29 | update_engine_client --payload=file://"$zipDir"/update/payload.bin --update --headers="
30 | FILE_HASH=$FILE_HASH
31 | FILE_SIZE=$FILE_SIZE
32 | METADATA_HASH=$METADATA_HASH
33 | METADATA_SIZE=$METADATA_SIZE"
34 | logcat -s update_engine:v
35 | else
36 | echo "ROM核心文件校验失败,请检查ROM完整性!"
37 | fi
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/EasyShip.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Application;
5 | import android.content.Context;
6 |
7 | import com.pointer.wave.easyship.common.crash.CrashHandler;
8 | import com.pointer.wave.easyship.core.CacheDao;
9 | import com.pointer.wave.easyship.utils.KeepShellPublic;
10 | import com.pointer.wave.easyship.core.RealtimeProcess;
11 |
12 |
13 | public class EasyShip extends Application {
14 |
15 | @SuppressLint("StaticFieldLeak")
16 | public static Context context;
17 | public static CacheDao cacheDao;
18 | public static boolean isVab;
19 | private static RealtimeProcess process;
20 | private static RealtimeProcess.MSG msg;
21 |
22 | private CacheDao dao;
23 |
24 | @Override
25 | public void onCreate() {
26 | super.onCreate();
27 | setContext(this);
28 |
29 | dao = new CacheDao();
30 | new Thread(()->{
31 | //初始化Magisk的shell函数库
32 | String cmdSync = KeepShellPublic.INSTANCE.doCmdSync(". " + dao.getShellFilePath() + "/" + dao.lisName + "\n" +
33 | "mount_partitions\n");
34 | String[] split = cmdSync.split("\n");
35 | System.arraycopy(split, 0, info, 0, split.length);
36 | }).start();
37 | //异常捕获
38 | CrashHandler.init(this);
39 | isVab = isVAB();
40 | }
41 |
42 | public static RealtimeProcess getProcess() {
43 | return process;
44 | }
45 |
46 | public static void setProcess(RealtimeProcess process) {
47 | EasyShip.process = process;
48 | }
49 |
50 | public synchronized static RealtimeProcess.MSG getMsg() {
51 | return msg;
52 | }
53 |
54 | public synchronized static void setMsg(RealtimeProcess.MSG msg) {
55 | EasyShip.msg = msg;
56 | }
57 |
58 | public static Context getContext() {
59 | return context;
60 | }
61 |
62 | private void setContext(Context context) {
63 | EasyShip.context = context;
64 | }
65 |
66 | public static String[] info = new String[2];
67 | private boolean isVAB(){
68 | String cmdSync = KeepShellPublic.INSTANCE.doCmdSync("find /dev/block/ -type l -name boot_a");
69 | System.out.println("cmdSync = " + cmdSync);
70 | return cmdSync.split("\n").length > 1;
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import android.os.Build
6 | import android.os.Bundle
7 | import android.widget.Toast
8 | import androidx.fragment.app.Fragment
9 | import androidx.fragment.app.FragmentActivity
10 | import androidx.lifecycle.lifecycleScope
11 | import androidx.viewpager2.adapter.FragmentStateAdapter
12 | import androidx.viewpager2.widget.ViewPager2
13 | import com.google.gson.Gson
14 | import com.lxj.xpopup.XPopup
15 | import com.pointer.wave.easyship.common.activity.BaseActivity
16 | import com.pointer.wave.easyship.core.ZoomInTransformer
17 | import com.pointer.wave.easyship.fragments.AboutFragment
18 | import com.pointer.wave.easyship.fragments.HomeFragment
19 | import com.pointer.wave.easyship.net.repo.UpdateRepo
20 | import com.pointer.wave.easyship.pojo.VersionBen
21 | import com.pointer.wave.easyship.utils.AndroidInfo
22 | import com.pointer.wave.easyship.widget.NavigationBar
23 | import kotlinx.coroutines.flow.catch
24 | import kotlinx.coroutines.flow.launchIn
25 | import kotlinx.coroutines.flow.onEach
26 |
27 | class MainActivity : BaseActivity() {
28 |
29 | private var cancel = false
30 |
31 | override fun onCreate(savedInstanceState: Bundle?) {
32 | super.onCreate(savedInstanceState)
33 | setContentView(R.layout.activity_main)
34 |
35 | val fragments = listOf(HomeFragment(), AboutFragment())
36 |
37 | val adapter = ViewPagerAdapter(fragments, this)
38 | val pager = findViewById(R.id.pager).apply {
39 | setAdapter(adapter)
40 | //isUserInputEnabled = false
41 | }
42 |
43 | findViewById(R.id.main_navigation).apply {
44 | bindData(pager, arrayOf("开始", "关于"), intArrayOf(R.mipmap.ic_home, R.mipmap.ic_settings))
45 | setPositionListener { _, position ->
46 | pager.currentItem = position
47 | }
48 | }
49 | // FIXME: 2022/4/4 本来我是想 ViewPager 滑动的时候切换下面的 Tab,但是 Tab 上面那个有动画的 View 似乎没效果,我也不清楚应该怎么修复,就暂时禁用了
50 | }
51 |
52 | override fun onWindowFocusChanged(hasFocus: Boolean) {
53 | super.onWindowFocusChanged(hasFocus)
54 | if (hasFocus && !cancel) {
55 | cancel = true
56 | lifecycleScope.launchWhenResumed {
57 | UpdateRepo().update()
58 | .catch {
59 | it.printStackTrace()
60 | }
61 | .onEach {
62 | val gson = Gson()
63 | val versionBen = gson.fromJson(it.content, VersionBen::class.java)
64 | val androidInfo = AndroidInfo(this@MainActivity)
65 | if (versionBen.versionCode.toInt() > androidInfo.versionCode) {
66 | XPopup.Builder(this@MainActivity)
67 | .isDestroyOnDismiss(true)
68 | .asConfirm("有更新啦~", versionBen.updateContent, "知道了", "去更新", {
69 | val intent = Intent().apply {
70 | action = "android.intent.action.VIEW"
71 | data = Uri.parse(versionBen.downloadUrl)
72 | }
73 | startActivity(intent)
74 | }, null, false).show()
75 | }
76 | }
77 | .catch {
78 | it.printStackTrace()
79 | }.launchIn(lifecycleScope)
80 | }
81 | }
82 | }
83 |
84 | inner class ViewPagerAdapter(
85 | private val fragments: List,
86 | activity: FragmentActivity
87 | ) :
88 | FragmentStateAdapter(activity) {
89 | override fun getItemCount(): Int = fragments.size
90 |
91 | override fun createFragment(position: Int): Fragment = fragments[position]
92 | }
93 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/android/KeysInterpreter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.android;
10 |
11 | import android.view.KeyEvent;
12 |
13 | import com.pointer.wave.easyship.common.Language;
14 |
15 | /**
16 | * Interprets shortcut key combinations and contains utility methods
17 | * to map Android keycodes to Unicode equivalents.
18 | */
19 | public class KeysInterpreter {
20 | public static boolean isSwitchPanel(KeyEvent event){
21 | return (event.isShiftPressed() &&
22 | (event.getKeyCode() == KeyEvent.KEYCODE_ENTER));
23 | }
24 |
25 | /**
26 | * Maps shortcut keys and Android keycodes to printable characters.
27 | * Note that whitespace is considered printable.
28 | *
29 | * @param event The KeyEvent to interpret
30 | * @return The printable character the event represents,
31 | * or Language.NULL_CHAR if the event does not represent a printable char
32 | */
33 | public static char keyEventToPrintableChar(KeyEvent event){
34 | char c = Language.NULL_CHAR;
35 |
36 | // convert tab, backspace, newline and space keycodes to standard ASCII values
37 | if (isNewline(event)){
38 | c = Language.NEWLINE;
39 | }
40 | else if (isBackspace(event)){
41 | c = Language.BACKSPACE;
42 | }
43 | // This should be before the check for isSpace() because the
44 | // shortcut for TAB uses the SPACE key.
45 | else if (isTab(event)){
46 | c = Language.TAB;
47 | }
48 | else if (isSpace(event)){
49 | c = ' ';
50 | }
51 | else if (event.isPrintingKey()){
52 | c = (char) event.getUnicodeChar(event.getMetaState());
53 | }
54 |
55 | return c;
56 | }
57 |
58 | private static boolean isTab(KeyEvent event){
59 | return (event.isShiftPressed() &&
60 | (event.getKeyCode() == KeyEvent.KEYCODE_SPACE)) ||
61 | (event.getKeyCode() == KeyEvent.KEYCODE_TAB);
62 | }
63 |
64 | private static boolean isBackspace(KeyEvent event) {
65 | return (event.getKeyCode() == KeyEvent.KEYCODE_DEL);
66 | }
67 |
68 | private static boolean isNewline(KeyEvent event) {
69 | return (event.getKeyCode() == KeyEvent.KEYCODE_ENTER);
70 | }
71 |
72 | private static boolean isSpace(KeyEvent event) {
73 | return (event.getKeyCode() == KeyEvent.KEYCODE_SPACE);
74 | }
75 |
76 | public static boolean isNavigationKey(KeyEvent event) {
77 | int keyCode = event.getKeyCode();
78 | return keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
79 | keyCode == KeyEvent.KEYCODE_DPAD_UP ||
80 | keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
81 | keyCode == KeyEvent.KEYCODE_DPAD_LEFT;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/android/OnSelectionChangedListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.android;
10 |
11 | public interface OnSelectionChangedListener {
12 | void onSelectionChanged(boolean active, int selStart, int selEnd);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/android/TextChangeListener.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.android;
2 |
3 | public interface TextChangeListener
4 | {
5 |
6 | void onNewLine(String c, int _caretPosition, int p2);
7 |
8 | void onDel(CharSequence text, int _caretPosition, int newCursorPosition);
9 |
10 | void onAdd(CharSequence text, int _caretPosition, int newCursorPosition);
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/base/BaseFragment.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.base;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 |
8 | import androidx.annotation.LayoutRes;
9 | import androidx.annotation.NonNull;
10 | import androidx.annotation.Nullable;
11 | import androidx.fragment.app.Fragment;
12 |
13 | abstract public class BaseFragment extends Fragment {
14 |
15 | public BaseFragment(){
16 | super();
17 | }
18 |
19 | public BaseFragment(@LayoutRes int layoutId){
20 | super(layoutId);
21 | }
22 |
23 | private boolean firstResumed = false;
24 |
25 | @Nullable
26 | @Override
27 | public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
28 | View rootView = super.onCreateView(inflater,container,savedInstanceState);
29 | if(rootView == null){
30 | rootView = onCreateViewByReturn(inflater, container);
31 | }
32 | return rootView;
33 | }
34 |
35 | protected View onCreateViewByReturn(@NonNull LayoutInflater inflater, @Nullable ViewGroup container){
36 | return null;
37 | }
38 |
39 | @Override
40 | public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
41 | super.onViewCreated(view, savedInstanceState);
42 | initView(view);
43 | }
44 |
45 | @Override
46 | public void onDestroyView() {
47 | super.onDestroyView();
48 | firstResumed = false;
49 | }
50 |
51 | @Override
52 | public void onResume() {
53 | super.onResume();
54 | if(!firstResumed){
55 | firstResumed = true;
56 | loadSingleData();
57 | }
58 | loadData();
59 | }
60 |
61 | protected void initView(View root){}
62 |
63 | protected void loadSingleData(){}
64 |
65 | protected void loadData(){}
66 | }
67 |
68 |
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/ColorScheme.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 |
10 | package com.pointer.wave.easyship.common;
11 |
12 | import java.util.HashMap;
13 |
14 | public abstract class ColorScheme {
15 | public enum Colorable {
16 | FOREGROUND, BACKGROUND, SELECTION_FOREGROUND, SELECTION_BACKGROUND,
17 | CARET_FOREGROUND, CARET_BACKGROUND, CARET_DISABLED, LINE_HIGHLIGHT,
18 | NON_PRINTING_GLYPH, COMMENT, KEYWORD, NAME, NUMBER,STRING,
19 | SECONDARY,DATATYPE,YSF
20 | }
21 |
22 | protected HashMap _colors = generateDefaultColors();
23 |
24 | public void setColor(Colorable colorable, int color) {
25 | _colors.put(colorable, color);
26 | }
27 |
28 | public int getColor(Colorable colorable) {
29 | Integer color = _colors.get(colorable);
30 | if (color == null) {
31 | TextWarriorException.fail("Color not specified for " + colorable);
32 | return 0;
33 | }
34 | return color.intValue();
35 | }
36 |
37 | // Currently, color scheme is tightly coupled with semantics of the token types
38 | public int getTokenColor(int tokenType) {
39 | Colorable element;
40 | switch (tokenType) {
41 | case Lexer.NORMAL:
42 | element = Colorable.FOREGROUND;
43 | break;
44 | case Lexer.KEYWORD:
45 | element = Colorable.KEYWORD;
46 | break;
47 | case Lexer.NAME:
48 | element = Colorable.NAME;
49 | break;
50 | case Lexer.DOUBLE_SYMBOL_LINE: //fall-through
51 | case Lexer.DOUBLE_SYMBOL_DELIMITED_MULTILINE:
52 | //case Lexer.SINGLE_SYMBOL_LINE_B:
53 | element = Colorable.COMMENT;
54 | break;
55 | case Lexer.SINGLE_SYMBOL_DELIMITED_A: //fall-through
56 | case Lexer.SINGLE_SYMBOL_DELIMITED_B:
57 | element = Colorable.STRING;
58 | break;
59 | case Lexer.NUMBER:
60 | element = Colorable.NUMBER;
61 | break;
62 | case Lexer.SINGLE_SYMBOL_LINE_A: //fall-through
63 | case Lexer.SINGLE_SYMBOL_WORD:
64 | case Lexer.OPERATOR:
65 | element = Colorable.SECONDARY;
66 | break;
67 | case Lexer.SINGLE_SYMBOL_LINE_B: //类型
68 | element = Colorable.NAME;
69 | break;
70 | case Lexer.DATATYPE:
71 | element = Colorable.DATATYPE;
72 | break;
73 | case Lexer.YSF:
74 | element = Colorable.YSF;
75 | break;
76 | default:
77 | TextWarriorException.fail("Invalid token type");
78 | element = Colorable.FOREGROUND;
79 | break;
80 | }
81 | return getColor(element);
82 | }
83 |
84 | /**
85 | * Whether this color scheme uses a dark background, like black or dark grey.
86 | */
87 | public abstract boolean isDark();
88 |
89 | private HashMap generateDefaultColors() {
90 | // High-contrast, black-on-white color scheme
91 | HashMap colors = new HashMap(Colorable.values().length);
92 | colors.put(Colorable.FOREGROUND, 0xFF000000);//文本颜色
93 | colors.put(Colorable.BACKGROUND, 0xFFFFFFFF);//编辑器背景色
94 | colors.put(Colorable.SELECTION_FOREGROUND, 0xFFFFFFFF);//选择文本的前景色
95 | colors.put(Colorable.SELECTION_BACKGROUND, 0xFF999999);//选择文本的背景色
96 | colors.put(Colorable.CARET_FOREGROUND, 0xff0099cc);
97 | colors.put(Colorable.CARET_BACKGROUND, 0xFF40B0FF);//选择文本的水滴背景色
98 | colors.put(Colorable.CARET_DISABLED, 0xFF000000);
99 | colors.put(Colorable.LINE_HIGHLIGHT, 0x20888888);//当前行颜色
100 |
101 | colors.put(Colorable.NON_PRINTING_GLYPH, 0xffd0d0d0);//行号
102 | colors.put(Colorable.COMMENT, 0xff009b00); //注释
103 | colors.put(Colorable.KEYWORD, 0xff2c82c8); //关键字
104 | colors.put(Colorable.NAME, 0xff000000); // Eclipse default color
105 | colors.put(Colorable.NUMBER, 0xffbc0000); // 数字
106 | colors.put(Colorable.STRING, 0xffbc0000); //字符串
107 | colors.put(Colorable.SECONDARY, 0xff6f008a);//宏定义
108 | colors.put(Colorable.DATATYPE, 0xff0096ff);//数据类型
109 | colors.put(Colorable.YSF,0xff007c1f);//运算符
110 | return colors;
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/ColorSchemeDark.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 |
10 | package com.pointer.wave.easyship.common;
11 |
12 |
13 | public class ColorSchemeDark extends ColorScheme {
14 | @Override
15 | public boolean isDark() {
16 | return true;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/ColorSchemeLight.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 |
10 | package com.pointer.wave.easyship.common;
11 |
12 |
13 | /**
14 | * Off-black on off-white background color scheme
15 | */
16 | public class ColorSchemeLight extends ColorScheme {
17 | @Override
18 | public boolean isDark() {
19 | return false;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/Flag.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | public class Flag {
12 | private boolean state = false;
13 |
14 | synchronized public final void set(){
15 | state = true;
16 | }
17 |
18 | synchronized public final void clear(){
19 | state = false;
20 | }
21 |
22 | synchronized public final boolean isSet(){
23 | return state;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/JavaTokenTypes.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.common;
2 |
3 | public interface JavaTokenTypes {
4 | int TokenNameWHITESPACE=1;
5 | int TokenNameCOMMENT_LINE=2;
6 | int TokenNameCOMMENT_BLOCK=3;
7 | int TokenNameIdentifier=4;
8 | int TokenNameabstract=5;
9 | int TokenNameassert=6;
10 | int TokenNameboolean=7;
11 | int TokenNamebreak=8;
12 | int TokenNamebyte=9;
13 | int TokenNamecase=10;
14 | int TokenNamecatch=11;
15 | int TokenNamechar=12;
16 | int TokenNameclass=13;
17 | int TokenNamecontinue=14;
18 | int TokenNameconst=15;
19 | int TokenNamedefault=16;
20 | int TokenNamedo=17;
21 | int TokenNamedouble=18;
22 | int TokenNameelse=19;
23 | int TokenNameenum=20;
24 | int TokenNameextends=21;
25 | int TokenNamefalse=22;
26 | int TokenNamefinal=23;
27 | int TokenNamefinally=24;
28 | int TokenNamefloat=25;
29 | int TokenNamefor=26;
30 | int TokenNamegoto=27;
31 | int TokenNameif=28;
32 | int TokenNameimplements=29;
33 | int TokenNameimport=30;
34 | int TokenNameinstanceof=31;
35 | int TokenNameint=32;
36 | int TokenNameinterface=33;
37 | int TokenNamelong=34;
38 | int TokenNamenative=35;
39 | int TokenNamenew=36;
40 | int TokenNamenull=37;
41 | int TokenNamepackage=38;
42 | int TokenNameprivate=39;
43 | int TokenNameprotected=40;
44 | int TokenNamepublic=41;
45 | int TokenNamereturn=42;
46 | int TokenNameshort=43;
47 | int TokenNamestatic=44;
48 | int TokenNamestrictfp=45;
49 | int TokenNamesuper=46;
50 | int TokenNameswitch=47;
51 | int TokenNamesynchronized=48;
52 | int TokenNamethis=49;
53 | int TokenNamethrow=50;
54 | int TokenNamethrows=51;
55 | int TokenNametransient=52;
56 | int TokenNametrue=53;
57 | int TokenNametry=54;
58 | int TokenNamevoid=55;
59 | int TokenNamevolatile=56;
60 | int TokenNamewhile=57;
61 | int TokenNameIntegerLiteral=58;
62 | int TokenNameLongLiteral=59;
63 | int TokenNameFloatingPointLiteral=60;
64 | int TokenNameDoubleLiteral=61;
65 | int TokenNameCharacterLiteral=62;
66 | int TokenNameStringLiteral=63;
67 | int TokenNamePLUS_PLUS=64;
68 | int TokenNameMINUS_MINUS=65;
69 | int TokenNameEQUAL_EQUAL=66;
70 | int TokenNameLESS_EQUAL=67;
71 | int TokenNameGREATER_EQUAL=68;
72 | int TokenNameNOT_EQUAL=69;
73 | int TokenNameLEFT_SHIFT=70;
74 | int TokenNameRIGHT_SHIFT=71;
75 | int TokenNameUNSIGNED_RIGHT_SHIFT=72;
76 | int TokenNamePLUS_EQUAL=73;
77 | int TokenNameMINUS_EQUAL=74;
78 | int TokenNameMULTIPLY_EQUAL=75;
79 | int TokenNameDIVIDE_EQUAL=76;
80 | int TokenNameAND_EQUAL=77;
81 | int TokenNameOR_EQUAL=78;
82 | int TokenNameXOR_EQUAL=79;
83 | int TokenNameREMAINDER_EQUAL=80;
84 | int TokenNameLEFT_SHIFT_EQUAL=81;
85 | int TokenNameRIGHT_SHIFT_EQUAL=82;
86 | int TokenNameUNSIGNED_RIGHT_SHIFT_EQUAL=83;
87 | int TokenNameOR_OR=84;
88 | int TokenNameAND_AND=85;
89 | int TokenNamePLUS=86;
90 | int TokenNameMINUS=87;
91 | int TokenNameNOT=88;
92 | int TokenNameREMAINDER=89;
93 | int TokenNameXOR=90;
94 | int TokenNameAND=91;
95 | int TokenNameMULTIPLY=92;
96 | int TokenNameOR=93;
97 | int TokenNameTWIDDLE=94;
98 | int TokenNameDIVIDE=95;
99 | int TokenNameGREATER=96;
100 | int TokenNameLESS=97;
101 | int TokenNameLPAREN=98;
102 | int TokenNameRPAREN=99;
103 | int TokenNameLBRACE=100;
104 | int TokenNameRBRACE=101;
105 | int TokenNameLBRACKET=102;
106 | int TokenNameRBRACKET=103;
107 | int TokenNameSEMICOLON=404;
108 | int TokenNameQUESTION=105;
109 | int TokenNameCOLON=106;
110 | int TokenNameCOMMA=107;
111 | int TokenNameDOT=108;
112 | int TokenNameEQUAL=109;
113 | int TokenNameAT=110;
114 | int TokenNameELLIPSIS=113;
115 | int TokenNameARROW=114;
116 | int TokenNameCOLON_COLON=115;
117 | int TokenNameEOF=116;
118 | int TokenNameERROR=117;
119 | }
120 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/LanguageCFamily.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | import java.util.HashMap;
12 |
13 | /**
14 | * Singleton class containing C-like symbols and operators but no keywords
15 | */
16 | public abstract class LanguageCFamily
17 | {
18 | public final static char EOF = '\uFFFF';
19 | public final static char NULL_CHAR = '\u0000';
20 | public final static char NEWLINE = '\n';
21 | public final static char BACKSPACE = '\b';
22 | public final static char TAB = '\t';
23 |
24 | protected HashMap _keywords;
25 | protected HashMap _operators;
26 |
27 | private final static char[] basic_c_operators = {
28 | '(', ')', '{', '}', '.', ',', ';', '=', '+', '-',
29 | '/', '*', '&', '!', '|', ':', '[', ']', '<', '>',
30 | '?', '~', '%', '^'
31 | };
32 |
33 | { replaceOperators(basic_c_operators); }
34 |
35 |
36 | protected void registerKeywords(String[] keywords)
37 | {
38 | _keywords = new HashMap(keywords.length);
39 | for (int i = 0; i < keywords.length; ++i)
40 | {
41 | _keywords.put(keywords[i], new Integer(Lexer.KEYWORD));
42 | }
43 | }
44 |
45 | protected void replaceOperators(char[] operators)
46 | {
47 | _operators = new HashMap(operators.length);
48 | for (int i = 0; i < operators.length; ++i)
49 | {
50 | _operators.put(new Character(operators[i]), new Integer(Lexer.OPERATOR));
51 | }
52 | }
53 |
54 | public final boolean isOperator(char c)
55 | {
56 | return _operators.containsKey(new Character(c));
57 | }
58 |
59 | public final boolean isKeyword(String s)
60 | {
61 | return _keywords.containsKey(s);
62 | }
63 |
64 | public boolean isWhitespace(char c)
65 | {
66 | return (c == ' ' || c == '\n' || c == '\t' ||
67 | c == '\r' || c == '\f' || c == EOF);
68 | }
69 |
70 | public boolean isSentenceTerminator(char c)
71 | {
72 | return (c == '.');
73 | }
74 |
75 | public boolean isEscapeChar(char c)
76 | {
77 | return (c == '\\');
78 | }
79 |
80 | /**
81 | * Derived classes that do not do represent C-like programming languages
82 | * should return false; otherwise return true
83 | */
84 | public boolean isProgLang()
85 | {
86 | return true;
87 | }
88 |
89 | /**
90 | * Whether the word after c is a token
91 | */
92 | public boolean isWordStart(char c)
93 | {
94 | return false;
95 | }
96 |
97 | /**
98 | * Whether cSc is a token, where S is a sequence of characters that are on the same line
99 | */
100 | public boolean isDelimiterA(char c)
101 | {
102 | return (c == '"');
103 | }
104 |
105 | /**
106 | * Same concept as isDelimiterA(char), but Language and its subclasses can
107 | * specify a second type of symbol to use here
108 | */
109 | public boolean isDelimiterB(char c)
110 | {
111 | return (c == '\'');
112 | }
113 |
114 | /**
115 | * Whether cL is a token, where L is a sequence of characters until the end of the line
116 | */
117 | public boolean isLineAStart(char c)
118 | {
119 | return (c == '#');
120 | }
121 |
122 | /**
123 | * Same concept as isLineAStart(char), but Language and its subclasses can
124 | * specify a second type of symbol to use here
125 | */
126 | public boolean isLineBStart(char c)
127 | {
128 | return false;
129 | }
130 |
131 | /**
132 | * Whether c0c1L is a token, where L is a sequence of characters until the end of the line
133 | */
134 | public boolean isLineStart(char c0, char c1)
135 | {
136 | return (c0 == '/' && c1 == '/');
137 | }
138 |
139 | /**
140 | * Whether c0c1 signifies the start of a multi-line token
141 | */
142 | public boolean isMultilineStartDelimiter(char c0, char c1)
143 | {
144 | return (c0 == '/' && c1 == '*');
145 | }
146 |
147 | /**
148 | * Whether c0c1 signifies the end of a multi-line token
149 | */
150 | public boolean isMultilineEndDelimiter(char c0, char c1)
151 | {
152 | return (c0 == '*' && c1 == '/');
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/LanguageJava.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided"as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | /**
12 | * Singleton class containing the symbols and operators of the Java language
13 | */
14 | public class LanguageJava extends Language {
15 | private static Language _theOne = null;
16 |
17 | private final static String[] keywords = {
18 |
19 | };
20 |
21 | private final static String[] function = {
22 | "r.TCQualityGrade", "foliage.MinLOD","foliage.LODDistanceScale","+CVars=","r.PUBGDeviceFPSLow","r.PUBGDeviceFPSMid","r.PUBGDeviceFPSHigh","r.PUBGDeviceFPSHDR","r.UserVulkanSetting","r.PUBGQualityLevel","r.PUBGMaxSupportQualityLevel","r.PUBGMSAASupport","r.PUBGLDR","r.PUBGCRLRuntmieMinMem","r.PUBGRenderSwitch","r.PUBGLimit","r.PUBGVersion","r.MobileContentScaleFactor","r.Mobile.TonemapperFilm","r.Mobile.AlwaysResolveDepth","r.MobileMSAA","r.Mobile.ForceDepthResolve","r.Mobile.TextureMipmapBias","r.MobileSimpleShader","r.MobileNumDynamicPointLights","r.Mobile.EarlyZPass","r.Mobile.SceneColorFormat","r.UserQualitySetting","r.UserHDRSetting","r.UseProgramBinaryCache","r.UseShaderPrecompileCount","r.UseShaderPrecompileMemLimit","r.UserMSAASetting","r.ShadowQuality","r.Shadow.MaxCSMResolution","r.Shadow.CSM.MaxMobileCascades","r.Shadow.DistanceScale","r.MetalVertexParameterSize","r.MetalPixelParameterSize","r.MetalComputeParameterSize","r.MaterialQualityLevel","r.BinningControlHintQCOMDriver","r.BinningControlHintQCOM","r.Android.DisableVulkanSupport","r.Android.DisableOpenGLES31Support","r.ACESStyle","r.BloomQuality","r.DefaultFeature.AntiAliasing","r.Decal.StencilSizeThreshold","r.DepthOfFieldQuality","r.DetailMode","r.EmitterSpawnRateScale","r.LightShaftQuality","r.MSAACount","r.MaxAnisotropy","r.NumBufferedOcclusionQueries","r.ParticleLODBias","r.RefractionQuality","r.StaticMeshLODDistanceScale","r.StaticMeshLODLevelLimited","r.Streaming.PoolSize","r.TextureStreaming","r.TagCullingSupport"
23 | };
24 |
25 | private final static char[] BASIC_C_OPERATORS = {
26 | '(', ')', '{', '}', '.', ',', ';', '=', '+', '-',
27 | '/', '*', '&', '!', '|', ':', '[', ']', '<', '>',
28 | '?', '~', '%', '^'
29 | };
30 |
31 | public static Language getInstance() {
32 | if (_theOne == null) {
33 | _theOne = new LanguageJava();
34 | }
35 | return _theOne;
36 | }
37 |
38 | private LanguageJava() {
39 | updateUserWord();
40 | setOperators(BASIC_C_OPERATORS);
41 | setKeywords(keywords);
42 | setNames(function);
43 | }
44 |
45 | /**
46 | * Java has no preprocessors. Override base class implementation
47 | */
48 | public boolean isLineAStart(char c) {
49 | return false;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/LanguageNonProg.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | /**
12 | * Singleton class that represents a non-programming language without keywords,
13 | * operators etc.
14 | */
15 | public class LanguageNonProg extends Language{
16 | private static Language _theOne = null;
17 |
18 | private final static String[] keywords = {};
19 |
20 | private final static char[] operators = {};
21 |
22 |
23 | public static Language getInstance(){
24 | if(_theOne == null){
25 | _theOne = new LanguageNonProg();
26 | }
27 | return _theOne;
28 | }
29 |
30 | private LanguageNonProg(){
31 | super.setKeywords(keywords);
32 | super.setOperators(operators);
33 | }
34 |
35 | @Override
36 | public boolean isProgLang(){
37 | return false;
38 | }
39 |
40 | @Override
41 | public boolean isEscapeChar(char c){
42 | return false;
43 | }
44 |
45 | @Override
46 | public boolean isDelimiterA(char c){
47 | return false;
48 | }
49 |
50 | @Override
51 | public boolean isDelimiterB(char c){
52 | return false;
53 | }
54 |
55 | @Override
56 | public boolean isLineAStart(char c){
57 | return false;
58 | }
59 |
60 | @Override
61 | public boolean isLineStart(char c0, char c1){
62 | return false;
63 | }
64 |
65 | @Override
66 | public boolean isMultilineStartDelimiter(char c0, char c1){
67 | return false;
68 | }
69 |
70 | @Override
71 | public boolean isMultilineEndDelimiter(char c0, char c1){
72 | return false;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/LinearSearchStrategy.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.common;
2 |
3 | public class LinearSearchStrategy implements SearchStrategy {
4 | private int _unitsDone = 0;
5 |
6 | public LinearSearchStrategy() {
7 | }
8 |
9 | protected boolean equals(DocumentProvider var1, String var2, int var3, boolean var4) {
10 | if (var1.docLength() - var3 < var2.length()) {
11 | var4 = false;
12 | } else {
13 | int var5 = 0;
14 |
15 | while(true) {
16 | if (var5 >= var2.length()) {
17 | var4 = true;
18 | break;
19 | }
20 |
21 | if (var4 && var2.charAt(var5) != var1.charAt(var5 + var3)) {
22 | var4 = false;
23 | break;
24 | }
25 |
26 | if (!var4 && Character.toLowerCase(var2.charAt(var5)) != Character.toLowerCase(var1.charAt(var5 + var3))) {
27 | var4 = false;
28 | break;
29 | }
30 |
31 | ++var5;
32 | }
33 | }
34 |
35 | return var4;
36 | }
37 |
38 | @Override
39 | public int find(DocumentProvider var1, String var2, int var3, int var4, boolean var5, boolean var6) {
40 | int var7 = var3;
41 | if (var2.length() == 0) {
42 | var3 = -1;
43 | } else {
44 | var3 = var3;
45 | if (var7 < 0) {
46 | TextWarriorException.fail("TextBuffer.find: Invalid start position");
47 | var3 = 0;
48 | }
49 |
50 | var7 = var4;
51 | if (var4 > var1.docLength()) {
52 | TextWarriorException.fail("TextBuffer.find: Invalid end position");
53 | var7 = var1.docLength();
54 | }
55 |
56 | for(var4 = Math.min(var7, var1.docLength() - var2.length() + 1); var3 < var4 && (!this.equals(var1, var2, var3, var5) || var6 && !this.isSandwichedByWhitespace(var1, var3, var2.length())); ++this._unitsDone) {
57 | ++var3;
58 | }
59 |
60 | if (var3 >= var4) {
61 | var3 = -1;
62 | }
63 | }
64 |
65 | return var3;
66 | }
67 |
68 | @Override
69 | public int findBackwards(DocumentProvider var1, String var2, int var3, int var4, boolean var5, boolean var6) {
70 | int var7 = var3;
71 | var3 = var4;
72 | if (var2.length() == 0) {
73 | var3 = -1;
74 | } else {
75 | int var8 = var7;
76 | if (var7 >= var1.docLength()) {
77 | TextWarriorException.fail("Invalid start position given to TextBuffer.find");
78 | var8 = var1.docLength() - 1;
79 | }
80 |
81 | var4 = var4;
82 | if (var3 < -1) {
83 | TextWarriorException.fail("Invalid end position given to TextBuffer.find");
84 | var4 = -1;
85 | }
86 |
87 | for(var3 = Math.min(var8, var1.docLength() - var2.length()); var3 > var4 && (!this.equals(var1, var2, var3, var5) || var6 && !this.isSandwichedByWhitespace(var1, var3, var2.length())); --var3) {
88 | }
89 |
90 | if (var3 <= var4) {
91 | var3 = -1;
92 | }
93 | }
94 |
95 | return var3;
96 | }
97 |
98 | @Override
99 | public int getProgress() {
100 | return this._unitsDone;
101 | }
102 |
103 | protected boolean isSandwichedByWhitespace(DocumentProvider var1, int var2, int var3) {
104 | Language var4 = Lexer.getLanguage();
105 | boolean var5;
106 | if (var2 == 0) {
107 | var5 = true;
108 | } else {
109 | var5 = var4.isWhitespace(var1.charAt(var2 - 1));
110 | }
111 |
112 | var2 += var3;
113 | boolean var6;
114 | if (var2 == var1.docLength()) {
115 | var6 = true;
116 | } else {
117 | var6 = var4.isWhitespace(var1.charAt(var2));
118 | }
119 |
120 | if (var5 && var6) {
121 | var5 = true;
122 | } else {
123 | var5 = false;
124 | }
125 |
126 | return var5;
127 | }
128 |
129 | @Override
130 | public Pair replaceAll(DocumentProvider var1, String var2, String var3, int var4, boolean var5, boolean var6) {
131 | int var7 = 0;
132 | int var8 = var4;
133 | this._unitsDone = 0;
134 | char[] var9 = var3.toCharArray();
135 | var4 = this.find(var1, var2, 0, var1.docLength(), var5, var6);
136 | long var10 = System.nanoTime();
137 | var1.beginBatchEdit();
138 |
139 | while(var4 != -1) {
140 | var1.deleteAt(var4, var2.length(), var10);
141 | var1.insertBefore(var9, var4, var10);
142 | int var12 = var8;
143 | if (var4 < var8) {
144 | var12 = var8 + (var3.length() - var2.length());
145 | }
146 |
147 | ++var7;
148 | this._unitsDone += var2.length();
149 | var4 = this.find(var1, var2, var4 + var3.length(), var1.docLength(), var5, var6);
150 | var8 = var12;
151 | }
152 |
153 | var1.endBatchEdit();
154 | return new Pair(var7, Math.max(var8, 0));
155 | }
156 |
157 | @Override
158 | public int wrappedFind(DocumentProvider var1, String var2, int var3, boolean var4, boolean var5) {
159 | int var6 = this.find(var1, var2, var3, var1.docLength(), var4, var5);
160 | int var7 = var6;
161 | if (var6 < 0) {
162 | var7 = this.find(var1, var2, 0, var3, var4, var5);
163 | }
164 |
165 | return var7;
166 | }
167 |
168 | @Override
169 | public int wrappedFindBackwards(DocumentProvider var1, String var2, int var3, boolean var4, boolean var5) {
170 | int var6 = this.findBackwards(var1, var2, var3, -1, var4, var5);
171 | int var7 = var6;
172 | if (var6 < 0) {
173 | var7 = this.findBackwards(var1, var2, var1.docLength() - 1, var3, var4, var5);
174 | }
175 |
176 | return var7;
177 | }
178 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/Pair.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | public final class Pair {
12 | private int _first;
13 | private int _second;
14 |
15 | public Pair(int x, int y){
16 | _first = x;
17 | _second = y;
18 | }
19 |
20 | public final int getFirst(){
21 | return _first;
22 | }
23 |
24 | public final int getSecond(){
25 | return _second;
26 | }
27 |
28 | public final void setFirst(int value){
29 | _first = value;
30 | }
31 |
32 | public final void setSecond(int value){
33 | _second = value;
34 | }
35 |
36 | @Override
37 | public String toString() {
38 | return "("+_first+","+_second+")";
39 | }
40 | }
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/ProgressObserver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | /**
12 | * Can be registered with a {@link ProgressSource} of interest, which will cause
13 | * progress updates to be sent to the ProgressObserver.
14 | */
15 | public interface ProgressObserver {
16 | void onComplete(int requestCode, Object result);
17 |
18 | void onError(int requestCode, int errorCode, String message);
19 |
20 | void onCancel(int requestCode);
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/ProgressSource.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2011 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | /**
12 | * Represents tasks that carry out long computations
13 | */
14 | public interface ProgressSource {
15 | /* Nature of computation tasks */
16 | int NONE = 0;
17 | int READ = 1;
18 | int WRITE = 2;
19 | int FIND = 4;
20 | int FIND_BACKWARDS = 8;
21 | int REPLACE_ALL = 16;
22 | int ANALYZE_TEXT = 32;
23 | /* Error codes */
24 | int ERROR_UNKNOWN = 0;
25 | int ERROR_OUT_OF_MEMORY = 1;
26 | int ERROR_INDEX_OUT_OF_RANGE = 2;
27 |
28 | /** Minimum progress value */
29 | int getMin();
30 |
31 | /** Maximum progress value */
32 | int getMax();
33 |
34 | /** Current progress value */
35 | int getCurrent();
36 |
37 | /** Whether computation is done */
38 | boolean isDone();
39 |
40 | /** Aborts computation */
41 | void forceStop();
42 |
43 | /** Registers observers that will be informed of changes to the progress state */
44 | void registerObserver(ProgressObserver obsv);
45 |
46 | /** Removes all attached observers */
47 | void removeObservers();
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/ReadThread.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.common;
2 |
3 | import android.os.Handler;
4 | import android.os.Message;
5 |
6 | import java.io.FileInputStream;
7 | import java.io.IOException;
8 | import java.io.InputStreamReader;
9 | import java.nio.charset.StandardCharsets;
10 |
11 | /**
12 | * Created by zyw on 2017/10/2.
13 | */
14 | public class ReadThread extends Thread
15 | {
16 | public static final int MSG_READ_OK =0x101;
17 | public static final int MSG_READ_FAIL =0x102;
18 | private Handler handler;
19 | private String path;
20 | public ReadThread(String path, Handler handler)
21 | {
22 | this.path=path;
23 | this.handler=handler;
24 | }
25 | @Override
26 | public void run() {
27 | synchronized (handler) {
28 | readFile(path);
29 | }
30 | }
31 |
32 | private void readFile(String file)
33 | {
34 | boolean isOk=false;
35 | FileInputStream fileInputStream = null;
36 | InputStreamReader inputStreamReader=null;
37 | StringBuilder stringBuilder=new StringBuilder();
38 | try {
39 | fileInputStream=new FileInputStream(file);
40 | inputStreamReader = new InputStreamReader(fileInputStream, StandardCharsets.UTF_8);
41 | char[] buf=new char[1024];
42 | int len=0;
43 | while ((len=inputStreamReader.read(buf))!=-1){
44 | stringBuilder.append(new String(buf,0,len));
45 | }
46 | isOk=true;
47 |
48 | } catch (IOException e) {
49 | e.printStackTrace();
50 | isOk=false;
51 | }finally {
52 | if(inputStreamReader!=null)
53 | {
54 | try {
55 | inputStreamReader.close();
56 | } catch (IOException e) {
57 | e.printStackTrace();
58 | }
59 | }
60 | }
61 | if(isOk)
62 | {
63 | if(handler!=null)
64 | handler.sendMessage(Message.obtain(handler, MSG_READ_OK,stringBuilder.toString()));
65 | }else
66 | {
67 | if(handler!=null)
68 | handler.sendMessage(Message.obtain(handler, MSG_READ_FAIL));
69 | }
70 |
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/RowListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | public interface RowListener {
12 | void onRowChange(int newRowIndex);
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/SearchStrategy.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.common;
2 |
3 | public interface SearchStrategy {
4 | int find(DocumentProvider var1, String var2, int var3, int var4, boolean var5, boolean var6);
5 |
6 | int findBackwards(DocumentProvider var1, String var2, int var3, int var4, boolean var5, boolean var6);
7 |
8 | int getProgress();
9 |
10 | Pair replaceAll(DocumentProvider var1, String var2, String var3, int var4, boolean var5, boolean var6);
11 |
12 | int wrappedFind(DocumentProvider var1, String var2, int var3, boolean var4, boolean var5);
13 |
14 | int wrappedFindBackwards(DocumentProvider var1, String var2, int var3, boolean var4, boolean var5);
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/TextBufferCache.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | /**
12 | * A LRU cache that stores the last seek line and its corresponding index so
13 | * that future lookups can start from the cached position instead of
14 | * the beginning of the file
15 | *
16 | * _cache.Pair.First = line index
17 | * _cache.Pair.Second = character offset of first character in that line
18 | *
19 | * TextBufferCache always has one valid entry (0,0) signifying that in line 0,
20 | * the first character is at offset 0. This is true even for an "empty" file,
21 | * which is not really empty because TextBuffer inserts a EOF character in it.
22 | *
23 | * Therefore, _cache[0] is always occupied by the entry (0,0). It is not affected
24 | * by invalidateCache, cache miss, etc. operations
25 | */
26 | public class TextBufferCache {
27 | private static final int CACHE_SIZE = 4; // minimum = 1
28 | private Pair[] _cache = new Pair[CACHE_SIZE];
29 |
30 | public TextBufferCache(){
31 | _cache[0] = new Pair(0, 0); // invariant lineIndex and charOffset relation
32 | for (int i = 1; i < CACHE_SIZE; ++i){
33 | _cache[i] = new Pair(-1, -1);
34 | // -1 line index is used implicitly in calculations in getNearestMatch
35 | }
36 | }
37 |
38 | //TODO consider extracting common parts with getNearestCharOffset(int)
39 | public Pair getNearestLine(int lineIndex){
40 | int nearestMatch = 0;
41 | int nearestDistance = Integer.MAX_VALUE;
42 | for(int i = 0; i < CACHE_SIZE; ++i){
43 | int distance = Math.abs(lineIndex - _cache[i].getFirst());
44 | if (distance < nearestDistance){
45 | nearestDistance = distance;
46 | nearestMatch = i;
47 | }
48 | }
49 |
50 | Pair nearestEntry = _cache[nearestMatch];
51 | makeHead(nearestMatch);
52 | return nearestEntry;
53 | }
54 |
55 | public Pair getNearestCharOffset(int charOffset){
56 | int nearestMatch = 0;
57 | int nearestDistance = Integer.MAX_VALUE;
58 | for(int i = 0; i < CACHE_SIZE; ++i){
59 | int distance = Math.abs(charOffset - _cache[i].getSecond());
60 | if (distance < nearestDistance){
61 | nearestDistance = distance;
62 | nearestMatch = i;
63 | }
64 | }
65 |
66 | Pair nearestEntry = _cache[nearestMatch];
67 | makeHead(nearestMatch);
68 | return nearestEntry;
69 | }
70 |
71 | /**
72 | * Place _cache[newHead] at the top of the list
73 | */
74 | private void makeHead(int newHead){
75 | if(newHead == 0){
76 | return;
77 | }
78 |
79 | Pair temp = _cache[newHead];
80 | for(int i = newHead; i > 1; --i){
81 | _cache[i] = _cache[i-1];
82 | }
83 | _cache[1] = temp; // _cache[0] is always occupied by (0,0)
84 | }
85 |
86 | public void updateEntry(int lineIndex, int charOffset){
87 | if(lineIndex <= 0){
88 | // lineIndex 0 always has 0 charOffset; ignore. Also ignore negative lineIndex
89 | return;
90 | }
91 |
92 | if(!replaceEntry(lineIndex, charOffset)){
93 | insertEntry(lineIndex, charOffset);
94 | }
95 | }
96 |
97 | private boolean replaceEntry(int lineIndex, int charOffset){
98 | for (int i = 1; i < CACHE_SIZE; ++i){
99 | if(_cache[i].getFirst() == lineIndex){
100 | _cache[i].setSecond(charOffset);
101 | return true;
102 | }
103 | }
104 | return false;
105 | }
106 |
107 | private void insertEntry(int lineIndex, int charOffset){
108 | makeHead(CACHE_SIZE-1); // rotate right list of entries
109 | // replace head (most recently used entry) with new entry
110 | _cache[1] = new Pair(lineIndex, charOffset);
111 | }
112 |
113 | /**
114 | * Invalidate all cache entries that have char offset >= fromCharOffset
115 | */
116 | final protected void invalidateCache(int fromCharOffset){
117 | for (int i = 1; i < CACHE_SIZE; ++i){
118 | if(_cache[i].getSecond() >= fromCharOffset){
119 | _cache[i] = new Pair(-1, -1);
120 | }
121 | }
122 | }
123 | }
124 |
125 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/TextWarriorException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2013 Tah Wei Hoon.
3 | * All rights reserved. This program and the accompanying materials
4 | * are made available under the terms of the Apache License Version 2.0,
5 | * with full text available at http://www.apache.org/licenses/LICENSE-2.0.html
6 | *
7 | * This software is provided "as is". Use at your own risk.
8 | */
9 | package com.pointer.wave.easyship.common;
10 |
11 | import android.util.Log;
12 |
13 | public class TextWarriorException extends Exception {
14 | private static final boolean NDEBUG = false; // set to true to suppress assertions
15 | private static final long serialVersionUID = -8393914265675038931L;
16 |
17 | public TextWarriorException(String msg){
18 | super(msg);
19 | }
20 |
21 | static public void fail(final String details){
22 | assertVerbose(false, details);
23 | }
24 |
25 | @SuppressWarnings("all") //suppress dead code warning when NDEBUG == true
26 | static public void assertVerbose(boolean condition, final String details){
27 | if(NDEBUG){
28 | return;
29 | }
30 |
31 | if (!condition){
32 | /* BlackBerry dialog way of displaying errors
33 | UiApplication.getUiApplication().invokeLater(new Runnable()
34 | {
35 | public void run()
36 | {
37 | Dialog.alert(details);
38 | }
39 | });
40 | */
41 |
42 | /* For Android, a Context has to be passed into this method
43 | * to display the error message on the device screen */
44 |
45 | System.err.print("TextWarrior assertion failed: ");
46 | System.err.println(details);
47 | Log.d("lua",details);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/common/WriteThread.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.common;
2 |
3 | import android.os.Handler;
4 | import android.os.Message;
5 |
6 | import java.io.File;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.io.OutputStreamWriter;
10 | import java.nio.charset.StandardCharsets;
11 |
12 | /**
13 | * Created by zyw on 2017/10/2.
14 | */
15 | public class WriteThread extends Thread {
16 |
17 | public static final int MSG_WRITE_OK =0x201;
18 | public static final int MSG_WRITE_FAIL =0x202;
19 | private Handler handler;
20 | private String outputPath;
21 | private String text;
22 | public WriteThread(String text,String outputPath, Handler handler)
23 | {
24 | this.outputPath=outputPath;
25 | this.text=text;
26 | this.handler=handler;
27 | }
28 | @Override
29 | public void run() {
30 |
31 | synchronized (handler) {
32 | writeFile(text, new File(outputPath));
33 | }
34 |
35 | }
36 |
37 | /**
38 | * 写文件
39 | * @param text
40 | * @param outputFile
41 | * @throws IOException
42 | */
43 | private void writeFile( final String text,File outputFile) {
44 | boolean isOk=false;
45 | if(!outputFile.getParentFile().exists())
46 | outputFile.getParentFile().mkdirs();
47 | FileOutputStream fileOutputStream=null;
48 | OutputStreamWriter outputStreamWriter=null;
49 | try {
50 | fileOutputStream=new FileOutputStream(outputFile);
51 | outputStreamWriter = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8);
52 | outputStreamWriter.write(text);
53 | outputStreamWriter.flush();
54 | isOk=true;
55 | }catch (IOException e){
56 | e.printStackTrace();
57 | isOk=false;
58 |
59 | }finally {
60 | if(outputStreamWriter!=null)
61 | try {
62 | outputStreamWriter.close();
63 | } catch (IOException e) {
64 | e.printStackTrace();
65 | }
66 | }
67 | if(isOk) {
68 | if (handler != null)
69 | handler.sendMessage(Message.obtain(handler, MSG_WRITE_OK));
70 | }
71 | else
72 | {
73 | if(handler!=null)
74 | handler.sendMessage(Message.obtain(handler, MSG_WRITE_FAIL));
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/core/LoadShellUtil.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.core;
2 |
3 | import android.content.Context;
4 |
5 | import java.io.File;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 |
10 | public class LoadShellUtil {
11 |
12 | public final Context context;
13 | public String _sh = "";
14 | public final String workFolder;
15 | public final String shellName = "run.sh";
16 | public final String shell2Name = "run.sh";
17 | public final String _7zaName = "7za";
18 |
19 | public LoadShellUtil(Context context){
20 | this.context = context;
21 | workFolder = this.context.getFilesDir().getPath() + "/work";
22 | }
23 |
24 | public void moveResources(){
25 | copy(shellName);
26 | //copy(shell2Name);
27 | copy(_7zaName);
28 | }
29 |
30 | public void remove(){
31 | File file = new File(workFolder);
32 | file.delete();
33 | }
34 |
35 | private boolean copy(String filename){
36 | File flFile = new File(workFolder);
37 | if (!flFile.exists()) {
38 | flFile.mkdirs();
39 | }
40 | boolean isCopysucss = false;
41 | try {
42 | InputStream is = this.context.getAssets().open(filename);//从assets文件夹中复制文件
43 | File file = new File(workFolder + "/" + filename);
44 | FileOutputStream fos = new FileOutputStream(file);
45 | byte[] buffer = new byte[1024];
46 | int byteCount;
47 | while ((byteCount = is.read(buffer)) != -1) {
48 | fos.write(buffer, 0, byteCount);
49 | }
50 | fos.flush();
51 | fos.close();
52 | is.close();
53 | isCopysucss = true;
54 | } catch (IOException e) {
55 | e.printStackTrace();
56 | }
57 | return isCopysucss;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/core/RealtimeProcess.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.core;
2 |
3 | import com.pointer.wave.easyship.core.CacheDao;
4 | import com.pointer.wave.easyship.interfaces.RealtimeProcessInterface;
5 |
6 | import java.io.BufferedReader;
7 | import java.io.DataOutputStream;
8 | import java.io.File;
9 | import java.io.IOException;
10 | import java.io.InputStreamReader;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.Random;
14 |
15 |
16 | public class RealtimeProcess{
17 | // 是否在执行
18 | private boolean isRunning = false;
19 | // 存放命令行
20 | private ArrayList commandList = new ArrayList<>();
21 | // 保存所有的输出信息
22 | private StringBuffer mStringBuffer = new StringBuffer();
23 | private BufferedReader readStdout = null;
24 | private BufferedReader readStderr = null;
25 | // 回调用到的接口
26 | private RealtimeProcessInterface mInterface;
27 | private int resultCode = 0;
28 | private String ROOT_DIR = null;
29 | private String tmp1 = null;
30 | private String tmp2 = null;
31 | private final MSG msg;
32 | private final ErrorMSG errorMSG;
33 |
34 | public MSG getMsg() {
35 | return msg;
36 | }
37 |
38 | public ErrorMSG getErrorMSG() {
39 | return errorMSG;
40 | }
41 |
42 | public RealtimeProcess(RealtimeProcessInterface mInterface){
43 | // 实例化接口对象
44 | this.mInterface = mInterface;
45 | this.errorMSG = new ErrorMSG();
46 | this.msg = new MSG();
47 | }
48 | public void setCommand(String ...commands){
49 | // 遍历命令
50 | for(String cmd : commands){
51 | RealtimeProcessCommand mRealtimeProcessCommand = new RealtimeProcessCommand();
52 | mRealtimeProcessCommand.setCommand(cmd);
53 | commandList.add(mRealtimeProcessCommand);
54 | }
55 | }
56 | public void setDirectory(String directory){
57 | this.ROOT_DIR = directory;
58 | }
59 |
60 | public void start() throws IOException, InterruptedException{
61 | isRunning = true;
62 | Process p = Runtime.getRuntime().exec("su");
63 | DataOutputStream write = new DataOutputStream(p.getOutputStream());
64 | for(RealtimeProcessCommand mRealtimeProcessCommand : commandList){
65 | write.writeBytes(mRealtimeProcessCommand.getCommand());
66 | write.writeBytes("\n");
67 | write.flush();
68 | }
69 | write.writeBytes("exit");
70 | write.writeBytes("\n");
71 | write.flush();
72 | exec(p);
73 | }
74 | public String getAllResult(){
75 | return mStringBuffer.toString();
76 | }
77 |
78 | private final Random random = new Random();
79 | private void exec(final Process process){
80 | // 获取标准输出
81 | readStdout = new BufferedReader(new InputStreamReader(process.getInputStream()));
82 | // 获取错误输出
83 | readStderr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
84 | // 创建线程执行
85 | try {
86 | // 逐行读取
87 | while((tmp1 = readStdout.readLine()) != null || (tmp2 = readStderr.readLine()) != null){
88 | if(tmp1 != null){
89 | mStringBuffer.append(tmp1 + "\n");
90 | // 回调接口方法
91 | mInterface.onNewStdoutListener(msg.append(tmp1));
92 | System.out.println("tmp1 = " + tmp1);
93 | }
94 | if(tmp2 != null){
95 | mStringBuffer.append(tmp2 + "\n");
96 | mInterface.onNewStderrListener(errorMSG.append(tmp2));
97 | System.out.println("tmp2 = " + tmp2);
98 | }
99 | // Thread.currentThread().sleep(random.nextInt(101));
100 | }
101 | resultCode = process.waitFor();
102 | } catch (IOException | InterruptedException e) {
103 | // TODO Auto-generated catch block
104 | e.printStackTrace();
105 | }
106 | isRunning = false;
107 | mInterface.onProcessFinish(resultCode);
108 | }
109 | public boolean isRunning(){
110 | return this.isRunning;
111 | }
112 | public int getCommandSize(){
113 | return commandList.size();
114 | }
115 | public RealtimeProcessCommand getRealtimeProcessCommand(int p){
116 | return commandList.get(p);
117 | }
118 |
119 | static class RealtimeProcessCommand{
120 | private String directory = null;
121 | private String command = null;
122 | public RealtimeProcessCommand(){}
123 |
124 | public void setDirectory(String directory){
125 | this.directory = directory;
126 | }
127 | public void setCommand(String command){
128 | this.command = command;
129 | }
130 | public String getDirectory(){
131 | return this.directory;
132 | }
133 | public String getCommand(){
134 | return this.command;
135 | }
136 |
137 | }
138 |
139 | static public class MSG{
140 | private final List list = new ArrayList<>();
141 |
142 | public synchronized MSG append(String s){
143 | list.add(s + "\n");
144 | return this;
145 | }
146 |
147 | public synchronized String getLastLine(){
148 | return list.size() > 0 ? list.get(list.size() - 1) : "";
149 | }
150 |
151 | @Override
152 | public synchronized String toString() {
153 | StringBuilder stringBuilder = new StringBuilder();
154 | for (String s : list) {
155 | stringBuilder.append(s);
156 | }
157 | return stringBuilder.toString();
158 | }
159 |
160 | public List getList() {
161 | return list;
162 | }
163 | }
164 |
165 | static public class ErrorMSG{
166 | private final List list = new ArrayList<>();
167 |
168 | public List getList() {
169 | return list;
170 | }
171 |
172 | public synchronized ErrorMSG append(String s){
173 | list.add(s + "\n");
174 | return this;
175 | }
176 |
177 | public synchronized String getLastLine(){
178 | return list.size() > 0 ? list.get(list.size() - 1) : "";
179 | }
180 |
181 | @Override
182 | public synchronized String toString() {
183 | StringBuilder stringBuilder = new StringBuilder();
184 | for (String s : list) {
185 | stringBuilder.append(s);
186 | }
187 | return stringBuilder.toString();
188 | }
189 | }
190 | }
191 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/core/RunTimeUtils.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.core;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 |
7 | public class RunTimeUtils implements OnResultListener {
8 |
9 | private static RunTimeUtils INSTANCE = new RunTimeUtils();
10 |
11 | private OnResultListener resultListener;
12 | private RunTimeUtils(){
13 | resultListener = this;
14 | }
15 |
16 | public static RunTimeUtils getInstance(){
17 | return INSTANCE;
18 | }
19 |
20 | public void cmd(String cmd) throws IOException {
21 | Process su = Runtime.getRuntime().exec("su");
22 | InputStream inputStream = su.getInputStream();
23 | OutputStream outputStream = su.getOutputStream();
24 | InputStream errorStream = su.getErrorStream();
25 | }
26 |
27 | @Override
28 | public void onResult(String result) {
29 |
30 | }
31 |
32 | public OnResultListener getRunning() {
33 | return resultListener;
34 | }
35 |
36 | public void setRunning(OnResultListener resultListener) {
37 | this.resultListener = resultListener;
38 | }
39 | }
40 | interface OnResultListener{
41 | void onResult(String result);
42 | }
43 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/core/UpdateEngineCallback.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.core;
2 |
3 | public abstract class UpdateEngineCallback {
4 |
5 | public abstract void onStatusUpdate(int status, float percent);
6 |
7 | public abstract void onPayloadApplicationComplete(int errorCode);
8 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/core/UpdateParser.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.core;
2 |
3 | import android.util.Log;
4 | import java.io.BufferedReader;
5 | import java.io.File;
6 | import java.io.IOException;
7 | import java.io.InputStreamReader;
8 | import java.util.Arrays;
9 | import java.util.Enumeration;
10 | import java.util.Locale;
11 | import java.util.zip.ZipEntry;
12 | import java.util.zip.ZipFile;
13 |
14 |
15 | /** Parse an A/B update zip file. */
16 | public class UpdateParser {
17 |
18 | private static final String TAG = "ROTAUpdateManager";
19 | private static final String PAYLOAD_BIN_FILE = "payload.bin";
20 | private static final String PAYLOAD_PROPERTIES = "payload_properties.txt";
21 | private static final String FILE_URL_PREFIX = "file://";
22 | private static final int ZIP_FILE_HEADER = 30;
23 |
24 | private UpdateParser() {
25 | }
26 |
27 | /**
28 | * Parse a zip file containing a system update and return a non null ParsedUpdate.
29 | */
30 | static ParsedUpdate parse(File file) throws IOException {
31 | long payloadOffset = 0;
32 | long payloadSize = 0;
33 | boolean payloadFound = false;
34 | String[] props = null;
35 |
36 | try (ZipFile zipFile = new ZipFile(file)) {
37 | Enumeration extends ZipEntry> entries = zipFile.entries();
38 | while (entries.hasMoreElements()) {
39 | ZipEntry entry = entries.nextElement();
40 | long fileSize = entry.getCompressedSize();
41 | if (!payloadFound) {
42 | payloadOffset += ZIP_FILE_HEADER + entry.getName().length();
43 | if (entry.getExtra() != null) {
44 | payloadOffset += entry.getExtra().length;
45 | }
46 | }
47 |
48 | if (entry.isDirectory()) {
49 | continue;
50 | } else if (entry.getName().equals(PAYLOAD_BIN_FILE)) {
51 | payloadSize = fileSize;
52 | payloadFound = true;
53 | } else if (entry.getName().equals(PAYLOAD_PROPERTIES)) {
54 | try (BufferedReader buffer = new BufferedReader(
55 | new InputStreamReader(zipFile.getInputStream(entry)))) {
56 | props = buffer.lines().toArray(String[]::new);
57 | }
58 | }
59 | if (!payloadFound) {
60 | payloadOffset += fileSize;
61 | }
62 |
63 | //if (Log.isLoggable(TAG, Log.DEBUG)) {
64 | Log.d(TAG, String.format("Entry %s", entry.getName()));
65 | //}
66 | }
67 | }
68 | return new ParsedUpdate(file, payloadOffset, payloadSize, props);
69 | }
70 |
71 | /** Information parsed from an update file. */
72 | static class ParsedUpdate {
73 | final String mUrl;
74 | final long mOffset;
75 | final long mSize;
76 | final String[] mProps;
77 |
78 | ParsedUpdate(File file, long offset, long size, String[] props) {
79 | mUrl = FILE_URL_PREFIX + file.getAbsolutePath();
80 | mOffset = offset;
81 | mSize = size;
82 | mProps = props;
83 | }
84 |
85 | /** Verify the update information is correct. */
86 | boolean isValid() {
87 | return mOffset >= 0 && mSize > 0 && mProps != null;
88 | }
89 |
90 | @Override
91 | public String toString() {
92 | return String.format(Locale.getDefault(),
93 | "ParsedUpdate: URL=%s, offset=%d, size=%s, props=%s",
94 | mUrl, mOffset, mSize, Arrays.toString(mProps));
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/core/ZoomInTransformer.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.core
2 |
3 | import android.view.View
4 | import androidx.viewpager2.widget.ViewPager2
5 | import kotlin.math.abs
6 |
7 |
8 | class ZoomInTransformer : ViewPager2.PageTransformer {
9 | override fun transformPage(page: View, pos: Float) {
10 | val scale = if (pos < 0) pos + 1f else abs(1f - pos)
11 | page.scaleX = scale
12 | page.scaleY = scale
13 | page.pivotX = page.width * 0.2f
14 | page.pivotY = page.height * 0.2f
15 | page.alpha = if (pos < -1f || pos > 1f) 0f else 1f - (scale - 1f)
16 | }
17 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/interfaces/OnNavigationStateListener.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.interfaces;
2 |
3 | public interface OnNavigationStateListener {
4 | void onNavigationState(boolean b, int i);
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/interfaces/OnProcessDestroyListener.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.interfaces;
2 |
3 | public interface OnProcessDestroyListener {
4 | void onDestroy();
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/interfaces/OnProcessErrorListener.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.interfaces;
2 |
3 | import com.pointer.wave.easyship.core.CacheDao;
4 |
5 | public interface OnProcessErrorListener {
6 | void onErrorRead(CacheDao.MSG msg);
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/interfaces/OnRunTimeListener.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.interfaces;
2 |
3 | import com.pointer.wave.easyship.core.CacheDao;
4 |
5 | public interface OnRunTimeListener {
6 | void onRead(final CacheDao.MSG read);
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/interfaces/RealtimeProcessInterface.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.interfaces;
2 |
3 | import com.pointer.wave.easyship.core.RealtimeProcess;
4 |
5 | public interface RealtimeProcessInterface {
6 | void onNewStdoutListener(RealtimeProcess.MSG msg);
7 |
8 | void onNewStderrListener(RealtimeProcess.ErrorMSG errorMSG);
9 |
10 | void onProcessFinish(int resultCode);
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/ktx/AppGlobalScope.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.ktx
2 |
3 | import android.os.Looper
4 | import kotlinx.coroutines.*
5 | import java.io.Closeable
6 | import java.util.concurrent.atomic.AtomicReference
7 | import kotlin.coroutines.AbstractCoroutineContextElement
8 | import kotlin.coroutines.CoroutineContext
9 |
10 | // 保存 CoroutineScope
11 | private var scopeRef: AtomicReference = AtomicReference()
12 |
13 | // 自定义的 CoroutineScope
14 | val appGlobalScope: CoroutineScope
15 | get() {
16 | while (true) {
17 | val existing = scopeRef.get() as CoroutineScope?
18 | if (existing != null) {
19 | return existing
20 | }
21 | val newScope = SafeCoroutineScope(Dispatchers.Main.immediate)
22 | if (scopeRef.compareAndSet(null, newScope)) {
23 | return newScope
24 | }
25 | }
26 | }
27 |
28 | // 不会崩溃的 CoroutineScope
29 | private class SafeCoroutineScope(context: CoroutineContext) : CoroutineScope, Closeable {
30 | override val coroutineContext: CoroutineContext =
31 | SupervisorJob() + context + UncaughtCoroutineExceptionHandler()
32 |
33 | override fun close() {
34 | coroutineContext.cancelChildren()
35 | }
36 | }
37 |
38 | // 自定义 CoroutineExceptionHandler
39 | private class UncaughtCoroutineExceptionHandler : CoroutineExceptionHandler,
40 | AbstractCoroutineContextElement(CoroutineExceptionHandler) {
41 | override fun handleException(context: CoroutineContext, exception: Throwable) {
42 | // 处理异常
43 | }
44 | }
45 |
46 |
47 | val isOnMainThread: Boolean
48 | get() = Looper.myLooper() == Looper.getMainLooper()
49 |
50 | fun runOnMainThread(block: () -> Unit) {
51 | if (isOnMainThread) block.invoke()
52 | else appGlobalScope.launch(Dispatchers.Main) { block.invoke() }
53 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/ktx/KoinKtx.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.ktx
2 |
3 | import org.koin.core.context.GlobalContext
4 | import org.koin.core.parameter.ParametersDefinition
5 | import org.koin.core.qualifier.Qualifier
6 | import org.koin.mp.KoinPlatformTools
7 |
8 | inline fun get(
9 | qualifier: Qualifier? = null,
10 | noinline parameters: ParametersDefinition? = null
11 | ): T {
12 | return GlobalContext.get().get(qualifier, parameters)
13 | }
14 |
15 | inline fun inject(
16 | qualifier: Qualifier? = null,
17 | mode: LazyThreadSafetyMode = KoinPlatformTools.defaultLazyMode(),
18 | noinline parameters: ParametersDefinition? = null
19 | ): Lazy {
20 | return GlobalContext.get().inject(qualifier, mode, parameters)
21 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/net/Api.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.net
2 |
3 | import com.pointer.wave.easyship.pojo.TipsBen
4 | import okhttp3.FormBody
5 | import retrofit2.http.Body
6 | import retrofit2.http.POST
7 |
8 | interface Api {
9 | @POST("http://ly.lumnytool.club/api/read.php")
10 | suspend fun tips(
11 | @Body body: FormBody
12 | ): TipsBen
13 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/net/NetModule.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.net
2 |
3 | import okhttp3.OkHttpClient
4 | import retrofit2.Retrofit
5 | import retrofit2.converter.gson.GsonConverterFactory
6 | import retrofit2.converter.scalars.ScalarsConverterFactory
7 |
8 | private val okhttp = OkHttpClient.Builder()
9 | .addInterceptor(LogInterceptor())
10 | .build()
11 |
12 | val retrofit: Retrofit = Retrofit.Builder()
13 | .client(okhttp)
14 | .baseUrl("https://bot.k2t3k.tk/api/")
15 | .addConverterFactory(ScalarsConverterFactory.create())
16 | .addConverterFactory(GsonConverterFactory.create())
17 | .build()
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/net/repo/UpdateRepo.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.net.repo
2 |
3 | import com.pointer.wave.easyship.net.Api
4 | import com.pointer.wave.easyship.net.retrofit
5 | import kotlinx.coroutines.Dispatchers
6 | import kotlinx.coroutines.flow.flow
7 | import kotlinx.coroutines.flow.flowOn
8 | import okhttp3.FormBody
9 |
10 | class UpdateRepo {
11 | private val api by lazy { retrofit.create(Api::class.java) }
12 |
13 | suspend fun update() =
14 | flow {
15 | val body = FormBody.Builder().apply {
16 | add("id","103169318")
17 | add("api","easy_ship")
18 | add("dir","update")
19 | add("name","update.txt")
20 | }
21 | emit(
22 | api.tips(
23 | body.build()
24 | )
25 | )
26 | }.flowOn(Dispatchers.IO)
27 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/pojo/TipsBen.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.pojo;
2 |
3 | public class TipsBen {
4 | private String name;
5 | private String is_dir;
6 | private String time;
7 | private String size;
8 | private String content;
9 |
10 | public TipsBen() {
11 | }
12 |
13 | public TipsBen(String name, String is_dir, String time, String size, String content) {
14 | this.name = name;
15 | this.is_dir = is_dir;
16 | this.time = time;
17 | this.size = size;
18 | this.content = content;
19 | }
20 |
21 | public String getName() {
22 | return name;
23 | }
24 |
25 | public void setName(String name) {
26 | this.name = name;
27 | }
28 |
29 | public String getIs_dir() {
30 | return is_dir;
31 | }
32 |
33 | public void setIs_dir(String is_dir) {
34 | this.is_dir = is_dir;
35 | }
36 |
37 | public String getTime() {
38 | return time;
39 | }
40 |
41 | public void setTime(String time) {
42 | this.time = time;
43 | }
44 |
45 | public String getSize() {
46 | return size;
47 | }
48 |
49 | public void setSize(String size) {
50 | this.size = size;
51 | }
52 |
53 | public String getContent() {
54 | return content;
55 | }
56 |
57 | public void setContent(String content) {
58 | this.content = content;
59 | }
60 |
61 | @Override
62 | public String toString() {
63 | return "TipsBen{" +
64 | "name='" + name + '\'' +
65 | ", is_dir='" + is_dir + '\'' +
66 | ", time='" + time + '\'' +
67 | ", size='" + size + '\'' +
68 | ", content='" + content + '\'' +
69 | '}';
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/pojo/UpdateLogBen.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.pojo;
2 |
3 | public class UpdateLogBen {
4 |
5 | private String versionName;
6 | private String versionCode;
7 | private String updateContent;
8 | private String downloadUrl;
9 |
10 | public UpdateLogBen() {
11 | }
12 |
13 | public UpdateLogBen(String versionName, String versionCode, String updateContent) {
14 | this.versionName = versionName;
15 | this.versionCode = versionCode;
16 | this.updateContent = updateContent;
17 | }
18 |
19 | public String getVersionName() {
20 | return versionName;
21 | }
22 |
23 | public void setVersionName(String versionName) {
24 | this.versionName = versionName;
25 | }
26 |
27 | public String getVersionCode() {
28 | return versionCode;
29 | }
30 |
31 | public void setVersionCode(String versionCode) {
32 | this.versionCode = versionCode;
33 | }
34 |
35 | public String getDownloadUrl() {
36 | return downloadUrl;
37 | }
38 |
39 | public void setDownloadUrl(String downloadUrl) {
40 | this.downloadUrl = downloadUrl;
41 | }
42 |
43 | public String getUpdateContent() {
44 | return updateContent;
45 | }
46 |
47 | public void setUpdateContent(String updateContent) {
48 | this.updateContent = updateContent;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return "版本号:" + versionCode + "
" +
55 | "更新内容:
" + updateContent.replace("\n", "
");
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/pojo/VersionBen.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.pojo;
2 |
3 | public class VersionBen {
4 |
5 | private String versionName;
6 | private String versionCode;
7 | private String updateContent;
8 | private String downloadUrl;
9 |
10 | public VersionBen() {
11 | }
12 |
13 | public VersionBen(String versionName, String versionCode, String updateContent) {
14 | this.versionName = versionName;
15 | this.versionCode = versionCode;
16 | this.updateContent = updateContent;
17 | }
18 |
19 | public String getVersionName() {
20 | return versionName;
21 | }
22 |
23 | public void setVersionName(String versionName) {
24 | this.versionName = versionName;
25 | }
26 |
27 | public String getVersionCode() {
28 | return versionCode;
29 | }
30 |
31 | public void setVersionCode(String versionCode) {
32 | this.versionCode = versionCode;
33 | }
34 |
35 | public String getDownloadUrl() {
36 | return downloadUrl;
37 | }
38 |
39 | public void setDownloadUrl(String downloadUrl) {
40 | this.downloadUrl = downloadUrl;
41 | }
42 |
43 | public String getUpdateContent() {
44 | return updateContent;
45 | }
46 |
47 | public void setUpdateContent(String updateContent) {
48 | this.updateContent = updateContent;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/services/ProcessService.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.services;
2 |
3 | import android.app.Service;
4 | import android.content.Intent;
5 | import android.os.IBinder;
6 |
7 | import androidx.annotation.Nullable;
8 |
9 | public class ProcessService extends Service {
10 |
11 | @Nullable
12 | @Override
13 | public IBinder onBind(Intent intent) {
14 | return null;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/utils/ColorChangeUtils.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.utils;
2 |
3 | import android.animation.Animator;
4 | import android.animation.AnimatorListenerAdapter;
5 | import android.animation.ArgbEvaluator;
6 | import android.animation.ObjectAnimator;
7 | import android.annotation.SuppressLint;
8 | import android.os.Handler;
9 | import android.view.View;
10 |
11 |
12 | public class ColorChangeUtils {
13 |
14 | private final int[] colors;
15 | private long duration = 2000;
16 | private long delay = 5000;
17 | private int index = -1;
18 |
19 | private final Handler mHandler;
20 | private final Runnable mRunnable;
21 |
22 | public ColorChangeUtils(int[] colors, View mView) {
23 | this.colors = colors;
24 | mHandler = new Handler(mView.getContext().getMainLooper());
25 | mRunnable = new Runnable() {
26 | @Override
27 | public void run() {
28 | @SuppressLint("ObjectAnimatorBinding") ObjectAnimator backgroundColor = ObjectAnimator.ofInt(mView, "backgroundColor", getColorTemp(), nextColor());
29 | backgroundColor.setDuration(duration);
30 | backgroundColor.setEvaluator(new ArgbEvaluator());
31 | backgroundColor.addListener(new AnimatorListenerAdapter() {
32 | @Override
33 | public void onAnimationEnd(Animator animation) {
34 | super.onAnimationEnd(animation);
35 | mHandler.postDelayed(mRunnable, delay);
36 | }
37 | });
38 | backgroundColor.start();
39 | }
40 | };
41 |
42 | @SuppressLint("ObjectAnimatorBinding") ObjectAnimator backgroundColor = ObjectAnimator.ofInt(mView, "backgroundColor", getColorTemp(), nextColor());
43 | backgroundColor.setDuration(0);
44 | backgroundColor.addListener(new Animator.AnimatorListener() {
45 | @Override
46 | public void onAnimationStart(Animator animation) {
47 |
48 | }
49 |
50 | @Override
51 | public void onAnimationEnd(Animator animation) {
52 |
53 | }
54 |
55 | @Override
56 | public void onAnimationCancel(Animator animation) {
57 |
58 | }
59 |
60 | @Override
61 | public void onAnimationRepeat(Animator animation) {
62 |
63 | }
64 | });
65 | backgroundColor.start();
66 | }
67 |
68 |
69 | private int nextColor(){
70 | int i = index + 1;
71 | if (i >= colors.length) i = 0;
72 | return colors[i];
73 | }
74 |
75 | private int getColorTemp(){
76 | index++;
77 | if (index >= colors.length) index = 0;
78 | return colors[index];
79 | }
80 |
81 | public long getDuration() {
82 | return duration;
83 | }
84 |
85 | public void setDuration(long duration) {
86 | this.duration = duration;
87 | }
88 |
89 | public long getDelay() {
90 | return delay;
91 | }
92 |
93 | public void setDelay(long delay) {
94 | this.delay = delay;
95 | }
96 |
97 | public void startAnimation(){
98 | mHandler.postDelayed(mRunnable, delay);
99 | }
100 |
101 | public void stopAnimation(){
102 | mHandler.removeCallbacks(mRunnable);
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/utils/DensityUtil.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.utils;
2 |
3 | import android.content.Context;
4 |
5 | public class DensityUtil {
6 |
7 | public static int dip2px(Context context, float dpValue) {
8 | final float scale = context.getResources().getDisplayMetrics().density;
9 | return (int) (dpValue * scale + 0.5f);
10 | }
11 |
12 | public static int px2dip(Context context, float pxValue) {
13 | final float scale = context.getResources().getDisplayMetrics().density;
14 | return (int) (pxValue / scale + 0.5f);
15 | }
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/utils/FileInterface.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.utils;
2 |
3 | public interface FileInterface {
4 | public boolean exists();
5 |
6 | public String getName();
7 |
8 | public String getParent();
9 |
10 | public String getPath();
11 |
12 | public boolean canRead();
13 |
14 | public boolean canWrite();
15 |
16 | public boolean isDirectory();
17 |
18 | public boolean isFile();
19 |
20 | public long lastModified();
21 |
22 | public long length();
23 |
24 | public boolean createNewFile();
25 |
26 | public boolean delete();
27 |
28 | public String[] list();
29 |
30 | public boolean mkDirs();
31 |
32 | public boolean renameTo(String name);
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/utils/FileUtil.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.utils;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.os.Build;
5 | import android.os.Environment;
6 |
7 | import java.io.BufferedInputStream;
8 | import java.io.BufferedOutputStream;
9 | import java.io.ByteArrayOutputStream;
10 | import java.io.File;
11 | import java.io.FileInputStream;
12 | import java.io.FileOutputStream;
13 | import java.io.IOException;
14 | import java.io.InputStream;
15 | import java.io.OutputStream;
16 | import java.nio.charset.StandardCharsets;
17 |
18 | public class FileUtil implements FileInterface {
19 |
20 | public static String getExternalStoragePath(){
21 | return Environment.getExternalStorageDirectory().getPath();
22 | }
23 |
24 | public static String getDirStoragePath(){
25 | return Environment.getExternalStorageDirectory().getPath() + "/Android/data";
26 | }
27 |
28 | @SuppressLint("SdCardPath")
29 | public static String getSDCardStoragePath(){
30 | return "/sdcard/Android/data";
31 | }
32 |
33 | private final String path;
34 | private final File file;
35 | private final SAF saf;
36 | public FileUtil(String path){
37 | this.path = path;
38 | file = new File(path);
39 | saf = new SAF(path);
40 | }
41 |
42 | private boolean isFileDir(){
43 | return (path.startsWith(getDirStoragePath()) || path.startsWith(getSDCardStoragePath())) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
44 | }
45 |
46 | public String readText(){
47 | try {
48 | return new String(readBytes(openInputStream()));
49 | } catch (Exception e) {
50 | e.printStackTrace();
51 | return null;
52 | }
53 | }
54 |
55 | public boolean writeText(String text){
56 | try{
57 | return writeBytes(openOutputStream(), text.getBytes(StandardCharsets.UTF_8));
58 | }catch (Exception e){
59 | e.printStackTrace();
60 | return false;
61 | }
62 | }
63 |
64 | public static byte[] readBytes(InputStream inputStream){
65 | try(ByteArrayOutputStream byteArrayOutputStream =new ByteArrayOutputStream(1024);
66 | BufferedInputStream bis = new BufferedInputStream(inputStream)) {
67 | byte[] temp=new byte[1024];
68 | int size = 0;
69 | while((size = bis.read(temp)) != -1) {
70 | byteArrayOutputStream.write(temp,0,size);
71 | }
72 | return byteArrayOutputStream.toByteArray();
73 | }catch (IOException e){
74 | e.printStackTrace();
75 | return null;
76 | }finally {
77 | if (inputStream != null){
78 | try {
79 | inputStream.close();
80 | } catch (IOException e) {
81 | e.printStackTrace();
82 | }
83 | }
84 | }
85 | }
86 |
87 | public static boolean writeBytes(OutputStream os, byte[] bs){
88 | try(BufferedOutputStream bos = new BufferedOutputStream(os)){
89 | bos.write(bs);
90 | return true;
91 | }catch (IOException e){
92 | e.printStackTrace();
93 | return false;
94 | }finally {
95 | if (os != null){
96 | try {
97 | os.close();
98 | } catch (IOException e) {
99 | e.printStackTrace();
100 | }
101 | }
102 | }
103 | }
104 |
105 | public InputStream openInputStream() throws IOException {
106 | if (isFileDir()) return saf.openInputStream();
107 | else return new FileInputStream(path);
108 | }
109 |
110 | public OutputStream openOutputStream() throws IOException {
111 | if (isFileDir()) return saf.openOutputStream();
112 | else return new FileOutputStream(path);
113 | }
114 |
115 |
116 | @Override
117 | public boolean exists() {
118 | if (isFileDir()) return saf.exists();
119 | else return file.exists();
120 | }
121 |
122 | @Override
123 | public String getName() {
124 | if (isFileDir()) return saf.getName();
125 | else return file.getName();
126 | }
127 |
128 | @Override
129 | public String getParent() {
130 | if (isFileDir()) return saf.getParent();
131 | else return file.getParent();
132 | }
133 |
134 | @Override
135 | public String getPath() {
136 | if (isFileDir()) return saf.getPath();
137 | else return file.getPath();
138 | }
139 |
140 | @Override
141 | public boolean canRead() {
142 | if (isFileDir()) return saf.canRead();
143 | else return file.canRead();
144 | }
145 |
146 | @Override
147 | public boolean canWrite() {
148 | if (isFileDir()) return saf.canWrite();
149 | else return file.canWrite();
150 | }
151 |
152 | @Override
153 | public boolean isDirectory() {
154 | if (isFileDir()) return saf.isDirectory();
155 | else return file.isDirectory();
156 | }
157 |
158 | @Override
159 | public boolean isFile() {
160 | if (isFileDir()) return saf.isFile();
161 | else return file.isFile();
162 | }
163 |
164 | @Override
165 | public long lastModified() {
166 | if (isFileDir()) return saf.lastModified();
167 | else return file.lastModified();
168 | }
169 |
170 | @Override
171 | public long length() {
172 | if (isFileDir()) return saf.length();
173 | else return file.length();
174 | }
175 |
176 | @Override
177 | public boolean createNewFile() {
178 | if (isFileDir()) return saf.createNewFile();
179 | else {
180 | try {
181 | return file.createNewFile();
182 | } catch (IOException e) {
183 | e.printStackTrace();
184 | return false;
185 | }
186 | }
187 | }
188 |
189 | @Override
190 | public boolean delete() {
191 | if (isFileDir()) return saf.delete();
192 | else return file.delete();
193 | }
194 |
195 | @Override
196 | public String[] list() {
197 | if (isFileDir()) return saf.list();
198 | else return file.list();
199 | }
200 |
201 | @Override
202 | public boolean mkDirs() {
203 | if (isFileDir()) return saf.mkDirs();
204 | else return file.mkdirs();
205 | }
206 |
207 | @Override
208 | public boolean renameTo(String name) {
209 | if (isFileDir()) return saf.renameTo(name);
210 | else return file.renameTo(new File(getParent() + "/" + name));
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/utils/JsonUtils.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.utils;
2 |
3 | import android.util.Log;
4 |
5 | import org.json.JSONArray;
6 | import org.json.JSONException;
7 | import org.json.JSONObject;
8 |
9 | /**
10 | * JSON实用工具,方便快速访问JSON各节点
11 | *
12 | * 支持点连接访问
13 | */
14 | public class JsonUtils {
15 |
16 | String TAG = "JSONUTILS";
17 |
18 | private JSONObject jsonObject;
19 |
20 | //临时对象
21 | private JSONObject tmpJsonObject;
22 | private JSONArray tmpJsonArray;
23 | private Object tmpObject;
24 |
25 | /**
26 | * 初始化
27 | *
28 | * @param json
29 | */
30 | public JsonUtils(String json) {
31 | try {
32 | this.tmpJsonObject = this.jsonObject = new JSONObject(json);
33 | } catch (JSONException e) {
34 | e.printStackTrace();
35 | }
36 | }
37 |
38 | /**
39 | * 获取JSON对象
40 | *
41 | * @param key
42 | * @return
43 | */
44 | public JsonUtils getJSONObject(String key) {
45 | try {
46 | this.tmpJsonObject = this.tmpJsonObject.getJSONObject(key);
47 | } catch (JSONException e) {
48 | Log.e(TAG, "键值:" + key + "不存在或是一个数组,正在尝试解析为数组...");
49 | this.getJSONArray(key);
50 | }
51 |
52 | return this;
53 | }
54 |
55 | /**
56 | * 获取对象,指非JSON对象,调用这个方法可以进行格式化返回结果,如toInt,toString等
57 | *
58 | * @param key
59 | * @return
60 | */
61 | public JsonUtils get(String key) {
62 | try {
63 | this.tmpObject = this.tmpJsonObject.get(key);
64 | } catch (JSONException e) {
65 | Log.e(TAG, "键值:" + key + "不存在或是一个数组,正在尝试解析为数组...");
66 | this.getJSONArray(key);
67 | }
68 |
69 | return this;
70 | }
71 |
72 | //重置临时JSON对象,调用toXXX函数时自动重置
73 | public JsonUtils reset() {
74 | this.tmpJsonObject = this.jsonObject;
75 | return this;
76 | }
77 |
78 |
79 | /**
80 | * 获取JSON数组对象
81 | *
82 | * @param key
83 | * @return
84 | */
85 | public JsonUtils getJSONArray(String key) {
86 | try {
87 | this.tmpJsonArray = this.tmpJsonObject.getJSONArray(key);
88 | } catch (JSONException e) {
89 | Log.e(TAG, "键值:" + key + "不是一个数组");
90 | }
91 |
92 | return this;
93 | }
94 |
95 | /**
96 | * 获取指定索引的数组项,JSON数组
97 | *
98 | * @param idx
99 | * @return
100 | */
101 | public JsonUtils getJSONArrayItem(int idx) {
102 | try {
103 | this.tmpJsonObject = this.tmpJsonArray.getJSONObject(idx);
104 | } catch (JSONException e) {
105 | e.printStackTrace();
106 | }
107 |
108 | return this;
109 | }
110 |
111 | /**
112 | * 获取指定索引的数组项,非JSON数组
113 | *
114 | * @param idx
115 | * @return
116 | */
117 | public JsonUtils getArraytem(int idx) {
118 | try {
119 | this.tmpObject = this.tmpJsonArray.get(idx);
120 | } catch (JSONException e) {
121 | e.printStackTrace();
122 | }
123 |
124 | return this;
125 | }
126 |
127 | /**
128 | * 点连接的方式访问键值,示例:a.b.c
129 | * @param key
130 | * @return
131 | */
132 | public JsonUtils getByDotKey(String key)
133 | {
134 | String[] keys = key.split("\\.");
135 |
136 | String tmpKey = "";
137 | String[] tmpKeys;
138 |
139 | JSONObject tmpJsonObject = this.tmpJsonObject;
140 |
141 | try
142 | {
143 | for(int i=0;i=keys.length)
156 | {
157 | this.tmpObject = tmpJsonObject.get(tmpKey);
158 | }else{
159 | tmpJsonObject = tmpJsonObject.getJSONObject(tmpKey);
160 | }
161 | }
162 | }
163 | }catch (Exception e)
164 | {
165 | e.printStackTrace();
166 | }
167 |
168 | return this;
169 | }
170 |
171 | public int toInt()
172 | {
173 | reset();
174 | return Integer.valueOf(tmpObject.toString());
175 | }
176 |
177 | public float toFloat()
178 | {
179 | reset();
180 | return Float.valueOf(tmpObject.toString());
181 | }
182 |
183 | public String toString()
184 | {
185 | reset();
186 | return tmpObject.toString();
187 | }
188 |
189 | public Boolean toBoolean()
190 | {
191 | reset();
192 | return Boolean.valueOf(tmpObject.toString());
193 | }
194 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/utils/KeepShellPublic.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.utils
2 |
3 | /**
4 | * Created by Hello on 2018/01/23.
5 | */
6 | object KeepShellPublic {
7 | private val keepShells = HashMap()
8 |
9 | fun getInstance(key: String, rootMode: Boolean): KeepShell {
10 | synchronized(keepShells) {
11 | if (!keepShells.containsKey(key)) {
12 | keepShells.put(key, KeepShell(rootMode))
13 | }
14 | return keepShells.get(key)!!
15 | }
16 | }
17 |
18 | fun destroyInstance(key: String) {
19 | synchronized(keepShells) {
20 | if (!keepShells.containsKey(key)) {
21 | return
22 | } else {
23 | val keepShell = keepShells.get(key)!!
24 | keepShells.remove(key)
25 | keepShell.tryExit()
26 | }
27 | }
28 | }
29 |
30 | fun destroyAll() {
31 | synchronized(keepShells) {
32 | while (keepShells.isNotEmpty()) {
33 | val key = keepShells.keys.first()
34 | val keepShell = keepShells.get(key)!!
35 | keepShells.remove(key)
36 | keepShell.tryExit()
37 | }
38 | }
39 | }
40 |
41 | public val defaultKeepShell = KeepShell()
42 | public val secondaryKeepShell = KeepShell()
43 |
44 | fun getDefaultInstance(): KeepShell {
45 | return if (defaultKeepShell.isIdle || !secondaryKeepShell.isIdle) {
46 | defaultKeepShell
47 | } else {
48 | secondaryKeepShell
49 | }
50 | }
51 |
52 | fun doCmdSync(commands: List): Boolean {
53 | val stringBuilder = StringBuilder()
54 |
55 | for (cmd in commands) {
56 | stringBuilder.append(cmd)
57 | stringBuilder.append("\n\n")
58 | }
59 |
60 | return doCmdSync(stringBuilder.toString()) != "error"
61 | }
62 |
63 | //执行脚本
64 | fun doCmdSync(cmd: String): String {
65 | return getDefaultInstance().doCmdSync(cmd)
66 | }
67 |
68 | //执行脚本
69 | fun checkRoot(): Boolean {
70 | return defaultKeepShell.checkRoot()
71 | }
72 |
73 | fun tryExit() {
74 | defaultKeepShell.tryExit()
75 | secondaryKeepShell.tryExit()
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/utils/ShellExecutor.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.utils;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 |
7 | public class ShellExecutor {
8 | private static String extraEnvPath = "";
9 | private static String defaultEnvPath = ""; // /sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin
10 |
11 | public static void setExtraEnvPath(String extraEnvPath) {
12 | ShellExecutor.extraEnvPath = extraEnvPath;
13 | }
14 |
15 | private static String getEnvPath() {
16 | // FIXME:非root模式下,默认的 TMPDIR=/data/local/tmp 变量可能会导致某些需要写缓存的场景(例如使用source指令)脚本执行失败!
17 | if (extraEnvPath != null && !extraEnvPath.isEmpty()) {
18 | if (defaultEnvPath.isEmpty()) {
19 | try {
20 | Process process = Runtime.getRuntime().exec("sh");
21 | OutputStream outputStream = process.getOutputStream();
22 | outputStream.write("echo $PATH".getBytes());
23 | outputStream.flush();
24 | outputStream.close();
25 |
26 | InputStream inputStream = process.getInputStream();
27 | byte[] cache = new byte[16384];
28 | int length = inputStream.read(cache);
29 | inputStream.close();
30 | process.destroy();
31 |
32 | String path = new String(cache, 0, length).trim();
33 | if (path.length() > 0) {
34 | defaultEnvPath = path;
35 | } else {
36 | throw new RuntimeException("未能获取到$PATH参数");
37 | }
38 | } catch (Exception ex) {
39 | defaultEnvPath = "/sbin:/system/sbin:/system/bin:/system/xbin:/odm/bin:/vendor/bin:/vendor/xbin";
40 | }
41 | }
42 |
43 | String path = defaultEnvPath;
44 |
45 | return ( "PATH=" + path + ":" + extraEnvPath);
46 | }
47 |
48 | return null;
49 | }
50 |
51 | private static Process getProcess(String run) throws IOException {
52 | String env = getEnvPath();
53 | Runtime runtime = Runtime.getRuntime();
54 | /*
55 | // 部分机型会有Aborted错误
56 | if (env != null) {
57 | return runtime.exec(run, new String[]{
58 | env
59 | });
60 | }
61 | */
62 | Process process = runtime.exec(run);
63 | if (env != null) {
64 | OutputStream outputStream = process.getOutputStream();
65 | outputStream.write("export ".getBytes());
66 | outputStream.write(env.getBytes());
67 | outputStream.write("\n".getBytes());
68 | outputStream.flush();
69 | }
70 | return process;
71 | }
72 |
73 | public static Process getSuperUserRuntime() throws IOException {
74 | return getProcess("su");
75 | }
76 |
77 | public static Process getRuntime() throws IOException {
78 | return getProcess("sh");
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/view/SymbolView.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.view;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Color;
6 | import android.graphics.Rect;
7 | import android.view.Gravity;
8 | import android.view.LayoutInflater;
9 | import android.view.MotionEvent;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.view.ViewTreeObserver;
13 | import android.view.WindowManager;
14 | import android.view.inputmethod.InputMethodManager;
15 | import android.widget.LinearLayout;
16 | import android.widget.PopupWindow;
17 | import android.widget.TextView;
18 |
19 | import com.pointer.wave.easyship.R;
20 | import com.pointer.wave.easyship.utils.DensityUtil;
21 |
22 | /*
23 | 符号栏类
24 | */
25 | public class SymbolView {
26 | private final int TILE_WIDTH = 60;
27 | private PopupWindow popupWindow;
28 | private View rootView;
29 | private OnSymbolViewClick onSymbolViewClick;
30 | private boolean visible = false;
31 | private InputMethodManager inputMethodManager;
32 | private boolean isFirst = true;
33 | private int maxLayoutHeight = 0;//布局总长
34 | private int currentLayoutHeight = 0;//当前布局高
35 | private Context context;
36 | private boolean isUC = true;
37 |
38 | @SuppressLint({"ClickableViewAccessibility", "ResourceType"})
39 | public SymbolView(final Context context, final View rootView) {
40 | this.context = context;
41 | this.rootView = rootView;
42 | popupWindow = new PopupWindow(context);
43 | inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
44 | View view = LayoutInflater.from(context).inflate(R.layout.symbol_view, null);
45 | LinearLayout linearLayout = view.findViewById(R.id.linear_container);
46 | final float[] tempPoint = new float[2];
47 | String symbol = "←
→
换行
删行
+CVars=
=
r.
[
]
.
+
[UserCustom DeviceProfile]";
48 | if (!isFirst){
49 | symbol = "←
→
换行
+CVars=
=
r.
[
]
.
+
[UserCustom DeviceProfile]
[FansSwitcher]
[FansCustom]";
50 | }
51 | String[] symbolArrary = symbol.split("
");
52 | for (int i = 0; i < symbolArrary.length; i++) {
53 | TextView textView = new TextView(context);
54 | textView.setGravity(Gravity.CENTER);
55 | textView.setText(symbolArrary[i]);
56 | textView.setClickable(true);
57 | textView.setTextSize(20);
58 | //textView.setWidth();
59 | textView.setPadding(DensityUtil.dip2px(context, 10), DensityUtil.dip2px(context, 5), DensityUtil.dip2px(context, 10), DensityUtil.dip2px(context, 5));
60 | textView.setOnTouchListener(new View.OnTouchListener() {
61 | @Override
62 | public boolean onTouch(View v, MotionEvent event) {
63 | int color = v.getDrawingCacheBackgroundColor();
64 | int motionEvent = event.getAction();
65 | TextView tv = (TextView) v;
66 |
67 | if (motionEvent == MotionEvent.ACTION_DOWN) {
68 | tempPoint[0] = event.getX();
69 | tempPoint[1] = event.getY();
70 | tv.setBackgroundColor(0xffcecfd1);
71 |
72 | } else if (motionEvent == MotionEvent.ACTION_UP || motionEvent == MotionEvent.ACTION_CANCEL) {
73 | tv.setBackgroundColor(Color.parseColor(context.getString(R.color.white)));
74 | if (Math.abs(event.getX() - tempPoint[0]) < TILE_WIDTH) {
75 | if (onSymbolViewClick != null)
76 | onSymbolViewClick.onClick(tv, tv.getText().toString());
77 | }
78 | }
79 | return true;
80 | }
81 | });
82 | LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
83 | linearLayout.setGravity(Gravity.CENTER);
84 | linearLayout.addView(textView, layoutParams);
85 |
86 | }
87 | popupWindow.setWidth(LinearLayout.LayoutParams.MATCH_PARENT);
88 | //popupWindow.setHeight(EditCodeActivity.height);
89 | popupWindow.getBackground().setAlpha(0);//窗口完全透明
90 | view.setBackgroundColor(Color.parseColor(context.getString(R.color.white)));//视图不完全透明
91 | popupWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
92 | popupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
93 | popupWindow.setContentView(view);
94 | rootView.getViewTreeObserver().addOnGlobalLayoutListener(
95 | new ViewTreeObserver.OnGlobalLayoutListener() {
96 | @Override
97 | public void onGlobalLayout() {
98 | Rect r = new Rect();
99 | rootView.getWindowVisibleDisplayFrame(r);
100 | if (isFirst) {
101 | maxLayoutHeight = r.bottom;//初始化时为布局的最高高度
102 | currentLayoutHeight = r.bottom;//当前弹出的布局高
103 | isFirst = false;
104 | } else {
105 | currentLayoutHeight = r.bottom;//当前弹出的布局高
106 | }
107 | if (currentLayoutHeight == maxLayoutHeight || !visible) {
108 | hide();
109 | } else if (currentLayoutHeight < maxLayoutHeight) {
110 | show(rootView.getHeight() - r.bottom);
111 | }
112 | }
113 | });
114 | }
115 |
116 | public void setUC(boolean UC) {
117 | isUC = UC;
118 |
119 | }
120 |
121 | public void setVisible(boolean visible) {
122 | this.visible = visible;
123 | }
124 |
125 | private void show(int bottom) {
126 | popupWindow.showAtLocation(rootView, Gravity.BOTTOM, 0, bottom);
127 | }
128 |
129 | private void hide() {
130 | popupWindow.dismiss();
131 | }
132 |
133 | public void setOnSymbolViewClick(OnSymbolViewClick onSymbolViewClick) {
134 | this.onSymbolViewClick = onSymbolViewClick;
135 | }
136 |
137 |
138 | public interface OnSymbolViewClick {
139 | void onClick(View view, String text);
140 | }
141 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/widget/HelpsDialog.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.widget;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.annotation.SuppressLint;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.net.Uri;
8 | import android.os.AsyncTask;
9 | import android.os.Handler;
10 | import android.text.Editable;
11 | import android.text.Html;
12 | import android.text.SpannableStringBuilder;
13 | import android.text.Spanned;
14 | import android.text.TextWatcher;
15 | import android.text.style.ClickableSpan;
16 | import android.text.style.URLSpan;
17 | import android.view.View;
18 | import android.widget.EditText;
19 | import android.widget.LinearLayout;
20 | import android.widget.TextView;
21 |
22 | import androidx.annotation.NonNull;
23 | import androidx.appcompat.app.AppCompatActivity;
24 | import androidx.recyclerview.widget.RecyclerView;
25 | import androidx.recyclerview.widget.StaggeredGridLayoutManager;
26 |
27 | import com.github.mmin18.widget.RealtimeBlurView;
28 | import com.google.gson.Gson;
29 | import com.lxj.xpopup.XPopup;
30 | import com.lxj.xpopup.core.BottomPopupView;
31 | import com.lxj.xpopup.enums.PopupAnimation;
32 | import com.pointer.wave.easyship.R;
33 | import com.pointer.wave.easyship.pojo.TipsBen;
34 | import com.pointer.wave.easyship.utils.HttpUtils;
35 | import com.pointer.wave.easyship.widget.adapter.HelpsListAdapter;
36 |
37 | import java.io.IOException;
38 | import java.util.ArrayList;
39 | import java.util.Arrays;
40 | import java.util.List;
41 |
42 | import okhttp3.Call;
43 | import okhttp3.Callback;
44 | import okhttp3.Response;
45 |
46 | public class HelpsDialog extends BottomPopupView {
47 |
48 | public static AppCompatActivity activity;
49 |
50 | @SuppressLint("StaticFieldLeak")
51 | public static HelpsDialog dialog;
52 | public HelpsDialog(@NonNull Context context, List list) {
53 | super(context);
54 | dialog = this;
55 | this.list = list;
56 | }
57 |
58 | @Override
59 | protected int getImplLayoutId() {
60 | return R.layout.dialog_full_base;
61 | }
62 |
63 | public static void showDialog(AppCompatActivity appCompatActivity, List list){
64 | activity = appCompatActivity;
65 | new XPopup.Builder(appCompatActivity)
66 | .animationDuration(750)
67 | .dismissOnTouchOutside(false)
68 | .hasShadowBg(false)
69 | .hasBlurBg(false)
70 | .isViewMode(true)
71 | .popupAnimation(PopupAnimation.TranslateAlphaFromBottom)
72 | .moveUpToKeyboard(false)
73 | .isDestroyOnDismiss(true)
74 | .asCustom(new HelpsDialog(appCompatActivity, list))
75 | .show();
76 | }
77 |
78 | private LinearLayout relativeLayout;
79 | private View inflate;
80 | private List list = new ArrayList<>();
81 | private HelpsListAdapter adapter;
82 | @Override
83 | protected void onCreate() {
84 | super.onCreate();
85 | relativeLayout = findViewById(R.id.root_view);
86 | inflate = View.inflate(getContext(), R.layout.dialog_helps, null);
87 | addChildView(inflate);
88 | RealtimeBlurView blurView = findViewById(R.id.blur_view);
89 | translation(blurView);
90 |
91 | RecyclerView recyclerView = inflate.findViewById(R.id.list_view);
92 | adapter = new HelpsListAdapter(list, activity);
93 | recyclerView.setLayoutManager(new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL));
94 | recyclerView.setAdapter(adapter);
95 |
96 | EditText editText = inflate.findViewById(R.id.editTextTextPersonName);
97 | editText.addTextChangedListener(new TextWatcher() {
98 | @Override
99 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
100 |
101 | }
102 |
103 | @Override
104 | public void onTextChanged(CharSequence s, int start, int before, int count) {
105 |
106 | }
107 |
108 | @Override
109 | public void afterTextChanged(Editable s) {
110 | search(s.toString());
111 | }
112 | });
113 | }
114 |
115 | @SuppressLint("StaticFieldLeak")
116 | private void search(String text) {
117 | new AsyncTask>(){
118 |
119 | @Override
120 | protected List doInBackground(String... strings) {
121 | List arrayList = new ArrayList<>();
122 | list.forEach((item)->{
123 | for (String string : strings) {
124 | if (item.contains(string)){
125 | arrayList.add(item);
126 | }
127 | }
128 | });
129 | return arrayList;
130 | }
131 |
132 | @Override
133 | protected void onPostExecute(List s) {
134 | super.onPostExecute(s);
135 | adapter.updateList(s);
136 | }
137 | }.execute(text);
138 | }
139 |
140 |
141 |
142 | private void addChildView(View view) {
143 | relativeLayout.removeAllViews();
144 | relativeLayout.addView(view);
145 | }
146 |
147 | private void translation(View view){
148 | ObjectAnimator translationY = ObjectAnimator.ofFloat(view, "translationY", 0, 0.1f);
149 | translationY.setDuration(100);
150 | translationY.start();
151 | new Handler(view.getContext().getMainLooper()).postDelayed(()->{
152 | translation(view);
153 | }, 200);
154 | }
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/widget/MarqueeTextView.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.widget;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.util.AttributeSet;
6 | import android.view.ViewDebug;
7 | import android.widget.TextView;
8 |
9 | @SuppressLint("AppCompatCustomView")
10 | public class MarqueeTextView extends TextView {
11 |
12 | public MarqueeTextView(Context context) {
13 | super(context);
14 | }
15 |
16 | public MarqueeTextView(Context context, AttributeSet attrs, int defStyle) {
17 | super(context, attrs, defStyle);
18 | }
19 |
20 | public MarqueeTextView(Context context, AttributeSet attrs) {
21 | super(context, attrs);
22 | }
23 |
24 | @Override
25 | @ViewDebug.ExportedProperty(category = "focus")
26 | public boolean isFocused() {
27 | // TODO Auto-generated method stub
28 | return true;
29 | }
30 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/widget/OverRecyclerView.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.widget;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 | import android.view.View;
9 |
10 | import androidx.recyclerview.widget.RecyclerView;
11 |
12 | import com.mixiaoxiao.overscroll.OverScrollDelegate;
13 |
14 | public class OverRecyclerView extends RecyclerView implements OverScrollDelegate.OverScrollable {
15 | private OverScrollDelegate mOverScrollDelegate;
16 |
17 | public OverRecyclerView(Context context) {
18 | super(context);
19 | this.createOverScrollDelegate(context);
20 | }
21 |
22 | public OverRecyclerView(Context context, AttributeSet attrs) {
23 | super(context, attrs);
24 | this.createOverScrollDelegate(context);
25 | }
26 |
27 | public OverRecyclerView(Context context, AttributeSet attrs, int defStyle) {
28 | super(context, attrs, defStyle);
29 | this.createOverScrollDelegate(context);
30 | }
31 |
32 | private void createOverScrollDelegate(Context context) {
33 | this.mOverScrollDelegate = new OverScrollDelegate(this);
34 | }
35 |
36 | public boolean onInterceptTouchEvent(MotionEvent ev) {
37 | return this.mOverScrollDelegate.onInterceptTouchEvent(ev) || super.onInterceptTouchEvent(ev);
38 | }
39 |
40 | @SuppressLint("ClickableViewAccessibility")
41 | public boolean onTouchEvent(MotionEvent event) {
42 | return this.mOverScrollDelegate.onTouchEvent(event) || super.onTouchEvent(event);
43 | }
44 |
45 | @SuppressLint("MissingSuperCall")
46 | public void draw(Canvas canvas) {
47 | //super.draw(canvas);
48 | this.mOverScrollDelegate.draw(canvas);
49 | }
50 |
51 | protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
52 | return this.mOverScrollDelegate.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
53 | }
54 |
55 | public int superComputeVerticalScrollExtent() {
56 | return super.computeVerticalScrollExtent();
57 | }
58 |
59 | public int superComputeVerticalScrollOffset() {
60 | return super.computeVerticalScrollOffset();
61 | }
62 |
63 | public int superComputeVerticalScrollRange() {
64 | return super.computeVerticalScrollRange();
65 | }
66 |
67 | public void superOnTouchEvent(MotionEvent event) {
68 | super.onTouchEvent(event);
69 | }
70 |
71 | public void superDraw(Canvas canvas) {
72 | super.draw(canvas);
73 | }
74 |
75 | public boolean superAwakenScrollBars() {
76 | return super.awakenScrollBars();
77 | }
78 |
79 | public boolean superOverScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
80 | return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
81 | }
82 |
83 | public View getOverScrollableView() {
84 | return this;
85 | }
86 |
87 | public OverScrollDelegate getOverScrollDelegate() {
88 | return this.mOverScrollDelegate;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/widget/OverScrollView.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.widget;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.os.Build;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 | import android.view.ViewConfiguration;
9 |
10 | import com.mixiaoxiao.overscroll.OverScrollScrollView;
11 |
12 | public class OverScrollView extends OverScrollScrollView {
13 | public OverScrollView(Context context) {
14 | super(context);
15 | }
16 |
17 | public OverScrollView(Context context, AttributeSet attrs) {
18 | super(context, attrs);
19 | }
20 |
21 | public OverScrollView(Context context, AttributeSet attrs, int defStyle) {
22 | super(context, attrs, defStyle);
23 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
24 | }
25 |
26 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
27 | public OverScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
28 | super(context, attrs, defStyleAttr, defStyleRes);
29 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
30 | }
31 |
32 | private int downX, downY;
33 | private int mTouchSlop;
34 | @Override
35 | public boolean onInterceptTouchEvent(MotionEvent ev) {
36 | int action = ev.getAction();
37 | switch (action) {
38 | case MotionEvent.ACTION_DOWN:
39 | downX = (int) ev.getRawX();
40 | downY = (int) ev.getRawY();
41 | break;
42 | case MotionEvent.ACTION_MOVE:
43 | int moveY = (int) ev.getRawY();
44 | // 判断是否滑动,若滑动就拦截事件
45 | if (Math.abs(moveY - downY) > mTouchSlop) {
46 | return true;
47 | }
48 | break;
49 | default:
50 | break;
51 | }
52 |
53 | return super.onInterceptTouchEvent(ev);
54 | }
55 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/widget/TipsPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.widget;
2 |
3 | import android.content.Context;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 | import android.widget.TextView;
7 |
8 | import androidx.annotation.NonNull;
9 | import androidx.viewpager.widget.PagerAdapter;
10 |
11 | import com.pointer.wave.easyship.R;
12 | import com.pointer.wave.easyship.pojo.TipsBen;
13 |
14 | import java.util.List;
15 |
16 | public class TipsPagerAdapter extends PagerAdapter{
17 | private final Context context;
18 | private final List mListView;
19 | public TipsPagerAdapter(List list, Context context) {
20 | this.context = context;
21 | this.mListView = list;
22 | }
23 |
24 | @Override
25 | public int getCount() {
26 | return mListView != null ? mListView.size() : 0;
27 | }
28 |
29 | @Override
30 | public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
31 | return view == object;
32 | }
33 |
34 | @Override
35 | public void destroyItem(ViewGroup view, int position, @NonNull Object object) {
36 | view.removeView((View) object);
37 | }
38 |
39 | @NonNull
40 | @Override
41 | public Object instantiateItem(@NonNull ViewGroup view, int position) {
42 | View a = View.inflate(context, R.layout.item_tips_viewpager, null);
43 | a.findViewById(R.id.tips_title).setText(mListView.get(position).getContent());
44 | view.addView(a);
45 | return a;
46 | }
47 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/widget/UpdateLogDialog.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.widget;
2 |
3 | import android.animation.ObjectAnimator;
4 | import android.annotation.SuppressLint;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.net.Uri;
8 | import android.os.Handler;
9 | import android.text.Html;
10 | import android.text.SpannableStringBuilder;
11 | import android.text.Spanned;
12 | import android.text.style.ClickableSpan;
13 | import android.text.style.URLSpan;
14 | import android.view.View;
15 | import android.widget.ImageView;
16 | import android.widget.LinearLayout;
17 | import android.widget.TextView;
18 |
19 | import androidx.annotation.NonNull;
20 | import androidx.appcompat.app.AppCompatActivity;
21 |
22 | import com.github.mmin18.widget.RealtimeBlurView;
23 | import com.lxj.xpopup.XPopup;
24 | import com.lxj.xpopup.core.BottomPopupView;
25 | import com.lxj.xpopup.enums.PopupAnimation;
26 | import com.pointer.wave.easyship.R;
27 | import com.pointer.wave.easyship.common.activity.BaseActivity;
28 |
29 | public class UpdateLogDialog extends BottomPopupView {
30 |
31 | public static AppCompatActivity activity;
32 |
33 | @SuppressLint("StaticFieldLeak")
34 | public static UpdateLogDialog dialog;
35 | private String html;
36 |
37 | public UpdateLogDialog(@NonNull Context context, String html) {
38 | super(context);
39 | dialog = this;
40 | this.html = html;
41 | }
42 |
43 | @Override
44 | protected int getImplLayoutId() {
45 | return R.layout.dialog_full_base;
46 | }
47 |
48 | public static void showDialog(AppCompatActivity appCompatActivity, String html){
49 | activity = appCompatActivity;
50 | new XPopup.Builder(appCompatActivity)
51 | .animationDuration(750)
52 | .dismissOnTouchOutside(false)
53 | .hasShadowBg(false)
54 | .hasBlurBg(false)
55 | .isViewMode(true)
56 | .popupAnimation(PopupAnimation.TranslateAlphaFromBottom)
57 | .moveUpToKeyboard(false)
58 | .isDestroyOnDismiss(true)
59 | .isRequestFocus(true)
60 | .asCustom(new UpdateLogDialog(appCompatActivity, html))
61 | .show();
62 | }
63 |
64 | private LinearLayout relativeLayout;
65 | private View inflate;
66 | @Override
67 | protected void onCreate() {
68 | super.onCreate();
69 | relativeLayout = findViewById(R.id.root_view);
70 | inflate = View.inflate(getContext(), R.layout.dialog_update_log, null);
71 | addChildView(inflate);
72 | RealtimeBlurView blurView = findViewById(R.id.blur_view);
73 | translation(blurView);
74 |
75 | TextView logView = inflate.findViewById(R.id.log);
76 | logView.setText(getClickableHtml(html));
77 | }
78 |
79 | private void addChildView(View view) {
80 | relativeLayout.removeAllViews();
81 | relativeLayout.addView(view);
82 | }
83 |
84 | private void translation(View view){
85 | ObjectAnimator translationY = ObjectAnimator.ofFloat(view, "translationY", 0, 0.1f);
86 | translationY.setDuration(100);
87 | translationY.start();
88 | new Handler(view.getContext().getMainLooper()).postDelayed(()->{
89 | translation(view);
90 | }, 200);
91 | }
92 |
93 | public void setLinkClickable(SpannableStringBuilder clickableHtml, URLSpan urlSpan) {
94 | int start = clickableHtml.getSpanStart(urlSpan);
95 | int end = clickableHtml.getSpanEnd(urlSpan);
96 | int flags = clickableHtml.getSpanFlags(urlSpan);
97 | ClickableSpan clickableSpan = new ClickableSpan() {
98 | @Override
99 | public void onClick(View widget) {
100 | if(urlSpan.getURL()!=null){
101 | Intent intent = new Intent();
102 | intent.setAction("android.intent.action.VIEW");
103 | intent.setData(Uri.parse(urlSpan.getURL()));
104 | getContext().startActivity(intent);
105 | }
106 | }
107 | };
108 | clickableHtml.setSpan(clickableSpan, start, end, flags);
109 | }
110 |
111 | public CharSequence getClickableHtml(String text) {
112 | Spanned spannedHtml = Html.fromHtml(text);
113 | SpannableStringBuilder clickableHtmlBuilder = new SpannableStringBuilder(spannedHtml);
114 | URLSpan[] urls = clickableHtmlBuilder.getSpans(0, spannedHtml.length(), URLSpan.class);
115 | for (final URLSpan span : urls){
116 | setLinkClickable(clickableHtmlBuilder, span);
117 | }
118 | return clickableHtmlBuilder;
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/widget/ViewPagerAdapterForView.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.widget;
2 |
3 | import android.os.Parcelable;
4 | import android.view.View;
5 | import android.view.ViewGroup;
6 |
7 | import androidx.viewpager.widget.PagerAdapter;
8 |
9 | import java.util.List;
10 |
11 | public class ViewPagerAdapterForView extends PagerAdapter {
12 |
13 | private final List mListView;
14 |
15 | public ViewPagerAdapterForView(List list)
16 | {
17 | // TODO Auto-generated method stub
18 | this.mListView = list;
19 | }
20 |
21 | @Override
22 | /**这个方法,是从ViewGroup中移出当前View**/
23 | public void destroyItem(View container, int position, Object object)
24 | {
25 | // TODO Auto-generated method stub
26 | ((ViewGroup) container ).removeView(mListView.get(position));
27 | }
28 |
29 | @Override
30 | public void finishUpdate(View view)
31 | {
32 | // TODO Auto-generated method stub
33 |
34 | }
35 |
36 | @Override
37 | /**这个方法,是获取当前窗体界面数**/
38 | public int getCount()
39 | {
40 | // TODO Auto-generated method stub
41 | return mListView.size();
42 | }
43 |
44 | @Override
45 | /**这个方法,return一个对象,这个对象表明了PagerAdapter适配器选择哪个对象*放在当前的ViewPager中**/
46 | public Object instantiateItem(View container, int position)
47 | {
48 | // TODO Auto-generated method stub
49 | ((ViewGroup) container).addView(mListView.get(position), 0);
50 | return mListView.get(position);
51 | }
52 |
53 | @Override
54 | /**这个方法,在帮助文档中原文是could be implemented as return view == object,*也就是用于判断是否由对象生成界面**/
55 | public boolean isViewFromObject(View view, Object object)
56 | {
57 | // TODO Auto-generated method stub
58 | return view == (object);
59 | }
60 |
61 | @Override
62 | public void restoreState(Parcelable state, ClassLoader loader)
63 | {
64 | // TODO Auto-generated method stub
65 |
66 | }
67 |
68 | @Override
69 | public Parcelable saveState()
70 | {
71 | // TODO Auto-generated method stub
72 | return null;
73 | }
74 |
75 | @Override
76 | public void startUpdate(View v)
77 | {
78 | // TODO Auto-generated method stub
79 |
80 | }
81 |
82 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/pointer/wave/easyship/widget/adapter/HelpsListAdapter.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship.widget.adapter;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.net.Uri;
7 | import android.view.View;
8 | import android.view.ViewGroup;
9 | import android.widget.TextView;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.recyclerview.widget.RecyclerView;
13 |
14 | import com.google.gson.Gson;
15 | import com.pointer.wave.easyship.R;
16 | import com.pointer.wave.easyship.pojo.TipsBen;
17 | import com.pointer.wave.easyship.widget.feedback.TouchFeedback;
18 |
19 | import java.util.List;
20 |
21 | public class HelpsListAdapter extends RecyclerView.Adapter implements TouchFeedback.OnFeedBackListener {
22 |
23 | private List list;
24 | private TouchFeedback touchFeedback;
25 | private final Gson gson = new Gson();
26 | public HelpsListAdapter(List list, Context context) {
27 | this.list = list;
28 | touchFeedback = TouchFeedback.newInstance(context);
29 | }
30 |
31 | @NonNull
32 | @Override
33 | public HelpHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
34 | HelpHolder helpHolder = new HelpHolder(View.inflate(parent.getContext(), R.layout.item_help_layout, null));
35 | //touchFeedback.setOnFeedBackListener(this, helpHolder.itemView, false);
36 | return helpHolder;
37 | }
38 |
39 | @Override
40 | public void onBindViewHolder(@NonNull HelpHolder holder, int position) {
41 | TipsBen tipsBen = gson.fromJson(list.get(position), TipsBen.class);
42 | holder.textView.setText(tipsBen.getName().replace(".txt", ""));
43 | holder.button.setOnClickListener((v)->{
44 | Intent intent = new Intent();
45 | intent.setAction("android.intent.action.VIEW");
46 | intent.setData(Uri.parse(tipsBen.getContent()));
47 | v.getContext().startActivity(intent);
48 | });
49 | }
50 |
51 | @Override
52 | public int getItemCount() {
53 | return list.size();
54 | }
55 |
56 | @SuppressLint("NotifyDataSetChanged")
57 | public void updateList(List list){
58 | this.list = list;
59 | notifyDataSetChanged();
60 | }
61 |
62 | @Override
63 | public void onClick(View view) {
64 |
65 | }
66 |
67 | @Override
68 | public void onLongClick(View view) {
69 |
70 | }
71 |
72 | static class HelpHolder extends RecyclerView.ViewHolder {
73 |
74 | public TextView textView;
75 | public TextView button;
76 | public HelpHolder(@NonNull View itemView) {
77 | super(itemView);
78 | textView = itemView.findViewById(R.id.text);
79 | button = itemView.findViewById(R.id.show_help);
80 | }
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/fragment_slide_hide.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
16 |
17 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/fragment_slide_show.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_content_copy_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/drawable/ic_content_copy_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_content_cut_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/drawable/ic_content_cut_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_content_paste_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/drawable/ic_content_paste_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_select_all_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/drawable/ic_select_all_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_method.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/drawable/icon_method.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_editor.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_flash_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_indicator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
5 |
6 |
7 |
8 |
9 |
10 | -
11 |
12 |
13 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_indicator_select.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/shape_shadow_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_full_base.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
16 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_helps.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
30 |
31 |
35 |
36 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_permissin_write.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
26 |
27 |
37 |
38 |
45 |
46 |
52 |
53 |
58 |
59 |
66 |
67 |
68 |
69 |
70 |
71 |
76 |
77 |
84 |
85 |
93 |
94 |
95 |
96 |
97 |
98 |
104 |
105 |
111 |
112 |
121 |
122 |
129 |
130 |
131 |
132 |
141 |
142 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_update_log.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
17 |
18 |
22 |
23 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
22 |
23 |
30 |
31 |
36 |
37 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_auto_panel.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
11 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_help_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
16 |
17 |
22 |
23 |
28 |
29 |
36 |
37 |
38 |
39 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_tips_viewpager.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
21 |
22 |
26 |
27 |
34 |
35 |
36 |
37 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/layout_navigation_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
22 |
23 |
31 |
32 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/symbol_view.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_alipay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_alipay.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_developer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_developer.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_download.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_es_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_es_logo.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_es_logo_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_es_logo_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_file.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_folder.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_github.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_help.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_help.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_home.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_idea.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_idea.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_log.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_log.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_logo_white_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_logo_white_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_mail.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_mail.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_notification.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_root.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_root.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_settings.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_start.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_sub_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_sub_notification.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_tips.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_tips.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_update.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_waring.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-mdpi/ic_waring.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FFFFFFFF
9 | #FF000000
10 | #FFEF5361
11 | #FFFD6D4B
12 | #FFFFCF47
13 | #FF9FD661
14 | #FF3FD1AD
15 | #FF2CBDF4
16 | #FFAD8FEF
17 | #FFEE85C0
18 | #8CFFFFFF
19 | #88CE9C
20 | #8CDCF7E8
21 | #AADCF7E8
22 | #D9D9D9
23 | #FFF5F5F5
24 | #FF474658
25 | #60000000
26 | #ff5f7c89
27 | #8c5f7c89
28 | #eceff2
29 | #fff2df
30 | #e8f6e9
31 | #e4f2fd
32 | #dff7f9
33 | #e8eaf6
34 | #EFEBE8
35 | #795547
36 | #ffebed
37 | #f3e5f6
38 | #9d27b1
39 | #3DDC84
40 | #8Ceceff2
41 | #FF119EFF
42 | #CC000000
43 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #FFEF5361
11 | #FFFD6D4B
12 | #FFFFCF47
13 | #FF9FD661
14 | #FF3FD1AD
15 | #FF2CBDF4
16 | #FFAD8FEF
17 | #FFEE85C0
18 | #8CFFFFFF
19 | #88CE9C
20 | #8CDCF7E8
21 | #AADCF7E8
22 | #D9D9D9
23 | #FFF5F5F5
24 | #FF474658
25 | #60000000
26 | #ff5f7c89
27 | #8c5f7c89
28 | #eceff2
29 | #fff2df
30 | #e8f6e9
31 | #e4f2fd
32 | #dff7f9
33 | #e8eaf6
34 | #EFEBE8
35 | #795547
36 | #ffebed
37 | #f3e5f6
38 | #9d27b1
39 | #3DDC84
40 | #8Ceceff2
41 | #FF119EFF
42 | #CC000000
43 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 一叶孤舟
3 |
4 | Hello blank fragment
5 | 1. 设备获取Root权限且以授予本软件权限;
6 |
2. 设备支持V-AB系统分区;
7 |
8 | 可能出现的问题:
9 |
10 | 1. 选择ROM路径时一定要从“本机存储”中选择,否则可能会无法选择ROM;
11 |
12 | 2. 由于Android对后台服务的限制,请在更新时尽量保证本软件为前台应用(当通知栏出现更新进度后就可以挂后台了);
13 |
14 | 3. 经测试,本软件支持官方ROM升级/降级操作,官改包与类原生请用户自行测试;
15 |
16 | 4. 如果提示更新失败,请重启手机并等候一段时间再进行刷写操作
17 |
18 | 5. 如有其他问题欢迎补充~]]>
19 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/update_path.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/test/java/com/pointer/wave/easyship/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 |
18 | @Test
19 | fun test(){
20 | }
21 | }
--------------------------------------------------------------------------------
/app/src/test/java/com/pointer/wave/easyship/Test.java:
--------------------------------------------------------------------------------
1 | package com.pointer.wave.easyship;
2 |
3 | public class Test {
4 |
5 | @org.junit.Test
6 | public void test(){
7 |
8 | }
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | mavenCentral()
7 | maven { url 'https://repo1.maven.org/maven2/' }
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:7.1.2'
11 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10"
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | task clean(type: Delete) {
19 | delete rootProject.buildDir
20 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | ## For more details on how to configure your build environment visit
2 | # http://www.gradle.org/docs/current/userguide/build_environment.html
3 | #
4 | # Specifies the JVM arguments used for the daemon process.
5 | # The setting is particularly useful for tweaking memory settings.
6 | # Default value: -Xmx1024m -XX:MaxPermSize=256m
7 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
8 | #
9 | # When configured, Gradle will run in incubating parallel mode.
10 | # This option should only be used with decoupled projects. More details, visit
11 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
12 | # org.gradle.parallel=true
13 | #Sun Mar 20 19:33:50 CST 2022
14 | android.nonTransitiveRClass=true
15 | kotlin.code.style=official
16 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding\=UTF-8
17 | android.useAndroidX=true
18 | android.enableJetifier=true
19 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lumyuan/EasyShip/82a53ba2f2ad91cc5dd914e55ed98fe6f9742c06/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Mar 20 15:46:56 CST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 | }
8 | dependencyResolutionManagement {
9 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 | repositories {
11 | google()
12 | mavenCentral()
13 | jcenter()
14 | }
15 | }
16 | rootProject.name = "EasyShip"
17 | include ':app'
18 |
--------------------------------------------------------------------------------